diff --git a/.ci/build-freetype.sh b/.ci/build-freetype.sh deleted file mode 100644 index 0f09f92e9f445ec920a25136b9e26691c242bc11..0000000000000000000000000000000000000000 --- a/.ci/build-freetype.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -x -set -o errexit -o nounset - -# 22.0.16 is the libtool version of 2.9.0 -if pkg-config --atleast-version 22.0.16 freetype2; then exit; fi - -pushd $HOME -wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 -tar xf freetype-2.9.tar.bz2 -pushd freetype-2.9 -./autogen.sh -./configure --prefix=$HOME/.local -make -j4 install -popd -popd diff --git a/.ci/build-win32.sh b/.ci/build-win32.sh new file mode 100644 index 0000000000000000000000000000000000000000..65265ec9a1e17e0e1351e026c604738bf6f4edfc --- /dev/null +++ b/.ci/build-win32.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -e + +meson --cross-file=.ci/win32-cross-file.txt win32build --wrap-mode=forcefallback -Dtests=disabled \ + -Dglib=enabled -Dfreetype=enabled -Dgdi=enabled -Ddirectwrite=enabled -Dcairo=enabled --buildtype=release $@ +ninja -Cwin32build -j3 # building with all the cores won't work fine with CricleCI for some reason + +rm -rf win32build/harfbuzz-win32 +mkdir win32build/harfbuzz-win32 +cp win32build/util/hb-*.exe win32build/harfbuzz-win32 +find win32build -name '*.dll' -exec cp {} win32build/harfbuzz-win32 \; +i686-w64-mingw32-strip win32build/harfbuzz-win32/*.{dll,exe} +rm -f harfbuzz-win32.zip +(cd win32build && zip -r ../harfbuzz-win32.zip harfbuzz-win32) +echo "harfbuzz-win32.zip is ready." diff --git a/.ci/deploy-docs.sh b/.ci/deploy-docs.sh index a8a85233195d1b78fc361a27fdc71cb1880bee5d..854ca2354bb06c13e578d5319b015c0a4e707cbc 100755 --- a/.ci/deploy-docs.sh +++ b/.ci/deploy-docs.sh @@ -3,11 +3,6 @@ set -x set -o errexit -o nounset -if test "x$TRAVIS_SECURE_ENV_VARS" != xtrue; then exit; fi - -BRANCH="$TRAVIS_BRANCH" -if test "x$BRANCH" != xmaster; then exit; fi - TAG="$(git describe --exact-match --match "[0-9]*" HEAD 2>/dev/null || true)" DOCSDIR=build-docs @@ -17,8 +12,8 @@ rm -rf $DOCSDIR || exit mkdir $DOCSDIR cd $DOCSDIR -cp ../docs/html/* . -#cp ../docs/CNAME . +cp ../build/docs/html/* . +#cp ../build/docs/CNAME . git init git config user.name "Travis CI" @@ -32,5 +27,8 @@ git reset upstream/master touch . git add -A . -git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION" -git push -q upstream HEAD:master + +if [[ $(git status -s) ]]; then + git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION" + git push -q upstream HEAD:master +fi diff --git a/.ci/fail.sh b/.ci/fail.sh deleted file mode 100755 index 4e0069e3f8ac57c1233d66c9177a52dc3a38b6da..0000000000000000000000000000000000000000 --- a/.ci/fail.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -for f in $(find . -name '*.log' -not -name 'config.log'); do - last=$(tail -1 $f) - if [[ $last = FAIL* ]]; then - echo '====' $f '====' - cat $f - elif [[ $last = PASS* ]]; then - # Do nothing. - true - else - # Travis Linux images has an old automake that does not match the - # patterns above, so in case of doubt just print the file. - cat $f - fi -done - -exit 1 diff --git a/.ci/publish_release_artifact.sh b/.ci/publish_release_artifact.sh new file mode 100644 index 0000000000000000000000000000000000000000..365734144ad29936560c293238eb87a40f7b2e49 --- /dev/null +++ b/.ci/publish_release_artifact.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +set -o pipefail + +if [[ -z $GITHUB_TOKEN ]]; then + echo "No GITHUB_TOKEN secret found, artifact publishing skipped" + exit +fi + +mkdir -p $HOME/.local/bin +export _GHR_VER=v0.13.0 +export _GHR=ghr_${_GHR_VER}_linux_amd64 +curl -sfL https://github.com/tcnksm/ghr/releases/download/$_GHR_VER/$_GHR.tar.gz | + tar xz -C $HOME/.local/bin --strip-components=1 $_GHR/ghr + +ghr -replace \ + -u $CIRCLE_PROJECT_USERNAME \ + -r $CIRCLE_PROJECT_REPONAME \ + $CIRCLE_TAG \ + $1 diff --git a/.ci/run-coveralls.sh b/.ci/run-coveralls.sh deleted file mode 100755 index 8d1ceb5e25a30e50e6be51391e3cfd8d58797dd4..0000000000000000000000000000000000000000 --- a/.ci/run-coveralls.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -x -set -o errexit -o nounset - -if test x"$TRAVIS_REPO_SLUG" != x"harfbuzz/harfbuzz"; then exit; fi - -pip install --user nose -pip install --user cpp-coveralls -export PATH=$HOME/.local/bin:$PATH - -rm -f src/.libs/NONE.gcov -touch src/NONE -coveralls -e docs diff --git a/.ci/trigger-coverity.sh b/.ci/trigger-coverity.sh deleted file mode 100644 index 19852bd1187920a8bd85ea4a6b090225c26cf2b3..0000000000000000000000000000000000000000 --- a/.ci/trigger-coverity.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -set -x -set -o errexit -o nounset - -if test x"$TRAVIS_EVENT_TYPE" != x"cron"; then exit; fi -if test x"$TRAVIS_BRANCH" != x"master"; then exit; fi - -git fetch --unshallow -git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.git" -git push -q upstream master:coverity_scan diff --git a/.ci/win32-cross-file.txt b/.ci/win32-cross-file.txt new file mode 100644 index 0000000000000000000000000000000000000000..982a909b76ec750882ad54104f9598bc2b5758e7 --- /dev/null +++ b/.ci/win32-cross-file.txt @@ -0,0 +1,20 @@ +[host_machine] +system = 'windows' +cpu_family = 'x86' +cpu = 'i686' +endian = 'little' + +[properties] +c_args = [] +c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread'] +cpp_args = [] +cpp_link_args = ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lpthread'] + +[binaries] +c = 'i686-w64-mingw32-gcc' +cpp = 'i686-w64-mingw32-g++' +ar = 'i686-w64-mingw32-ar' +ld = 'i686-w64-mingw32-ld' +objcopy = 'i686-w64-mingw32-objcopy' +strip = 'i686-w64-mingw32-strip' +windres = 'i686-w64-mingw32-windres' diff --git a/.ci/win64-cross-file.txt b/.ci/win64-cross-file.txt new file mode 100644 index 0000000000000000000000000000000000000000..e906e085e215d6523f1ec72980ed0ca0f3f5d603 --- /dev/null +++ b/.ci/win64-cross-file.txt @@ -0,0 +1,20 @@ +[host_machine] +system = 'windows' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +c_args = [] +c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread'] +cpp_args = [] +cpp_link_args = ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lpthread'] + +[binaries] +c = 'x86_64-w64-mingw32-gcc' +cpp = 'x86_64-w64-mingw32-g++' +ar = 'x86_64-w64-mingw32-ar' +ld = 'x86_64-w64-mingw32-ld' +objcopy = 'x86_64-w64-mingw32-objcopy' +strip = 'x86_64-w64-mingw32-strip' +windres = 'x86_64-w64-mingw32-windres' diff --git a/.circleci/config.yml b/.circleci/config.yml index 6ad98d237c68044d13eb8c147b374c87adbc7bb8..9449b6e6ecfb481b91907c6cbcd1edcc40d23c2a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,342 +1,176 @@ -version: 2 +version: 2.1 -jobs: +executors: + win32-executor: + docker: + - image: cimg/base:edge-20.04 + autotools-executor: + docker: + - image: cimg/base:edge-20.04 - macos-10.12.6-aat-fonts: - macos: - xcode: "9.2.0" - steps: - - checkout - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo - - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo - - run: make -j4 - - run: make check || .ci/fail.sh +jobs: - macos-10.13.6-aat-fonts: + macos-10_14_4-aat-fonts: macos: - xcode: "10.1.0" + xcode: "11.1.0" steps: - checkout - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo - - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo - - run: make -j4 - - run: make check || .ci/fail.sh + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 ninja + - run: pip3 install meson --upgrade + - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled + - run: meson compile -Cbuild + - run: meson test -Cbuild --print-errorlogs + - store_artifacts: + path: build/meson-logs/ - macos-10.14.3-aat-fonts: + macos-10_15_3-aat-fonts: macos: - xcode: "10.2.0" + xcode: "11.4.0" steps: - checkout - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2 - - run: export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" && ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-coretext --with-graphite2 - - run: make -j4 - - run: make check || .ci/fail.sh + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection gtk-doc ninja + - run: pip3 install meson --upgrade + - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled + - run: meson compile -Cbuild + - run: meson test -Cbuild --print-errorlogs + - store_artifacts: + path: build/meson-logs/ + # will be dropped with autotools removal distcheck: - docker: - - image: ubuntu:19.04 + executor: autotools-executor steps: - checkout - - run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools + - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip + - run: pip3 install fonttools meson --upgrade - run: ./autogen.sh - - run: make -j32 - - run: make distcheck || .ci/fail.sh - - run: rm -rf harfbuzz-* - - run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install - - alpine-O3-Os-NOMMAP: - docker: - - image: alpine - steps: - - checkout - - run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev python - # C??FLAGS are not needed for a regular build - - run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh - - run: make -j32 - - run: make check || .ci/fail.sh - - run: make clean - - run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh - - run: make -j32 - - run: make check || .ci/fail.sh - - archlinux-py3-all: - docker: - - image: archlinux/base - steps: - - checkout - - run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip make which base-devel - - run: pip install flake8 fonttools - - run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - # C??FLAGS are not needed for a regular build - - run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 - - run: make -j32 CPPFLAGS="-Werror" - - run: make check CPPFLAGS="-Werror" || .ci/fail.sh - - ## Doesn't play well with CircleCI apparently - #void-notest: - # docker: - # - image: voidlinux/voidlinux - # steps: - # - checkout - # - run: xbps-install -Suy freetype gettext gcc glib graphite pkg-config ragel libtool autoconf automake make - # - run: ./autogen.sh && make -j32 && make check - - clang-O3-O0-and-nobuildsystem: - docker: - - image: ubuntu:18.10 - steps: - - checkout - - run: apt update || true - - run: apt install -y clang wget autoconf automake libtool pkg-config ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd .. - - run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2 - - run: make -j32 - - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh - - run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2 - - run: make -j32 - - run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh - - run: make clean && cd src && clang++ -c hb-*.cc - - gcc-valgrind: - docker: - - image: ubuntu:18.10 - steps: - - checkout - - run: apt update || true - - run: apt install -y gcc binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip valgrind - - run: pip install fonttools - - run: ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig - - run: make -j32 - # run-shape-fuzzer-tests.py automatically runs valgrind if see available - # but test/api runs it by request, we probably should normalize the approaches - - run: RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh - # informational for now - - run: make -Ctest/api check-symbols || true + - run: make -j2 distcheck + - run: rm harfbuzz-* && make distdir + - run: cd harfbuzz-* && meson build && ninja -j2 -Cbuild test + - run: make dist + - persist_to_workspace: + root: . + paths: harfbuzz-*.tar.xz - clang-everything: - docker: - - image: ubuntu:18.10 + publish-dist: + executor: autotools-executor steps: - checkout - - run: apt update || true; apt install -y wget gnupg - - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - - - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list - - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list - - run: apt update || true - - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig - - run: make -j32 CPPFLAGS="-Werror" - - run: make check CPPFLAGS="-Werror" || .ci/fail.sh + - attach_workspace: + at: . + - run: | + .ci/publish_release_artifact.sh harfbuzz-$CIRCLE_TAG.tar.xz - clang-asan: + fedora-valgrind: docker: - - image: ubuntu:18.10 + - image: fedora:33 steps: - checkout - - run: apt update || true; apt install -y wget gnupg - - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - - - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list - - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list - - run: apt update || true - - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 - - run: make -j32 - - run: make check || .ci/fail.sh | asan_symbolize | c++filt + - run: dnf install -y pkg-config ragel valgrind gcc gcc-c++ meson git glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip || true + - run: meson build --buildtype=debugoptimized + - run: ninja -Cbuild -j9 + # TOOD: increase timeouts and remove --no-suite=slow + - run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs - clang-msan: + alpine: docker: - - image: ubuntu:18.10 + - image: alpine steps: - checkout - - run: apt update || true; apt install -y wget gnupg - - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - - - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list - - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list - - run: apt update || true - - run: apt install -y clang lld binutils libtool autoconf automake gtk-doc-tools gettext make pkg-config ragel libcairo2-dev libicu-dev libmount-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 10 - - run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd .. - - run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd .. - - run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu - - run: make -j32 && MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt + - run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja + - run: pip3 install meson==0.47.0 + - run: meson build --buildtype=minsize + - run: ninja -Cbuild -j9 + - run: meson test -Cbuild --print-errorlogs - clang-tsan: + archlinux: docker: - - image: ubuntu:18.10 + - image: archlinux/base steps: - checkout - - run: apt update || true; apt install -y wget gnupg - - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - - - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list - - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list - - run: apt update || true - - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 - - run: make -j32 - - run: make check || .ci/fail.sh | asan_symbolize | c++filt + - run: pacman --noconfirm -Syu freetype2 meson git clang cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip base-devel gtk-doc + - run: pip install flake8 fonttools + - run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics + - run: meson build -Dgraphite=enabled -Dauto_features=enabled -Dexperimental_api=true + - run: meson compile -Cbuild -j9 + - run: meson test -Cbuild --print-errorlogs + - run: meson dist -Cbuild + - run: clang -c src/harfbuzz.cc -DHB_NO_MT + - run: clang -c src/hb-*.cc -DHB_NO_MT -DHB_TINY -DHB_NO_OT_FONT - clang-ubsan: + sanitizers: docker: - - image: ubuntu:18.10 + - image: ubuntu:20.04 steps: - checkout - - run: apt update || true; apt install -y wget gnupg - - run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - - - run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list - - run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list - run: apt update || true - - run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 - - run: make -j32 - - run: make check || .ci/fail.sh | asan_symbolize | c++filt - - fedora-O0-debug-outoftreebuild-mingw: - docker: - - image: fedora - steps: - - checkout - - run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true - - run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 - - run: mkdir build && cd build && ../configure && make -j32 && (make check || ../.ci/fail.sh) - - run: pip install pefile - - run: mkdir winbuild32 && cd winbuild32 && ../mingw32.sh && make -j32 && make dist-win && cp harfbuzz-*-win32.zip harfbuzz-win32.zip - - run: mkdir winbuild64 && cd winbuild64 && ../mingw64.sh && make -j32 && make dist-win && cp harfbuzz-*-win64.zip harfbuzz-win64.zip - - store_artifacts: - path: winbuild32/harfbuzz-win32.zip - destination: harfbuzz-win32.zip + - run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils meson pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev + # asan+ubsan + - run: rm -rf build && meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true + - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + # tsan + - run: rm -rf build && meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true + - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + # msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least + - run: rm -rf build && meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true + - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - run: clang -c src/harfbuzz.cc src/hb-subset*.cc -DHB_NO_MT -Werror -std=c++2a + + crossbuild-win32: + executor: win32-executor + steps: + - checkout + - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build binutils gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip git g++-mingw-w64-i686 zip + - run: pip3 install meson==0.56.0 --upgrade + - run: .ci/build-win32.sh - store_artifacts: - path: winbuild64/harfbuzz-win64.zip - destination: harfbuzz-win64.zip - - cmake-gcc: - docker: - - image: ubuntu:19.04 - steps: - - checkout - - run: apt update && apt install -y ninja-build binutils cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip - - run: pip install fonttools - - run: cmake -DHB_CHECK=ON -Bbuild -H. -GNinja - - run: ninja -Cbuild - - run: CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test - - run: ninja -Cbuild install - - #cmake-oracledeveloperstudio: - # docker: - # - image: fedora - # steps: - # - checkout - # - run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true - # - run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner - # - run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H. - # - run: make -Cbuild -j32 - # - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test - # - run: make -Cbuild install - - crosscompile-notest-djgpp: - docker: - # https://gist.github.com/ebraminio/8551fc74f27951e668102baa2f6b1175 - - image: quay.io/ebraminio/djgpp - steps: - - checkout - - run: apt update && apt install -y ragel pkg-config libtool autoconf - - run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp - - run: make -j32 - - crosscompile-notest-psvita: - docker: - - image: dockcross/base - steps: - - checkout - - run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh - - run: echo '#!/bin/true' > /usr/bin/ragel && chmod +x /usr/bin/ragel - - run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi - - run: make -j32 + path: harfbuzz-win32.zip + - persist_to_workspace: + root: . + paths: harfbuzz-win32.zip - crosscompile-cmake-notest-android-arm: - docker: - - image: dockcross/android-arm - steps: - - checkout - - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - - run: ninja -Cbuild - - crosscompile-cmake-notest-browser-asmjs-hb_tiny: - docker: - - image: dockcross/browser-asmjs - steps: - - checkout - - run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF - - run: ninja -Cbuild - - crosscompile-cmake-notest-linux-arm64: - docker: - - image: dockcross/linux-arm64 - steps: - - checkout - - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - - run: ninja -Cbuild - - crosscompile-cmake-notest-linux-mips: - docker: - - image: dockcross/linux-mips + publish-win32: + executor: win32-executor steps: - checkout - - run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF - - run: ninja -Cbuild - - #crosscompile-cmake-notest-windows-x64: - # docker: - # - image: dockcross/windows-x64 - # steps: - # - checkout - # - run: cmake -Bbuild -H. -GNinja - # - run: ninja -Cbuild + - attach_workspace: + at: . + - run: | + mv harfbuzz-win32{,-$CIRCLE_TAG}.zip + .ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip workflows: version: 2 + build: jobs: - # macOS - - macos-10.12.6-aat-fonts - - macos-10.13.6-aat-fonts - - macos-10.14.3-aat-fonts - - # both autotools and cmake - - distcheck - - # autotools based builds - - alpine-O3-Os-NOMMAP - - archlinux-py3-all - #- void-notest - - gcc-valgrind - - clang-O3-O0-and-nobuildsystem - - clang-everything - - clang-asan - - clang-msan - - clang-tsan - - clang-ubsan - - fedora-O0-debug-outoftreebuild-mingw - - # cmake based builds - - cmake-gcc - #- cmake-oracledeveloperstudio - - # crosscompiles - # they can't be test thus are without tests - ## autotools - - crosscompile-notest-djgpp - - crosscompile-notest-psvita - - ## cmake - - crosscompile-cmake-notest-android-arm - - crosscompile-cmake-notest-browser-asmjs-hb_tiny - - crosscompile-cmake-notest-linux-arm64 - - crosscompile-cmake-notest-linux-mips - #- crosscompile-cmake-notest-windows-x64 + - macos-10_14_4-aat-fonts + - macos-10_15_3-aat-fonts + - distcheck: # will be dropped with autotools removal + filters: + tags: + only: /^\d+.\d+.\d+$/ + - publish-dist: + requires: + - distcheck + filters: + tags: + only: /^\d+\.\d+\.\d+$/ + branches: + ignore: /.*/ + - fedora-valgrind + - alpine + #- archlinux + - sanitizers + - crossbuild-win32: + filters: + tags: + only: /^\d+.\d+.\d+$/ + - publish-win32: + requires: + - crossbuild-win32 + filters: + tags: + only: /^\d+\.\d+\.\d+$/ + branches: + ignore: /.*/ diff --git a/.editorconfig b/.editorconfig index 4850f2bf65553a2808aab15fda5c9751be6eb3c5..cac917b91072d1fdc3c1aef7599cd0f557c7345a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,7 +6,7 @@ trim_trailing_whitespace = true end_of_line = lf insert_final_newline = true -[*.{c,cc,h,hh}] +[*.{c,cc,h,hh,rl}] tab_width = 8 indent_size = 2 indent_style = tab # should be space @@ -17,5 +17,7 @@ indent_style = tab [{Makefile.am,Makefile.sources,configure.ac}] tab_width = 8 -[{CMakeLists.txt,*.cmake}] +[{meson.build,meson_options.txt}] +tab_width = 8 +indent_style = space indent_size = 2 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 703fac25c4d4770f44e03bd793b4837f65f7e26e..0000000000000000000000000000000000000000 --- a/.travis.yml +++ /dev/null @@ -1,78 +0,0 @@ -# Build Configuration for Travis -dist: trusty - -language: cpp - -env: - global: - - CPPFLAGS="" - - CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2" - - NOCONFIGURE=1 - # COVERITY_SCAN_TOKEN - - secure: "k6l/18dpsoPAf0E5RQWCr+rgjbHns0H3k0WzSYovCoVg0B7RVlV8x8OjyEOBzEvXI4aaHRdH6MHCPDFnX4fa7ysImlT6LxxIG8YhDdLkJWyS0hHbcJiGxko9AhAGzOZcDl8fZi13d697wagMqqXpjN5v2T/AQm8t4X9z2otJosY=" - -matrix: - include: - - os: linux - compiler: gcc - script: - # Remove the following three lines when Travis updates its distro - - export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig" - - export LD_LIBRARY_PATH="$HOME/.local/lib" - - bash .ci/build-freetype.sh - - - ./autogen.sh - - ./configure $CONFIGURE_OPTS --enable-gtk-doc --enable-code-coverage - - make - - make check || .ci/fail.sh - - rm -rf freetype-2.9 - after_success: - - bash .ci/run-coveralls.sh # coveralls.io code coverage - - bash <(curl -s https://codecov.io/bash) # codecov.io code coverage - - bash .ci/deploy-docs.sh - - bash .ci/trigger-coverity.sh - - - os: linux - compiler: clang - script: - # Remove the following three lines when Travis updates its distro - - export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig" - - export LD_LIBRARY_PATH="$HOME/.local/lib" - - bash .ci/build-freetype.sh - - - ./autogen.sh - - ./configure $CONFIGURE_OPTS - - make - - make check || .ci/fail.sh - -notifications: - irc: "irc.freenode.org#harfbuzz" - email: harfbuzz-bots-chatter@googlegroups.com - -cache: - directories: - - /home/travis/.local - -addons: - apt: - packages: - - pkg-config # for autogen.sh - - ragel - - lcov - - gtk-doc-tools - - libfreetype6-dev # for font function - - libglib2.0-dev # for font functions / tests / utils - - libcairo2-dev # for utils - - libicu-dev # for extra unicode functions - - libgraphite2-dev # for extra shapers - #- libgirepository1.0-dev # for gobject-introspection - - coverity_scan: - project: - name: behdad/harfbuzz - version: 1.0 - description: HarfBuzz OpenType text shaping engine - notification_email: harfbuzz-bots-chatter@googlegroups.com - build_command_prepend: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 - build_command: make - branch_pattern: coverity_scan diff --git a/BUILD.gn b/BUILD.gn index b1c5304497af93d78de18abc5248f41889f01f1d..87edce6bbf0e67f200ad1fe25d22371aca69e9a0 100755 --- a/BUILD.gn +++ b/BUILD.gn @@ -28,6 +28,7 @@ harfbuzz_source = [ "//third_party/harfbuzz/src/hb-fallback-shape.cc", "//third_party/harfbuzz/src/hb-font.cc", "//third_party/harfbuzz/src/hb-map.cc", + "//third_party/harfbuzz/src/hb-number.cc", "//third_party/harfbuzz/src/hb-ot-cff1-table.cc", "//third_party/harfbuzz/src/hb-ot-cff2-table.cc", "//third_party/harfbuzz/src/hb-ot-face.cc", @@ -46,8 +47,8 @@ harfbuzz_source = [ "//third_party/harfbuzz/src/hb-ot-shape-complex-indic.cc", "//third_party/harfbuzz/src/hb-ot-shape-complex-khmer.cc", "//third_party/harfbuzz/src/hb-ot-shape-complex-myanmar.cc", + "//third_party/harfbuzz/src/hb-ot-shape-complex-syllabic.cc", "//third_party/harfbuzz/src/hb-ot-shape-complex-thai.cc", - "//third_party/harfbuzz/src/hb-ot-shape-complex-use-table.cc", "//third_party/harfbuzz/src/hb-ot-shape-complex-use.cc", "//third_party/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc", "//third_party/harfbuzz/src/hb-ot-shape-fallback.cc", @@ -70,13 +71,14 @@ if (defined(ohos_lite)) { lite_library("harfbuzz") { target_type = "shared_library" sources = harfbuzz_source - + defines = [ "HAVE_PTHREAD = 1" ] public_configs = [ ":harfbuzz_config" ] } } else { ohos_static_library("harfbuzz_static") { sources = harfbuzz_source include_dirs = [ "src\base" ] + defines = [ "HAVE_PTHREAD = 1" ] public_configs = [ ":harfbuzz_config" ] } } diff --git a/BUILD.md b/BUILD.md index 4c1c306450c88fcb171904784c5b89dcce22b8ee..f64f8687d3c090e3d6df5d2d540b2050ac2ac7f7 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,50 +1,27 @@ On Linux, install the development packages for FreeType, Cairo, and GLib. For example, on Ubuntu / Debian, you would do: - sudo apt-get install gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev + sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do: - sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel + sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-dev -on Windows, consider using [vcpkg](https://github.com/Microsoft/vcpkg), -provided by Microsoft, for building HarfBuzz and other open-source libraries -but if you need to build harfbuzz from source, put ragel binary on your -PATH and follow appveyor CI's cmake -[build steps](https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml). +and on ArchLinux and Manjaro: -on macOS, using MacPorts: + sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo - sudo port install freetype glib2 cairo +then use meson to build the project like `meson build && meson test -Cbuild`. -or using Homebrew: +On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson` then use +meson like above. - brew install freetype glib cairo +On Windows, meson can build the project like above if a working MSVC's cl.exe (`vcvarsall.bat`) +or gcc/clang is already on your path, and if you use something like `meson build --wrap-mode=default` +it fetches and compiles most of the dependencies also. -If you are using a tarball, you can now proceed to running configure and make -as with any other standard package. That should leave you with a shared -library in `src/`, and a few utility programs including `hb-view` and `hb-shape` -under `util/`. +Our CI configurations is also a good source of learning how to build HarfBuzz. -If you are bootstrapping from git, you need a few more tools before you can -run `autogen.sh` for the first time. Namely, `pkg-config` and `ragel`. - -Again, on Ubuntu / Debian: - - sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools - -and on Fedora, RHEL, CentOS: - - sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc - -on the Mac, using MacPorts: - - sudo port install autoconf automake libtool pkgconfig ragel gtk-doc - -or using Homebrew: - - brew install autoconf automake libtool pkgconfig ragel gtk-doc - -To build the Python bindings, you also need: - - brew install pygobject3 +There is also amalgam source provided with HarfBuzz which reduces whole process of building +HarfBuzz like `g++ src/harfbuzz.cc -fno-exceptions` but there is not guarantee provided +with buildability and reliability of features you get. diff --git a/CMakeLists.txt b/CMakeLists.txt index 66e4a83883448f6a9058d5ae8edd036235e2ede0..379091907718754de2f08f174024a3dfe3f05b02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ -cmake_minimum_required(VERSION 2.8.0) +cmake_minimum_required(VERSION 3.0.0) project(harfbuzz) -enable_testing() +message(WARN "HarfBuzz has a Meson port and tries to migrate all the other build systems to it, please consider using it as we might remove our cmake port soon.") ## Limit framework build to Xcode generator if (BUILD_FRAMEWORK) @@ -53,7 +53,6 @@ if (HB_BUILD_UTILS) endif () option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON) -option(HB_BUILD_TESTS "Build harfbuzz tests" ON) option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF) if (HB_HAVE_GOBJECT) @@ -66,25 +65,6 @@ if (HB_HAVE_INTROSPECTION) set (HB_HAVE_GLIB ON) endif () -option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and enable all options)") -if (HB_CHECK) - set (BUILD_SHARED_LIBS ON) - set (HB_BUILD_UTILS ON) - set (HB_HAVE_ICU) - set (HB_HAVE_GLIB ON) - #set (HB_HAVE_GOBJECT ON) - #set (HB_HAVE_INTROSPECTION ON) - set (HB_HAVE_FREETYPE ON) - set (HB_HAVE_GRAPHITE2 ON) - if (WIN32) - set (HB_HAVE_UNISCRIBE ON) - set (HB_HAVE_GDI ON) - set (HB_HAVE_DIRECTWRITE ON) - elseif (APPLE) - set (HB_HAVE_CORETEXT ON) - endif () -endif () - include_directories(AFTER ${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src @@ -108,7 +88,7 @@ endmacro () if (UNIX) list(APPEND CMAKE_REQUIRED_LIBRARIES m) endif () -check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l) +check_funcs(atexit mprotect sysconf getpagesize mmap isatty) check_include_file(unistd.h HAVE_UNISTD_H) if (${HAVE_UNISTD_H}) add_definitions(-DHAVE_UNISTD_H) @@ -117,15 +97,15 @@ check_include_file(sys/mman.h HAVE_SYS_MMAN_H) if (${HAVE_SYS_MMAN_H}) add_definitions(-DHAVE_SYS_MMAN_H) endif () -check_include_file(xlocale.h HAVE_XLOCALE_H) -if (${HAVE_XLOCALE_H}) - add_definitions(-DHAVE_XLOCALE_H) -endif () check_include_file(stdbool.h HAVE_STDBOOL_H) if (${HAVE_STDBOOL_H}) add_definitions(-DHAVE_STDBOOL_H) endif () +# https://github.com/harfbuzz/harfbuzz/pull/2874#issuecomment-782859099 +if (NOT WIN32) + add_definitions("-DHAVE_PTHREAD") +endif () if (MSVC) add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS) @@ -147,7 +127,7 @@ function (extract_make_variable variable makefile_source) set (${variable} ${listVar} PARENT_SCOPE) endfunction () -# http://stackoverflow.com/a/27630120 +# https://stackoverflow.com/a/27630120 function (add_prefix_to_list var prefix) set (listVar "") foreach (f ${${var}}) @@ -257,7 +237,7 @@ endif () if (HB_HAVE_ICU) add_definitions(-DHAVE_ICU) - # https://github.com/WebKit/webkit/blob/master/Source/cmake/FindICU.cmake + # https://github.com/WebKit/webkit/blob/fdd7733f2f30eab7fe096a9791f98c60f62f49c0/Source/cmake/FindICU.cmake find_package(PkgConfig) pkg_check_modules(PC_ICU QUIET icu-uc) @@ -326,6 +306,7 @@ if (WIN32 AND HB_HAVE_DIRECTWRITE) endif () if (HB_HAVE_GOBJECT) + add_definitions(-DHAVE_GOBJECT) include (FindPerl) # Use the hints from glib-2.0.pc to find glib-mkenums @@ -429,41 +410,25 @@ if (HB_HAVE_GOBJECT) ) endif () -## Atomic ops availability detection -file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c" -" void memory_barrier (void) { __sync_synchronize (); } - int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); } - int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); } - void mutex_unlock (int *m) { __sync_lock_release (m); } - int main () { return 0; } -") -try_compile(HB_HAVE_INTEL_ATOMIC_PRIMITIVES - ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives - ${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c) -if (HB_HAVE_INTEL_ATOMIC_PRIMITIVES) - add_definitions(-DHAVE_INTEL_ATOMIC_PRIMITIVES) -endif () - -file(WRITE "${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c" -" #include - /* This requires Solaris Studio 12.2 or newer: */ - #include - void memory_barrier (void) { __machine_rw_barrier (); } - int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); } - void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); } - int main () { return 0; } -") -try_compile(HB_HAVE_SOLARIS_ATOMIC_OPS - ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops - ${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c) -if (HB_HAVE_SOLARIS_ATOMIC_OPS) - add_definitions(-DHAVE_SOLARIS_ATOMIC_OPS) -endif () - ## Define harfbuzz library add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers}) target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS}) +target_include_directories(harfbuzz PUBLIC + "$" + "$") + +## Define harfbuzz-icu library +if (HB_HAVE_ICU) + add_library(harfbuzz-icu ${PROJECT_SOURCE_DIR}/src/hb-icu.cc ${PROJECT_SOURCE_DIR}/src/hb-icu.h) + add_dependencies(harfbuzz-icu harfbuzz) + target_link_libraries(harfbuzz-icu harfbuzz ${THIRD_PARTY_LIBS}) + + if (BUILD_SHARED_LIBS) + set_target_properties(harfbuzz harfbuzz-icu PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE) + endif () +endif () + ## Define harfbuzz-subset library if (HB_BUILD_SUBSET) @@ -615,12 +580,14 @@ if (HB_HAVE_INTROSPECTION) POST_BUILD COMMAND ${G_IR_SCANNER_CMD} --warn-all --no-libtool --verbose - -n hb --namespace=HarfBuzz --nsversion=0.0 + --symbol-prefix=hb + --symbol-prefix=hb_gobject --identifier-prefix=hb_ --include GObject-2.0 - --pkg-export=harfbuzz + --pkg-export=harfbuzz-gobject + --c-include=hb-gobject.h --cflags-begin -I${PROJECT_SOURCE_DIR}/src -I${PROJECT_BINARY_DIR}/src @@ -723,6 +690,14 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) NAMESPACE harfbuzz:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz ) + if (HB_HAVE_ICU) + install(TARGETS harfbuzz-icu + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FRAMEWORK DESTINATION Library/Frameworks + ) + endif () if (HB_BUILD_UTILS) if (WIN32 AND BUILD_SHARED_LIBS) install(TARGETS harfbuzz-subset @@ -767,54 +742,3 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) endif () endif () endif () - -if (HB_BUILD_TESTS) - ## src/ executables - foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize test-unicode-ranges) # hb-ot-tag - set (prog_name ${prog}) - if (${prog_name} STREQUAL "test") - # test can not be used as a valid executable name on cmake, lets special case it - set (prog_name test-test) - endif () - add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc) - target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS}) - endforeach () - # set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN") - - ## Tests - if (UNIX OR MINGW) - if (BUILD_SHARED_LIBS) - # generate harfbuzz.def after build completion - add_custom_command(TARGET harfbuzz POST_BUILD - COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src) - - add_test(NAME check-static-inits.sh - COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack - ) - add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh) - add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh) - - set_tests_properties( - check-static-inits.sh check-libstdc++.sh check-symbols.sh - PROPERTIES - ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src" - SKIP_RETURN_CODE 77) - endif () - - add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh) - add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh) - add_test(NAME check-externs.sh COMMAND ./check-externs.sh) - add_test(NAME check-includes.sh COMMAND ./check-includes.sh) - set_tests_properties( - check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh - PROPERTIES - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src - SKIP_RETURN_CODE 77) - endif () - - # Needs to come last so that variables defined above are passed to - # subdirectories. - add_subdirectory(test) -endif () diff --git a/CONFIG.md b/CONFIG.md index 46971b0f2d971bda9129436d0db1ed9e2b190b41..2ca02935c579abc2c1657fe0f745b78db57a4b7f 100644 --- a/CONFIG.md +++ b/CONFIG.md @@ -1,9 +1,9 @@ # Configuring HarfBuzz Most of the time you will not need any custom configuration. The configuration -options provided by `configure` or `cmake` should be enough. In particular, -if you just want HarfBuzz library plus hb-shape / hb-view utilities, make sure -FreeType and Cairo are available and found during configuration. +options provided by `meson` should be enough. In particular, if you just want +HarfBuzz library plus hb-shape / hb-view utilities, make sure FreeType and Cairo +are available and found during configuration. If you are building for distribution, you should more carefully consider whether you need Glib, ICU, Graphite2, as well as CoreText / Uniscribe / DWrite. Make @@ -18,9 +18,9 @@ binary size savings. ## Compiler Options Make sure you build with your compiler's "optimize for size" option. On `gcc` -this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os` either to `configure` -(sticky) or to `make` (non-sticky). On clang there is an even more extreme flag, -`-Oz`. +this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os`. On clang there +is an even more extreme flag, `-Oz`. Meson also provides `--buildtype=minsize` +for more convenience. HarfBuzz heavily uses inline functions and the optimize-size flag can make the library smaller by 20% or more. Moreover, sometimes, based on the target CPU, @@ -32,8 +32,7 @@ optimizations. Search for `HB_OPTIMIZE_SIZE` for details, if you are using other compilers, or continue reading. Another compiler option to consider is "link-time optimization", also known as -'lto'. To enable that, with `gcc` or `clang`, add `-flto` to both `CXXFLAGS` -and `LDFLAGS`, either on `configure` invocation (sticky) or on `make` (non-sticky). +'lto'. To enable that, feel free to use `-Db_lto=true` of meson. This, also, can have a huge impact on the final size, 20% or more. Finally, if you are making a static library build or otherwise linking the @@ -109,7 +108,7 @@ Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless. That removes the By default HarfBuzz builds as a thread-safe library. The exception is that the `HB_TINY` predefined configuring (more below) disables thread-safety. -If you do /not/ need thread-safety in the library (eg. you always call into +If you do *not* need thread-safety in the library (eg. you always call into HarfBuzz from the same thread), you can disable thread-safety by defining `HB_NO_MT`. As noted already, this is enabled by `HB_TINY`. @@ -145,7 +144,7 @@ overrides at the end. ## Notes Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and -`HB_TINY` does /not/ mean that the resulting library won't work with CFF fonts. +`HB_TINY` does *not* mean that the resulting library won't work with CFF fonts. The library can shape valid CFF fonts just fine, with or without this option. -This option disables (among other things) the code to calculate glyph exntents +This option disables (among other things) the code to calculate glyph extents for CFF fonts. diff --git a/COPYING b/COPYING index 0278e60a5c05492cfb64be11515701b482163df5..57343164f212b524ff39a0d89bb35572a8c213d9 100644 --- a/COPYING +++ b/COPYING @@ -2,8 +2,9 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. For parts of HarfBuzz that are licensed under different licenses see individual files names COPYING in subdirectories where applicable. -Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Google, Inc. -Copyright © 2019 Facebook, Inc. +Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc. +Copyright © 2018,2019,2020 Ebrahim Byagowi +Copyright © 2019,2020 Facebook, Inc. Copyright © 2012 Mozilla Foundation Copyright © 2011 Codethink Limited Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) diff --git a/Makefile.am b/Makefile.am index 2bbd3c55da375a4291f651e1606d32600f6cd5c7..aee0f530c771e04503249158269955f2bf3a222c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,6 @@ EXTRA_DIST = \ autogen.sh \ harfbuzz.doap \ README.md \ - README.mingw.md \ README.python.md \ BUILD.md \ CONFIG.md \ @@ -18,10 +17,29 @@ EXTRA_DIST = \ TESTING.md \ CMakeLists.txt \ replace-enum-strings.cmake \ + meson.build \ + meson_options.txt \ + subprojects/expat.wrap \ + subprojects/freetype2.wrap \ + subprojects/glib.wrap \ + subprojects/libffi.wrap \ + subprojects/proxy-libintl.wrap \ + subprojects/zlib.wrap \ + subprojects/google-benchmark.wrap \ + perf/meson.build \ + perf/perf-draw.hh \ + perf/perf-extents.hh \ + perf/perf-shaping.hh \ + perf/perf.cc \ + perf/fonts/Amiri-Regular.ttf \ + perf/fonts/NotoNastaliqUrdu-Regular.ttf \ + perf/fonts/NotoSansDevanagari-Regular.ttf \ + perf/fonts/Roboto-Regular.ttf \ + perf/texts/en-thelittleprince.txt \ + perf/texts/en-words.txt \ + perf/texts/fa-monologue.txt \ + perf/texts/fa-thelittleprince.txt \ mingw-configure.sh \ - mingw-ldd.py \ - mingw32.sh \ - mingw64.sh \ $(NULL) MAINTAINERCLEANFILES = \ @@ -75,29 +93,4 @@ dist-hook: dist-clear-sticky-bits dist-clear-sticky-bits: chmod -R a-s $(distdir) -tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.xz -sha256_file = $(tar_file).sha256 -gpg_file = $(sha256_file).asc -$(sha256_file): $(tar_file) - sha256sum $^ > $@ -$(gpg_file): $(sha256_file) - @echo "Please enter your GPG password to sign the checksum." - gpg --armor --sign $^ - -release-files: $(tar_file) $(sha256_file) $(gpg_file) - -dist-win: - @case $(host_triplet) in *-w64-mingw32) ;; *) echo "Error: Requires mingw build. See README.mingw.md.">&2; exit 1 ;; esac - @DIR=$(PACKAGE_TARNAME)-$(VERSION)-win`case $(host_triplet) in i686-*) echo 32 ;; x86_64-*) echo 64 ;; esac`; \ - $(RM) -r $$DIR; $(MKDIR_P) $$DIR || exit 1; \ - cp util/.libs/hb-{shape,view,subset}.exe $$DIR && \ - $(top_srcdir)/mingw-ldd.py $$DIR/hb-view.exe | grep -v 'not found' | cut -d '>' -f 2 | xargs cp -t $$DIR && \ - cp src/.libs/libharfbuzz{,-subset}-0.dll $$DIR && \ - chmod a+x $$DIR/*.{exe,dll} && \ - $(STRIP) $$DIR/*.{exe,dll} && \ - zip -r $$DIR.zip $$DIR && \ - $(RM) -r $$DIR && \ - echo "$$DIR.zip is ready." - - -include $(top_srcdir)/git.mk diff --git a/NEWS b/NEWS index ef5f487af1da6c4b721942c56c02fc6db6402cd0..a05ff67cfee8809b8ea8ba12d4feb716520ea8da 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,159 @@ +Overview of changes leading to 2.8.1 +Tuesday, May 4, 2021 +==================================== +- Subsetter now fully supports GSUB/GPOS/GDEF tables (including variations); as + such, layout tables are retained by subsetter by default. (Garret Rieger, Qunxin Liu) +- Build scripts no longer check for FontConfig as HarfBuzz does not use it. +- hb-view supports iTerm2 and kitty inline image protocols (Khaled Hosny), + it can also use Chafa for terminal graphics if available (Hans Petter Jansson). + +Overview of changes leading to 2.8.0 +Tuesday, March 16, 2021 +==================================== +- Shape joining scripts other than Arabic/Syriac using the Universal Shaping Engine. + Previously these were shaped using the generalized Arabic shaper. (David Corbett) +- Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett) +- Update language tags. (David Corbett) +- Variations: reduce error: do not round each interpolated delta. (Just van Rossum) +- Documentation improvements. (Khaled Hosny, Nathan Willis) +- Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu) +- Fuzzer-found fixes and other improvements when memory failures happen. (Behdad) +- Removed most atomic implementations now that we have C++11 atomic impl. (Behdad) +- General codebase upkeep; using more C++11 features: constexpr constructors, etc. (Behdad) + + +Overview of changes leading to 2.7.4 +Sunday, December 27, 2020 +==================================== +- Fix missing --enable-introspection configure option from previous release + tarball. +- Documentation updates. + +Overview of changes leading to 2.7.3 +Wednesday, December 23, 2020 +==================================== +- Update USE shaper to 2020-08-13 specification, and other improvements. +- Don’t disable liga feature in myanmar shaper, to match Uniscribe. +- Improvements to language and script tags handling. +- Update language system tag registry to OpenType 1.8.4 +- Support for serializing and deserializing Unicode buffers. Serialized buffers + are now delimited with `<>` or `[]` based on whether it is a Unicode or + glyphs buffer. +- Increase buffer work limits to handle fonts with many complex lookups. +- Handle more shaping operations in trace output. +- Memory access fixes. +- More OOM fixes. +- Improved documentation. +- Build system improvements. +- New API: ++hb_buffer_has_positions() ++hb_buffer_serialize() ++hb_buffer_serialize_unicode() ++hb_buffer_deserialize_unicode() + + +Overview of changes leading to 2.7.2 +Saturday, August 29, 2020 +==================================== +- Fix a regression in the previous release that caused a crash with Kaithi. +- More OOM fixes. + + +Overview of changes leading to 2.7.1 +Thursday, August 13, 2020 +==================================== +- ot-funcs now handles variable empty glyphs better when hvar/vvar isn't present. +- Reverted a GDEF processing regression. +- A couple of fixes to handle OOM better. + + +Overview of changes leading to 2.7.0 +Saturday, July 25, 2020 +==================================== +- Use an implementation for round that always rounds up, some minor fluctuations + are expected on var font specially when hb-ot callback is used. +- Fix an AAT's `kerx` issue on broken rendering of Devanagari Sangam MN. +- Remove AAT's `lcar` table support from _get_ligature_carets API, not even much + use on macOS installed fonts (only two files). GDEF support is the recommended + one and expected to work properly after issues fixed two releases ago. +- Minor memory fixes to handle OOM better specially in hb-ft. +- Minor .so files versioning scheme change and remove stable/unstable scheme + differences, was never used in practice (always default to stable scheme). +- We are now suggesting careful packaging of the library using meson, + https://github.com/harfbuzz/harfbuzz/wiki/Notes-on-migration-to-meson + for more information. +- Distribution package URL is changed, either use GitHub generated tarballs, + `https://github.com/harfbuzz/harfbuzz/archive/$pkgver.tar.gz` + or, even more preferably use commit hash of the release and git checkouts like, + `git+https://github.com/harfbuzz/harfbuzz#commit=$commit` + + +Overview of changes leading to 2.6.8 +Monday, June 22, 2020 +==================================== +- New API to fetch glyph alternates from GSUB table. +- hb-coretext build fix for macOS < 10.10. +- Meson build fixes, cmake port removal is postponed but please prepare for + it and give us feedback. + Autotools is still our main build system however please consider + experimenting with meson also for packaging the library. +- New API: ++hb_ot_layout_lookup_get_glyph_alternates() + + +Overview of changes leading to 2.6.7 +Wednesday, June 3, 2020 +==================================== +- Update to Unicode 13.0.0. +- Fix hb_ot_layout_get_ligature_carets for fonts without lcar table, it was + completely broken for all the other fonts since 2.1.2. +- As a part of our migration to meson, this release will be the last one + to provide cmake port files but autotools still is our main build system. + There is a possibility that the next version or the after be released + using meson. + + +Overview of changes leading to 2.6.6 +Tuesday, May 12, 2020 +==================================== +- A fix in AAT kerning for Geeza Pro. +- Better support for resource fork fonts on macOS. + + +Overview of changes leading to 2.6.5 +Friday, April 17, 2020 +==================================== +- Add experimental meson build system. Autotools is still the primary + and supported build system. +- AAT is now always preferred for horizontal scripts when both AAT and OT + layout tables exist at the same time. +- Subsetter improvements. +- New API: ++hb_ft_font_lock_face() ++hb_ft_font_unlock_face() + + +Overview of changes leading to 2.6.4 +Monday, October 29, 2019 +==================================== +- Small bug fix. +- Build fixes. + + +Overview of changes leading to 2.6.3 +Monday, October 28, 2019 +==================================== +- Misc small fixes, mostly to build-related issues. +- New API: ++hb_font_get_nominal_glyphs() + + +Overview of changes leading to 2.6.2 +Monday, September 30, 2019 +==================================== +- Misc small fixes, mostly to build-related issues. + + Overview of changes leading to 2.6.1 Thursday, August 22, 2019 ==================================== diff --git a/README b/README index 42061c01a1c70097d1e4579f29a5adf40abdec95..f4d2294c934d474485357b851a2c121fce1c9b0a 120000 --- a/README +++ b/README @@ -1 +1,15 @@ -README.md \ No newline at end of file +This is HarfBuzz, a text shaping library. + +For bug reports, mailing list, and other information please visit: + + http://harfbuzz.org/ + +For license information, see https://github.com/harfbuzz/harfbuzz/blob/master/COPYING + +For build information, see https://github.com/harfbuzz/harfbuzz/blob/master/BUILD.md + +For custom configurations, see https://github.com/harfbuzz/harfbuzz/blob/master/CONFIG.md + +For test execution, see https://github.com/harfbuzz/harfbuzz/blob/master/TESTING.md + +Documentation: https://harfbuzz.github.io diff --git a/README.OpenSource b/README.OpenSource index 27779cb8188e892a6e9232c1d113f35e6570fc90..ba3a8565d3d6d4b98d226dd827218c116abf00f6 100755 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,9 +3,9 @@ "Name" : "harfbuzz", "License" : "MIT License", "License File" : "COPYING", - "Version Number" : "2.6.1", + "Version Number" : "2.8.1", "Owner" : "liyujia4@huawei.com", - "Upstream URL" : "https://github.com/harfbuzz/harfbuzz/releases/tag/2.6.1", + "Upstream URL" : "https://github.com/harfbuzz/harfbuzz/releases/tag/2.8.1", "Description" : "HarfBuzz is a text shaping engine. It primarily supports OpenType, but also Apple Advanced Typography. HarfBuzz is used in Android, Chrome, ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt, XeTeX, and other places." } ] \ No newline at end of file diff --git a/README.md b/README.md index c3cc0c26e948e4771de115a55285fbead11778fd..0df556de37fa8a76b0154bcce94cbbe8a71efd68 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg?branch=master)](https://travis-ci.org/harfbuzz/harfbuzz) -[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true&branch=master)](https://ci.appveyor.com/project/harfbuzz/harfbuzz) +[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg) [![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master) [![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html) [![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz) [![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz) [![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz) [![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz) +[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions) [ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/) This is HarfBuzz, a text shaping library. @@ -23,3 +23,11 @@ For custom configurations, see [CONFIG.md](CONFIG.md). For test execution, see [TESTING.md](TESTING.md). Documentation: https://harfbuzz.github.io + + +
+ Packaging status of HarfBuzz + +[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions) + +
diff --git a/README.mingw.md b/README.mingw.md index 76d1a8754e3f7ed6d452b91674890a7ea74e5649..d9bd3474021882bd605d64b4149204a9604275e1 100644 --- a/README.mingw.md +++ b/README.mingw.md @@ -4,28 +4,35 @@ implementation and that specially is important where OpenType specification is or wasn't that clear. For having access to Uniscribe on Linux/macOS these steps are recommended: -1. Install Wine from your favorite package manager. On Fedora that's `dnf install wine`. +You want to follow the 32bit instructions. The 64bit equivalents are included +for reference. -2. And `mingw-w64` compiler. - With `brew` on macOS, you can have it like `brew install mingw-w64`. - On Fedora, with `dnf install mingw32-gcc-c++`, or `dnf install mingw64-gcc-c++` for the - 64-bit Windows. +1. Install Wine. + - Fedora: `dnf install wine`. -3. Install cross-compiled dependency packages. Alternatively see [^1] below. - On Fedora that would be `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype` - for 32-bit, or `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` for 64-bit. +2. Install `mingw-w64` compiler. + - Fedora, 32bit: `dnf install mingw32-gcc-c++` + - Fedora, 64bit: `dnf install mingw64-gcc-c++` + - Debian: `apt install g++-mingw-w64` + - Mac: `brew install mingw-w64` -5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild` +3. If you have drank the `meson` koolaid, look at `.ci/build-win32.sh` to see how to + invoke `meson` now, or just run that script. Otherwise, here's how to use the + old trusty autotools instead: -6. Run `../mingw32.sh` for 32-bit build, or `../mingw64.sh` for 64-bit. This configures - HarfBuzz for cross-compiling. It enables Uniscribe backend as well. + a) Install dependencies. + - Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype` + - Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` -7. `make` + b) Configure: + - `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild` + - 32bit: `../mingw-configure.sh i686` + - 64bit: `../mingw-configure.sh x86_64` -Now you can use hb-shape using `wine util/hb-shape.exe` but if you like to shape with -the Microsoft Uniscribe, +Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)` +but if you like to shape with the Microsoft Uniscribe: -8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your +4. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your Windows installation (assuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy ([for more info](https://en.wikipedia.org/wiki/Uniscribe)). @@ -35,14 +42,6 @@ the Microsoft Uniscribe, Put the DLL in the folder you are going to run the next command, -9. `WINEDLLOVERRIDES="usp10=n" wine util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe` +5. `WINEDLLOVERRIDES="usp10=n" wine hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe` (`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need) - - -[^1] Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) - in your `~/.local/i686-w64-mingw32`. Then replace all the instances of - `/home/behdad/.local/i586-mingw32msvc` and `/home/behdad/.local/i686-w64-mingw32` - with `<$HOME>/.local/i686-w64-mingw32` on that folder. - (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS) - You shouldn't replace the instances of those inside binary files. diff --git a/README.python.md b/README.python.md index d9aaf898717d3d1e5abcedd9a8802608f1a6787b..7496f045ec9238c5504b04f244cb679b7767b4ca 100644 --- a/README.python.md +++ b/README.python.md @@ -6,13 +6,8 @@ you can install that this way: sudo apt-get install libgirepository1.0-dev ``` -And then run `autogen.sh` (if building from git), and then: - -```bash -./configure --with-gobject --enable-introspection -``` - -Make sure that gobject-introspection is reported enabled then in the `configure` script output. +And then run `meson setup` and make sure that `Introspection` is reported +enabled in output. Compile and install. diff --git a/RELEASING.md b/RELEASING.md index 360aea76450b96f42dfdb9db31a4e2cb2a4cb6b4..e3ef7b66e5c117dbdebed44550e0a05652360ca6 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -20,53 +20,25 @@ HarfBuzz release walk-through checklist: 3. Search for REPLACEME on the repository and replace it with the chosen version for the release. -4. Make sure you have correct date and new version at the top of NEWS file, +4. Make sure you have correct date and new version at the top of NEWS file. -5. Bump version in configure.ac line 3, +5. Bump version in line 3 of meson.build and configure.ac. + Do a `meson test -Cbuild` so it both checks the tests and updates + hb-version.h (use `git diff` to see if is really updated). -6. Do "make distcheck", if it passes, you get a tarball. - Otherwise, fix things and commit them separately before making release, - Note: Check src/hb-version.h and make sure the new version number is - there. Sometimes, it does not get updated. If that's the case, - "touch configure.ac" and rebuild. Also check that there is no hb-version.h - in your build/src file. Typically it will fail the distcheck if there is. - That's what happened to 2.0.0 going out with 1.8.0 hb-version.h... So, that's - a clue. +6. Commit NEWS, meson.build, configure.ac, and src/hb-version.h, as well as any REPLACEME + changes you made. The commit message is simply the release number. Eg. "1.4.7" -7. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h, - as well as any REPLACEME changes you made. The commit message is simply the - release number. Eg. "1.4.7" +7. Do a `meson dist -Cbuild` that runs the tests against the latest commited changes. + If doesn't pass, something fishy is going on, reset the repo and start over. -8. "make dist" again to get a tarball with your new commit in the ChangeLog. Then - "make release-files". Enter your GPG password. This creates a sha256 hash - and signs it. Check the size of the three resulting files. +8. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your + GPG password. -9. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your - GPG password again. +9. Build win32 bundle. See [README.mingw.md](README.mingw.md). -10. Build win32 bundle. +10. Push the commit and tag out: "git push --follow-tags". - a. Build Win32 binaries. See [README.mingw.md](README.mingw.md). - - b. Run "make dist-win" to build Win32 bundle. - -11. Copy all artefacts to users.freedesktop.org and move them into - `/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four - files. Eg.: - ``` --rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.xz --rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256 --rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256.asc --rw-r--r-- 1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip -``` - -12. While doing that, quickly double-check the size of the .tar.xz and .zip - files against their previous releases to make sure nothing bad happened. - They should be in the ballpark, perhaps slightly larger. Sometimes they - do shrink, that's not by itself a stopper. - -13. Push the commit and tag out: "git push --follow-tags". Make sure it's - pushed both to freedesktop repo and github. - -14. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases), - edit the tag, upload artefacts and NEWS entry and save. +11. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases), + edit the tag, upload win32 bundle and NEWS entry and save. + No need to upload source tarball as we rely to GitHub's automatic tar.gz generation. diff --git a/TESTING.md b/TESTING.md index 4efc64ca5a9fa40f2151e175b068118260466733..c722834559d390a374bb9a0be04b4305ff82531a 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,75 +1,55 @@ -## Build & Run - -Depending on what area you are working in change or add `HB_DEBUG_`. -Values defined in `hb-debug.hh`. +## Build and Test ```shell -# quick sanity check -time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \ - && (make -j4 -C test/api check || cat test/api/test-suite.log)) - -# slower sanity check -time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \ - && make -j4 -C src check \ - && make -j4 -C test/api check \ - && make -j4 -C test/subset check) +meson build +ninja -Cbuild +meson test -Cbuild +``` -# confirm you didn't break anything else -time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \ - && make -j4 check) +### Debug with GDB -# often catches files you didn't add, e.g. test fonts to EXTRA_DIST -make distcheck +```shell +meson test -Cbuild --gdb testname ``` -### Run tests with asan +## Build and Run -**NOTE**: this sometimes yields harder to read results than the full fuzzer +Depending on what area you are working in change or add `HB_DEBUG_`. +Values defined in `hb-debug.hh`. ```shell -# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8 -# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer -# ex -export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer - -./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address -# make/run tests as usual +CPPFLAGS='-DHB_DEBUG_SUBSET=100' meson setup build --reconfigure +meson test -C build ``` -### Debug with GDB +### Run tests with asan -``` -cd ./util -../libtool --mode=execute gdb --args ./hb-subset ... +```shell +meson setup build -Db_sanitize=address --reconfigure +meson compile -C build +meson test -C build ``` ### Enable Debug Logging ```shell -# make clean if you previously build w/o debug logging -make CPPFLAGS=-DHB_DEBUG_SUBSET=100 +CPPFLAGS=-DHB_DEBUG_SUBSET=100 meson build --reconfigure +ninja -C build ``` -## Build and Test via CMake - -Note: You'll need to first install ninja-build via apt-get. - -```shell -cd harfbuzz -mkdir buid -cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test -``` ## Test with the Fuzzer ```shell -# push your changs to a branch on googlefonts/harfbuzz -# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile -# Change the git clone to pull your branch +CXXFLAGS="-fsanitize=address,fuzzer-no-link" meson fuzzbuild --default-library=static -Dfuzzer_ldflags="-fsanitize=address,fuzzer" -Dexperimental_api=true +ninja -Cfuzzbuild test/fuzzing/hb-{shape,draw,subset,set}-fuzzer +fuzzbuild/test/fuzzing/hb-subset-fuzzer test/fuzzing/fonts +``` -# Do this periodically -sudo python infra/helper.py build_image harfbuzz +## Profiling -# Do these to update/run -sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz -sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer ``` +meson build --reconfigure +meson compile -C build +build/perf/perf +``` + diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 7fbcf491cd1a80514ccc52d572bc3d766aa58b14..0000000000000000000000000000000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,93 +0,0 @@ -platform: x64 - -environment: - matrix: - - #- compiler: msvc - # generator: Visual Studio 14 - # platform: Win32 - # configuration: Debug - # triplet: x86-windows - - #- compiler: msvc - # generator: Visual Studio 14 Win64 - # platform: x64 - # configuration: Debug - # triplet: x64-windows - - - compiler: msvc - generator: Visual Studio 14 ARM - platform: ARM - configuration: Debug - - - # Build only - - #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 - # compiler: msvc2 - # generator: Visual Studio 12 - # platform: Win32 - # configuration: Release - # triplet: x86-windows - - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - compiler: msvc2 - generator: Visual Studio 15 - platform: Win32 - configuration: Release - triplet: x86-windows - - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - compiler: msvc2 - generator: Visual Studio 16 - platform: Win32 - configuration: Release - triplet: x86-windows - - - - compiler: msys2 - MINGW_PREFIX: /mingw64 - MINGW_CHOST: x86_64-w64-mingw32 - MSYS2_ARCH: x86_64 - - - compiler: msys2 - MINGW_PREFIX: /mingw32 - MINGW_CHOST: i686-w64-mingw32 - MSYS2_ARCH: i686 - - -install: - - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2,ragel}"' - - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%' - -build_script: - - 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%"' - - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake' - - - 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin' - - 'if "%compiler%"=="msvc" cd build' - - 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%' - - 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%' - - - 'if "%compiler%"=="msvc2" cmake -G "%generator%" -Bbuild -H.' - - 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%' - - - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"' - - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --with-gdi --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"' - -cache: - - c:\tools\vcpkg\installed\ - -notifications: - - provider: Email - to: - - harfbuzz-bots-chatter@googlegroups.com - on_build_success: false - on_build_failure: true - on_build_status_changed: true - -# Do not build feature branch with open Pull Requests -skip_branch_with_pr: true - -# disable automatic tests -test: off diff --git a/autogen.sh b/autogen.sh index fd5c1983c732faaa0f2c31b6991f8c778de1ceb9..085b4d8632d15a979bbcefd654e06e4ffec9ec60 100755 --- a/autogen.sh +++ b/autogen.sh @@ -7,24 +7,24 @@ test -n "$srcdir" || srcdir=. olddir=`pwd` cd $srcdir -#echo -n "checking for ragel... " +#printf "checking for ragel... " #which ragel || { # echo "You need to install ragel... See http://www.complang.org/ragel/" # exit 1 #} -echo -n "checking for pkg-config... " +printf "checking for pkg-config... " which pkg-config || { echo "*** No pkg-config found, please install it ***" exit 1 } -echo -n "checking for libtoolize... " +printf "checking for libtoolize... " which glibtoolize || which libtoolize || { echo "*** No libtoolize (libtool) found, please install it ***" exit 1 } -echo -n "checking for gtkdocize... " +printf "checking for gtkdocize... " if which gtkdocize ; then gtkdocize --copy || exit 1 else @@ -32,7 +32,7 @@ else echo "EXTRA_DIST = " > gtk-doc.make fi -echo -n "checking for autoreconf... " +printf "checking for autoreconf... " which autoreconf || { echo "*** No autoreconf (autoconf) found, please install it ***" exit 1 diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 88c0a984aad41e66243f6f455482bb63c1bab982..0000000000000000000000000000000000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,21 +0,0 @@ -pool: - vmImage: 'VS2017-Win2016' - -variables: - buildPlatform: 'x86' - buildConfiguration: 'Debug' - triplet: 'x86-windows' - -steps: -- script: | - git clone https://github.com/Microsoft/vcpkg - cd vcpkg - .\bootstrap-vcpkg.bat - .\vcpkg integrate install - .\vcpkg install glib:x86-windows freetype:x86-windows cairo:x86-windows - cd .. - cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake ../ - msbuild harfbuzz.sln /p:Configuration=Debug /p:Platform=Win32 - cd build - ctest --output-on-failure -C Debug - displayName: Build and test diff --git a/configure.ac b/configure.ac index ab079fc05835d620b985accfadc3e5a90785c056..043f6ed61b59f1e12ea0581cf7e5d7986824accb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.64]) AC_INIT([HarfBuzz], - [2.6.1], + [2.8.1], [https://github.com/harfbuzz/harfbuzz/issues/new], [harfbuzz], [http://harfbuzz.org/]) @@ -23,9 +23,9 @@ AC_PROG_CC AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_CXX -AX_CXX_COMPILE_STDCXX(11,, optional) +AX_CXX_COMPILE_STDCXX(11) AC_SYS_LARGEFILE -PKG_PROG_PKG_CONFIG([0.20]) +PKG_PROG_PKG_CONFIG([0.28]) AM_MISSING_PROG([RAGEL], [ragel]) AM_MISSING_PROG([GIT], [git]) @@ -46,16 +46,7 @@ AC_SUBST(HB_VERSION) # Libtool version m4_define([hb_version_int], m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro)) -m4_if(m4_eval(hb_version_minor % 2), [1], - dnl for unstable releases - [m4_define([hb_libtool_revision], 0)], - dnl for stable releases - [m4_define([hb_libtool_revision], hb_version_micro)]) -m4_define([hb_libtool_age], - m4_eval(hb_version_int - hb_libtool_revision)) -m4_define([hb_libtool_current], - m4_eval(hb_libtool_age)) -HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age +HB_LIBTOOL_VERSION_INFO=hb_version_int:0:hb_version_int AC_SUBST(HB_LIBTOOL_VERSION_INFO) AC_ARG_WITH([libstdc++], @@ -77,8 +68,8 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl]) ]) # Functions and headers -AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l) -AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h) +AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty) +AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h) # Compiler flags AC_CANONICAL_HOST @@ -223,21 +214,21 @@ AM_CONDITIONAL(HAVE_CAIRO_FT, $have_cairo_ft) dnl ========================================================================== -AC_ARG_WITH(fontconfig, - [AS_HELP_STRING([--with-fontconfig=@<:@yes/no/auto@:>@], - [Use fontconfig @<:@default=auto@:>@])],, - [with_fontconfig=auto]) -have_fontconfig=false -if test "x$with_fontconfig" = "xyes" -o "x$with_fontconfig" = "xauto"; then - PKG_CHECK_MODULES(FONTCONFIG, fontconfig, have_fontconfig=true, :) +AC_ARG_WITH(chafa, + [AS_HELP_STRING([--with-chafa=@<:@yes/no/auto@:>@], + [Use chafa @<:@default=auto@:>@])],, + [with_chafa=auto]) +have_chafa=false +if test "x$with_chafa" = "xyes" -o "x$with_chafa" = "xauto"; then + PKG_CHECK_MODULES(CHAFA, chafa >= 1.6.0, have_chafa=true, :) fi -if test "x$with_fontconfig" = "xyes" -a "x$have_fontconfig" != "xtrue"; then - AC_MSG_ERROR([fontconfig support requested but not found]) +if test "x$with_chafa" = "xyes" -a "x$have_chafa" != "xtrue"; then + AC_MSG_ERROR([chafa support requested but not found]) fi -if $have_fontconfig; then - AC_DEFINE(HAVE_FONTCONFIG, 1, [Have fontconfig library]) +if $have_chafa; then + AC_DEFINE(HAVE_CHAFA, 1, [Have chafa terminal graphics library]) fi -AM_CONDITIONAL(HAVE_FONTCONFIG, $have_fontconfig) +AM_CONDITIONAL(HAVE_CHAFA, $have_chafa) dnl ========================================================================== @@ -248,25 +239,6 @@ AC_ARG_WITH(icu, have_icu=false if test "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" -o "x$with_icu" = "xauto"; then PKG_CHECK_MODULES(ICU, icu-uc, have_icu=true, :) - - dnl Fallback to icu-config if ICU pkg-config files could not be found - if test "$have_icu" != "true"; then - AC_CHECK_TOOL(ICU_CONFIG, icu-config, no) - AC_MSG_CHECKING([for ICU by using icu-config fallback]) - if test "$ICU_CONFIG" != "no" && "$ICU_CONFIG" --version >/dev/null; then - have_icu=true - # We don't use --cflags as this gives us a lot of things that we don't - # necessarily want, like debugging and optimization flags - # See man (1) icu-config for more info. - ICU_CFLAGS=`$ICU_CONFIG --cppflags` - ICU_LIBS=`$ICU_CONFIG --ldflags-searchpath --ldflags-libsonly` - AC_SUBST(ICU_CFLAGS) - AC_SUBST(ICU_LIBS) - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - fi fi if test \( "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" \) -a "x$have_icu" != "xtrue"; then AC_MSG_ERROR([icu support requested but icu-uc not found]) @@ -445,45 +417,6 @@ AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext) dnl =========================================================================== -AC_CACHE_CHECK([for Intel atomic primitives], hb_cv_have_intel_atomic_primitives, [ - hb_cv_have_intel_atomic_primitives=false - AC_TRY_LINK([ - void memory_barrier (void) { __sync_synchronize (); } - int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); } - int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); } - void mutex_unlock (int *m) { __sync_lock_release (m); } - ], [], hb_cv_have_intel_atomic_primitives=true - ) -]) -if $hb_cv_have_intel_atomic_primitives; then - AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1, [Have Intel __sync_* atomic primitives]) -fi - -dnl =========================================================================== - -AC_CACHE_CHECK([for Solaris atomic operations], hb_cv_have_solaris_atomic_ops, [ - hb_cv_have_solaris_atomic_ops=false - AC_TRY_LINK([ - #include - /* This requires Solaris Studio 12.2 or newer: */ - #include - void memory_barrier (void) { __machine_rw_barrier (); } - int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); } - void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); } - ], [], hb_cv_have_solaris_atomic_ops=true - ) -]) -if $hb_cv_have_solaris_atomic_ops; then - AC_DEFINE(HAVE_SOLARIS_ATOMIC_OPS, 1, [Have Solaris __machine_*_barrier and atomic_* operations]) -fi - -if test "$os_win32" = no && ! $have_pthread; then - AC_CHECK_HEADERS(sched.h) - AC_SEARCH_LIBS(sched_yield,rt,AC_DEFINE(HAVE_SCHED_YIELD, 1, [Have sched_yield])) -fi - -dnl =========================================================================== - AC_CONFIG_FILES([ Makefile src/Makefile @@ -499,6 +432,7 @@ test/shaping/data/in-house/Makefile test/shaping/data/text-rendering-tests/Makefile test/subset/Makefile test/subset/data/Makefile +test/subset/data/repack_tests/Makefile docs/Makefile docs/version.xml ]) @@ -510,6 +444,14 @@ echo "C++ compiler version:" $CXX --version echo +AC_MSG_NOTICE([ + +Autotools is no longer our supported build system for building the library +for *nix distributions, please migrate to meson. + +]) + + AC_MSG_NOTICE([ Build configuration: @@ -524,9 +466,9 @@ Font callbacks (the more the merrier): Tools used for command-line utilities: Cairo: ${have_cairo} - Fontconfig: ${have_fontconfig} + Chafa: ${have_chafa} -Additional shapers (the more the merrier): +Additional shapers: Graphite2: ${have_graphite2} Platform shapers (not normally needed): diff --git a/docs/HarfBuzz.png b/docs/HarfBuzz.png index 771d955d01fc9cfe4511107137237eab35763de2..c9d2e7b6f5b60373870e93464a8857ec96997672 100644 Binary files a/docs/HarfBuzz.png and b/docs/HarfBuzz.png differ diff --git a/docs/HarfBuzz.svg b/docs/HarfBuzz.svg index 4e2df254146496c8c09636aba2f6bb997ca43338..beb13addf359c41fb773e794302cba5815d25e02 100644 --- a/docs/HarfBuzz.svg +++ b/docs/HarfBuzz.svg @@ -1,277 +1,8 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/docs/Makefile.am b/docs/Makefile.am index f4bf2fdbcc27bbafb64ef1e17db73b1803f09630..5c03209a387809b71dec3589ee25d6b7006391fd 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -29,15 +29,12 @@ SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \ - --ignore-decorators="HB_EXTERN" + --ignore-decorators='HB_EXTERN|HB_DEPRECATED' # Header files or dirs to ignore when scanning. Use base file/dir names # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'` -if HAVE_GOBJECT -else IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h -endif # Extra options to supply to gtkdoc-mkdb. # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml @@ -83,6 +80,7 @@ content_files= \ usermanual-opentype-features.xml \ usermanual-clusters.xml \ usermanual-utilities.xml \ + usermanual-integration.xml \ version.xml # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded @@ -106,7 +104,7 @@ include $(top_srcdir)/gtk-doc.make # Other files to distribute # e.g. EXTRA_DIST += version.xml.in -EXTRA_DIST += version.xml.in +EXTRA_DIST += version.xml.in meson.build # Files not to distribute # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types diff --git a/docs/harfbuzz-docs.xml b/docs/harfbuzz-docs.xml index 433c2065914ab70d51a82467f17fbd569ea8e68b..7f97189a1b77acdcc9780f19f4585893c2e88712 100644 --- a/docs/harfbuzz-docs.xml +++ b/docs/harfbuzz-docs.xml @@ -11,8 +11,7 @@ HarfBuzz - HarfBuzz is an OpenType - text shaping engine. Using the HarfBuzz library allows + HarfBuzz is a text shaping library. Using the HarfBuzz library allows programs to convert a sequence of Unicode input into properly formatted and positioned glyph output—for any writing system and language. @@ -27,7 +26,7 @@ - + User's manual @@ -39,9 +38,10 @@ + - + This document is for HarfBuzz &version;. @@ -49,40 +49,9 @@ http://[SERVER]/libharfbuzz/.--> - - - - The current HarfBuzz codebase is versioned 2.x.x and is stable - and under active maintenance. This is what is used in latest - versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice, - XeTeX, Android, and KDE, among other places. - - - Prior to 2012, the original HarfBuzz codebase (which, these - days, is referred to as harfbuzz-old) was - derived from code in FreeType, Pango, and - Qt. - It is not actively developed or - maintained, and is extremely buggy. All users of harfbuzz-old - are encouraged to switch over to the new HarfBuzz as soon as possible. - - - To make this distinction clearer in discussions, the current - HarfBuzz codebase is sometimes referred to as - harfbuzz-ng. - - - For reference purposes, the harfbuzz-old source tree is archived - here. There - are no release tarballs of harfbuzz-old whatsoever. - - Reference manual - + Core API @@ -98,31 +67,34 @@ - + OpenType API + + - + Apple Advanced Typography API - + Integration API - + + + + The hb_uniscribe_font_get_hfont() function + also takes a hb_font_t font object, but it returns + an HFONT — a handle to the underlying logical + font — instead. + + + LOGFONTWs and HFONTs are both needed + by other Uniscribe functions. + + + As a final note, you may notice a reference to an optional + uniscribe shaper back-end in the section of the HarfBuzz manual. This + option is not a Uniscribe-integration facility. + + + Instead, it is a internal code path used in the + hb-shape command-line utility, which hands + shaping functionality over to Uniscribe entirely, when run on a + Windows system. That allows testing HarfBuzz's native output + against the Uniscribe engine, for tracking compatibility and + debugging. + + + Because this back-end is only used when testing HarfBuzz + functionality, it is disabled by default when building the + HarfBuzz binaries. + + + +
+ Core Text integration + + If your client program is running on macOS or iOS, HarfBuzz offers + an additional API that can help integrate with Apple's + Core Text engine and the underlying Core Graphics + framework. HarfBuzz does not attempt to offer the same + drop-in-replacement functionality for Core Text that it strives + for with Uniscribe on Windows, but you can still use HarfBuzz + to perform text shaping in native macOS and iOS applications. + + + Note, though, that if your interest is just in using fonts that + contain Apple Advanced Typography (AAT) features, then you do + not need to add Core Text integration. HarfBuzz natively + supports AAT features and will shape AAT fonts (on any platform) + automatically, without requiring additional work on your + part. This includes support for AAT-specific TrueType tables + such as mort, morx, and + kerx, which AAT fonts use instead of + GSUB and GPOS. + + + On a macOS or iOS system, the primary integration points offered + by HarfBuzz are for face objects and font objects. + + + The Apple APIs offer a pair of data structures that map well to + HarfBuzz's face and font objects. The Core Graphics API, which + is slightly lower-level than Core Text, provides + CGFontRef, which enables access to typeface + properties, but does not include size information. Core Text's + CTFontRef is analagous to a HarfBuzz font object, + with all of the properties required to render text at a specific + size and configuration. + Consequently, a HarfBuzz hb_font_t font object can + be hooked up to a Core Text CTFontRef, and a HarfBuzz + hb_face_t face object can be hooked up to a + CGFontRef. + + + You can create a hb_face_t from a + CGFontRef by using the + hb_coretext_face_create(). Subsequently, + you can retrieve the CGFontRef from a + hb_face_t with hb_coretext_face_get_cg_font(). + + + Likewise, you create a hb_font_t from a + CTFontRef by calling + hb_coretext_font_create(), and you can + fetch the associated CTFontRef from a + hb_font_t font object with + hb_coretext_face_get_ct_font(). + + + HarfBuzz also offers a hb_font_set_ptem() + that you an use to set the nominal point size on any + hb_font_t font object. Core Text uses this value to + implement optical scaling. + + + When integrating your client code with Core Text, it is + important to recognize that Core Text points + are not typographic points (standardized at 72 per inch) as the + term is used elsewhere in OpenType. Instead, Core Text points + are CSS points, which are standardized at 96 per inch. + + + HarfBuzz's font functions take this distinction into account, + but it can be an easy detail to miss in cross-platform + code. + + + As a final note, you may notice a reference to an optional + coretext shaper back-end in the section of the HarfBuzz manual. This + option is not a Core Text-integration facility. + + + Instead, it is a internal code path used in the + hb-shape command-line utility, which hands + shaping functionality over to Core Text entirely, when run on a + macOS system. That allows testing HarfBuzz's native output + against the Core Text engine, for tracking compatibility and debugging. + + + Because this back-end is only used when testing HarfBuzz + functionality, it is disabled by default when building the + HarfBuzz binaries. + +
+ +
+ ICU integration + + Although HarfBuzz includes its own Unicode-data functions, it + also provides integration APIs for using the International + Components for Unicode (ICU) library as a source of Unicode data + on any supported platform. + + + The principal integration point with ICU is the + hb_unicode_funcs_t Unicode-functions structure + attached to a buffer. This structure holds the virtual methods + used for retrieving Unicode character properties, such as + General Category, Script, Combining Class, decomposition + mappings, and mirroring information. + + + To use ICU in your client program, you need to call + hb_icu_get_unicode_funcs(), which creates a + Unicode-functions structure populated with the ICU function for + each included method. Subsequently, you can attach the + Unicode-functions structure to your buffer: + + + hb_unicode_funcs_t *icufunctions; + icufunctions = hb_icu_get_unicode_funcs(); + hb_buffer_set_unicode_funcs(buf, icufunctions); + + + and ICU will be used for Unicode-data access. + + + HarfBuzz also supplies a pair of functions + (hb_icu_script_from_script() and + hb_icu_script_to_script()) for converting + between ICU's and HarfBuzz's internal enumerations of Unicode + scripts. The hb_icu_script_from_script() + function converts from a HarfBuzz hb_script_t to an + ICU UScriptCode. The + hb_icu_script_to_script() function does the + reverse: converting from a UScriptCode identifier + to a hb_script_t. + + + By default, HarfBuzz's ICU support is built as a separate shared + library (libharfbuzz-icu.so) + when compiling HarfBuzz from source. This allows client programs + that do not need ICU to link against HarfBuzz without unnecessarily + adding ICU as a dependency. You can also build HarfBuzz with ICU + support built directly into the main HarfBuzz shared library + (libharfbuzz.so), + by specifying the --with-icu=builtin + compile-time option. + + +
+ +
+ Python bindings + + As noted in the section, + HarfBuzz uses a feature called GObject + Introspection (GI) to provide bindings for Python. + + + At compile time, the GI scanner analyzes the HarfBuzz C source + and builds metadata objects connecting the language bindings to + the C library. Your Python code can then use the HarfBuzz binary + through its Python interface. + + + HarfBuzz's Python bindings support Python 2 and Python 3. To use + them, you will need to have the pygobject + package installed. Then you should import + HarfBuzz from + gi.repository: + + + from gi.repository import HarfBuzz + + + and you can call HarfBuzz functions from Python. Sample code can + be found in the sample.py script in the + HarfBuzz src directory. + + + Do note, however, that the Python API is subject to change + without advance notice. GI allows the bindings to be + automatically updated, which is one of its advantages, but you + may need to update your Python code. + +
+ +
diff --git a/docs/usermanual-object-model.xml b/docs/usermanual-object-model.xml index f571c477fad02e72160d4768289285b239e5526c..23065bf761d577d4de8a12fb995641ccc9523367 100644 --- a/docs/usermanual-object-model.xml +++ b/docs/usermanual-object-model.xml @@ -232,7 +232,7 @@ different.
- Blobs are an abstraction desgined to negotiate lifecycle and + Blobs are an abstraction designed to negotiate lifecycle and permissions for raw pieces of data. For example, when you load the raw font data into memory and want to pass it to HarfBuzz, you do so in a hb_blob_t wrapper. @@ -244,7 +244,7 @@ malloc(), you would create the blob using - hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free) + hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, data, free) That way, HarfBuzz will call free() on the diff --git a/docs/usermanual-opentype-features.xml b/docs/usermanual-opentype-features.xml index 3eedab3d4add6c7f023e187a4e05430baef1a8a0..e9ea145344c9ef2c3d4eb467cd15b9a4ac230e8d 100644 --- a/docs/usermanual-opentype-features.xml +++ b/docs/usermanual-opentype-features.xml @@ -48,14 +48,14 @@ If a font has a GDEF table, then that is used for glyph classes; if not, HarfBuzz will fall back to Unicode - categorization by code point. If a font has an AAT "morx" table, + categorization by code point. If a font has an AAT morx table, then it is used for substitutions; if not, but there is a GSUB table, then the GSUB table is used. If the font has an AAT - "kerx" table, then it is used for positioning; if not, but + kerx table, then it is used for positioning; if not, but there is a GPOS table, then the GPOS table is used. If neither - table is found, but there is a "kern" table, then HarfBuzz will - use the "kern" table. If there is no "kerx", no GPOS, and no - "kern", HarfBuzz will fall back to positioning marks itself. + table is found, but there is a kern table, then HarfBuzz will + use the kern table. If there is no kerx, no GPOS, and no + kern, HarfBuzz will fall back to positioning marks itself. With a well-behaved OpenType font, you expect GDEF, GSUB, and @@ -139,7 +139,8 @@ Other features are more generic and can apply to several (or any) script, and shaping engines are expected to implement them. By default, HarfBuzz activates several of these features - on every text run. They include ccmp, + on every text run. They include abvm, + blwm, ccmp, locl, mark, mkmk, and rlig. @@ -147,9 +148,40 @@ In addition, if the text direction is horizontal, HarfBuzz also applies the calt, clig, curs, - kern, liga, - rclt, and frac features. + dist, kern, + liga and rclt, features. + + Additionally, when HarfBuzz encounters a fraction slash + (U+2044), it looks backward and forward for decimal + digits (Unicode General Category = Nd), and enables features + numr on the sequence before the fraction slash, + dnom on the sequence after the fraction slash, + and frac on the whole sequence including the fraction + slash. + + + Some script-specific shaping models + (see ) disable some of the + features listed above: + + + + + Hangul: calt + + + + + Indic: liga + + + + + Khmer: liga + + + If the text direction is vertical, HarfBuzz applies the vert feature by default. diff --git a/docs/usermanual-utilities.xml b/docs/usermanual-utilities.xml index 1c5370c11e0280c186144fca62e46d0fdda2b947..0208dbf70832c39a6436f1262ed52b3dde43ff67 100644 --- a/docs/usermanual-utilities.xml +++ b/docs/usermanual-utilities.xml @@ -10,16 +10,15 @@ HarfBuzz includes several auxiliary components in addition to the main APIs. These include a set of command-line tools, a set of lower-level APIs for common data types that may be of interest to - client programs, and an embedded library for working with - Unicode Character Database (UCD) data. + client programs.
Command-line tools HarfBuzz include three command-line tools: - hb-shape, hb-view, and - hb-subset. They can be used to examine + hb-shape, hb-view, and + hb-subset. They can be used to examine HarfBuzz's functionality, debug font binaries, or explore the various shaping models and features from a terminal. @@ -27,12 +26,12 @@
hb-shape - hb-shape allows you to run HarfBuzz's + hb-shape allows you to run HarfBuzz's hb_shape() function on an input string and to examine the outcome, in human-readable form, as terminal - output. hb-shape does + output. hb-shape does not render the results of the shaping call - into rendered text (you can use hb-view, below, for + into rendered text (you can use hb-view, below, for that). Instead, it prints out the final glyph indices and positions, taking all shaping operations into account, as if the input string were a HarfBuzz input buffer. @@ -80,10 +79,10 @@
hb-view - hb-view allows you to + hb-view allows you to see the shaped output of an input string in rendered - form. Like hb-shape, - hb-view takes a font file and a text string + form. Like hb-shape, + hb-view takes a font file and a text string as its arguments: @@ -92,7 +91,7 @@ yourinputtext - By default, hb-view renders the shaped + By default, hb-view renders the shaped text in ASCII block-character images as terminal output. By appending the --output-file=filename @@ -100,7 +99,7 @@ (among other formats). - As with hb-shape, a lengthy set of options + As with hb-shape, a lengthy set of options is available, with which you can enable or disable specific font features, set variation-font axis values, alter the language, script, direction, and clustering settings @@ -114,10 +113,10 @@ with - In general, hb-view is a quick way to + In general, hb-view is a quick way to verify that the output of HarfBuzz's shaping operation looks correct for a given text-and-font combination, but you may - want to use hb-shape to figure out exactly + want to use hb-shape to figure out exactly why something does not appear as expected.
@@ -125,13 +124,13 @@
hb-subset - hb-subset allows you + hb-subset allows you to generate a subset of a given font, with a limited set of supported characters, features, and variation settings. By default, you provide an input font and an input text string - as the arguments to hb-subset, and it will + as the arguments to hb-subset, and it will generate a font that covers the input text exactly like the input font does, but includes no other characters or features. @@ -216,29 +215,4 @@
-
- UCDN - - HarfBuzz includes a copy of the UCDN (Unicode - Database and Normalization) library, which provides functions - for accessing basic Unicode character properties, performing - canonical composition, and performing both canonical and - compatibility decomposition. - - - Currently, UCDN supports direct queries for several more character - properties than HarfBuzz's built-in set of Unicode functions - does, such as the BiDirectional Class, East Asian Width, Paired - Bracket and Resolved Linebreak properties. If you need to access - more properties than HarfBuzz's internal implementation - provides, using the built-in UCDN functions may be a useful solution. - - - The built-in UCDN functions are compiled by default when - building HarfBuzz from source, but this can be disabled with a - compile-time switch. - -
- diff --git a/docs/usermanual-what-is-harfbuzz.xml b/docs/usermanual-what-is-harfbuzz.xml index 3513fb285e165520b738e5dd4f7ba882f4ee7a02..4534783c240ce29f0d5d7bcbf4cc0082b010c7c3 100644 --- a/docs/usermanual-what-is-harfbuzz.xml +++ b/docs/usermanual-what-is-harfbuzz.xml @@ -226,7 +226,7 @@
-
+
What does HarfBuzz do? HarfBuzz provides text shaping through a cross-platform diff --git a/harfbuzz.zip b/harfbuzz.zip new file mode 100644 index 0000000000000000000000000000000000000000..3ab767fb275e65ea59dd72ea9a32cfa89e8f38ea Binary files /dev/null and b/harfbuzz.zip differ diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 5032bba8091d5d1074f4509b4c47b38a66389c6b..8b6df5a5ded5bceb4cd0c513b2288e6aac2dd468 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -422,7 +422,7 @@ namespace cxx11 } - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..4d5cd0ca51dff782b6166c2fdb1bbcb99de41377 --- /dev/null +++ b/meson.build @@ -0,0 +1,408 @@ +project('harfbuzz', 'c', 'cpp', + meson_version: '>= 0.47.0', + version: '2.8.1', + default_options: [ + 'cpp_eh=none', # Just to support msvc, we are passing -fno-rtti also anyway + 'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway + 'cpp_std=c++11', + 'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548 + ], +) + +hb_version_arr = meson.project_version().split('.') +hb_version_major = hb_version_arr[0].to_int() +hb_version_minor = hb_version_arr[1].to_int() +hb_version_micro = hb_version_arr[2].to_int() + +# libtool versioning +hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro +hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int) + +pkgmod = import('pkgconfig') +cpp = meson.get_compiler('cpp') +null_dep = dependency('', required: false) + +if cpp.get_id() == 'msvc' + # Ignore several spurious warnings for things HarfBuzz does very commonly. + # If a warning is completely useless and spammy, use '/wdXXXX' to suppress it + # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once + # NOTE: Only add warnings here if you are sure they're spurious + msvc_args = [ + '/wd4018', # implicit signed/unsigned conversion + '/wd4146', # unary minus on unsigned (beware INT_MIN) + '/wd4244', # lossy type conversion (e.g. double -> int) + '/wd4305', # truncating type conversion (e.g. double -> float) + cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 + ] + add_project_arguments(msvc_args, language: ['c', 'cpp']) + # Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW + # noseh_link_args = ['/SAFESEH:NO'] +endif + +add_project_link_arguments(cpp.get_supported_link_arguments([ + '-Bsymbolic-functions' +]), language: 'c') + +add_project_arguments(cpp.get_supported_arguments([ + '-fno-exceptions', + '-fno-rtti', + '-fno-threadsafe-statics', + '-fvisibility-inlines-hidden', +]), language: 'cpp') + +if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') != 1 + if cpp.has_argument('-mstructure-size-boundary=8') + add_project_arguments('-mstructure-size-boundary=8', language: 'cpp') + endif +endif + +check_headers = [ + ['unistd.h'], + ['sys/mman.h'], + ['stdbool.h'], +] + +check_funcs = [ + ['atexit'], + ['mprotect'], + ['sysconf'], + ['getpagesize'], + ['mmap'], + ['isatty'], +] + +m_dep = cpp.find_library('m', required: false) + +freetype_dep = null_dep +if not get_option('freetype').disabled() + freetype_dep = dependency('freetype2', required: false) + + if (not freetype_dep.found() and + cpp.get_id() == 'msvc' and + cpp.has_header('ft2build.h')) + freetype_dep = cpp.find_library('freetype', required: false) + endif + + if not freetype_dep.found() + # https://github.com/harfbuzz/harfbuzz/pull/2498 + freetype_dep = dependency('freetype2', required: get_option('freetype'), + fallback: ['freetype2', 'freetype_dep'], + default_options: ['harfbuzz=disabled']) + endif +endif + +glib_dep = dependency('glib-2.0', required: get_option('glib'), + fallback: ['glib', 'libglib_dep']) +gobject_dep = dependency('gobject-2.0', required: get_option('gobject'), + fallback: ['glib', 'libgobject_dep']) +graphite2_dep = dependency('graphite2', required: get_option('graphite')) + +icu_dep = null_dep +if not get_option('icu').disabled() + icu_dep = dependency('icu-uc', required: false) + + if (not icu_dep.found() and + cpp.get_id() == 'msvc' and + cpp.has_header('unicode/uchar.h') and + cpp.has_header('unicode/unorm2.h') and + cpp.has_header('unicode/ustring.h') and + cpp.has_header('unicode/utf16.h') and + cpp.has_header('unicode/uversion.h') and + cpp.has_header('unicode/uscript.h')) + if get_option('buildtype') == 'debug' + icu_dep = cpp.find_library('icuucd', required: false) + else + icu_dep = cpp.find_library('icuuc', required: false) + endif + endif + + if not icu_dep.found() + icu_dep = dependency('icu-uc', required: get_option('icu')) + endif +endif + +cairo_dep = null_dep +cairo_ft_dep = null_dep +if not get_option('cairo').disabled() + cairo_dep = dependency('cairo', required: false) + cairo_ft_dep = dependency('cairo-ft', required: false) + + if (not cairo_dep.found() and + cpp.get_id() == 'msvc' and + cpp.has_header('cairo.h')) + cairo_dep = cpp.find_library('cairo', required: false) + if cairo_dep.found() and cpp.has_function('cairo_ft_font_face_create_for_ft_face', + prefix: '#include ', + dependencies: cairo_dep) + cairo_ft_dep = cairo_dep + endif + endif + + if not cairo_dep.found() + # Requires Meson 0.54.0 to use cairo subproject + if meson.version().version_compare('>=0.54.0') + # Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback + # dependency cycle here because we have configured freetype2 above with + # harfbuzz support disabled, so when cairo will lookup freetype2 dependency + # it will be forced to use that one. + cairo_dep = dependency('cairo', fallback: 'cairo', required: get_option('cairo')) + cairo_ft_dep = dependency('cairo-ft', fallback: 'cairo', required: get_option('cairo')) + elif get_option('cairo').enabled() + error('cairo feature is enabled but it cannot be found on the system and ' + + 'meson>=0.54.0 is required to build it as subproject') + endif + endif +endif + +chafa_dep = dependency('chafa', version: '>= 1.6.0', required: get_option('chafa')) + +conf = configuration_data() +incconfig = include_directories('.') + +add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp']) + +warn_cflags = [ + '-Wno-non-virtual-dtor', +] + +cpp_args = cpp.get_supported_arguments(warn_cflags) + +if glib_dep.found() + conf.set('HAVE_GLIB', 1) +endif + +if gobject_dep.found() + conf.set('HAVE_GOBJECT', 1) +endif + +if cairo_dep.found() + conf.set('HAVE_CAIRO', 1) +endif + +if cairo_ft_dep.found() + conf.set('HAVE_CAIRO_FT', 1) +endif + +if chafa_dep.found() + conf.set('HAVE_CHAFA', 1) +endif + +if graphite2_dep.found() + conf.set('HAVE_GRAPHITE2', 1) +endif + +if icu_dep.found() + conf.set('HAVE_ICU', 1) +endif + +if get_option('icu_builtin') + conf.set('HAVE_ICU_BUILTIN', 1) +endif + +if get_option('experimental_api') + conf.set('HB_EXPERIMENTAL_API', 1) +endif + +if freetype_dep.found() + conf.set('HAVE_FREETYPE', 1) + check_freetype_funcs = [ + ['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}], + ['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}], + ['FT_Done_MM_Var', {'deps': freetype_dep}], + ] + + if freetype_dep.type_name() == 'internal' + foreach func: check_freetype_funcs + name = func[0] + conf.set('HAVE_@0@'.format(name.to_upper()), 1) + endforeach + else + check_funcs += check_freetype_funcs + endif +endif + +gdi_uniscribe_deps = [] +# GDI (Uniscribe) (Windows) +if host_machine.system() == 'windows' and not get_option('gdi').disabled() + if (get_option('directwrite').enabled() and + not (cpp.has_header('usp10.h') and cpp.has_header('windows.h'))) + error('GDI/Uniscribe was enabled explicitly, but required headers are missing.') + endif + + gdi_deps_found = true + foreach usplib : ['usp10', 'gdi32', 'rpcrt4'] + dep = cpp.find_library(usplib, required: get_option('gdi')) + gdi_deps_found = gdi_deps_found and dep.found() + gdi_uniscribe_deps += dep + endforeach + + if gdi_deps_found + conf.set('HAVE_UNISCRIBE', 1) + conf.set('HAVE_GDI', 1) + endif +endif + +# DirectWrite (Windows) +directwrite_dep = null_dep +if host_machine.system() == 'windows' and not get_option('directwrite').disabled() + if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h') + error('DirectWrite was enabled explicitly, but required header is missing.') + endif + + directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite')) + + if directwrite_dep.found() + conf.set('HAVE_DIRECTWRITE', 1) + endif +endif + +# CoreText (macOS) +coretext_deps = [] +if host_machine.system() == 'darwin' and not get_option('coretext').disabled() + app_services_dep = dependency('appleframeworks', modules: ['ApplicationServices'], required: false) + if cpp.has_type('CTFontRef', prefix: '#include ', dependencies: app_services_dep) + coretext_deps += [app_services_dep] + conf.set('HAVE_CORETEXT', 1) + # On iOS CoreText and CoreGraphics are stand-alone frameworks + # Check for a different symbol to avoid getting cached result + else + coretext_dep = dependency('appleframeworks', modules: ['CoreText'], required: false) + coregraphics_dep = dependency('appleframeworks', modules: ['CoreGraphics'], required: false) + corefoundation_dep = dependency('appleframeworks', modules: ['CoreFoundation'], required: false) + if cpp.has_type('CTRunRef', prefix: '#include ', dependencies: [coretext_dep, coregraphics_dep, corefoundation_dep]) + coretext_deps += [coretext_dep, coregraphics_dep, corefoundation_dep] + conf.set('HAVE_CORETEXT', 1) + elif get_option('coretext').enabled() + error('CoreText was enabled explicitly, but required headers or frameworks are missing.') + endif + endif +endif + +# threads +thread_dep = null_dep +if host_machine.system() != 'windows' + thread_dep = dependency('threads', required: false) + + if thread_dep.found() + conf.set('HAVE_PTHREAD', 1) + endif +endif + +conf.set_quoted('PACKAGE_NAME', 'HarfBuzz') +conf.set_quoted('PACKAGE_VERSION', meson.project_version()) + +foreach check : check_headers + name = check[0] + + if cpp.has_header(name) + conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1) + endif +endforeach + +harfbuzz_extra_deps = [] +foreach check : check_funcs + name = check[0] + opts = check.get(1, {}) + link_withs = opts.get('link_with', []) + check_deps = opts.get('deps', []) + extra_deps = [] + found = true + + # First try without linking + found = cpp.has_function(name, dependencies: check_deps) + + if not found and link_withs.length() > 0 + found = true + + foreach link_with : link_withs + dep = cpp.find_library(link_with, required: false) + if dep.found() + extra_deps += dep + else + found = false + endif + endforeach + + if found + found = cpp.has_function(name, dependencies: check_deps + extra_deps) + endif + endif + + if found + harfbuzz_extra_deps += extra_deps + conf.set('HAVE_@0@'.format(name.to_upper()), 1) + endif +endforeach + +subdir('src') +subdir('util') + +if not get_option('tests').disabled() + subdir('test') +endif + +if not get_option('benchmark').disabled() + subdir('perf') +endif + +if not get_option('docs').disabled() + subdir('docs') +endif + +configure_file(output: 'config.h', configuration: conf) + +build_summary = { + 'Directories': + {'prefix': get_option('prefix'), + 'bindir': get_option('bindir'), + 'libdir': get_option('libdir'), + 'includedir': get_option('includedir'), + 'datadir': get_option('datadir'), + }, + 'Unicode callbacks (you want at least one)': + {'Builtin': true, + 'Glib': conf.get('HAVE_GLIB', 0) == 1, + 'ICU': conf.get('HAVE_ICU', 0) == 1, + }, + 'Font callbacks (the more the merrier)': + {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1, + }, + 'Dependencies used for command-line utilities': + {'Cairo': conf.get('HAVE_CAIRO', 0) == 1, + 'Chafa': conf.get('HAVE_CHAFA', 0) == 1, + }, + 'Additional shapers': + {'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1, + }, + 'Platform shapers (not normally needed)': + {'CoreText': conf.get('HAVE_CORETEXT', 0) == 1, + 'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1, + 'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1), + }, + 'Other features': + {'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1, + 'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1, + 'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1, + 'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1, + }, + 'Testing': + {'Tests': get_option('tests').enabled(), + 'Benchmark': get_option('benchmark').enabled(), + }, +} +if meson.version().version_compare('>=0.53') + foreach section_title, section : build_summary + summary(section, bool_yn: true, section: section_title) + endforeach +else + summary = [''] + foreach section_title, section : build_summary + summary += ' @0@:'.format(section_title) + foreach feature, value : section + summary += ' @0@:'.format(feature) + summary += ' @0@'.format(value) + endforeach + summary += '' + endforeach + message('\n'.join(summary)) +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000000000000000000000000000000000..602d053b77bdb882003faf03a59d67718d938457 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,38 @@ +# HarfBuzz feature options +option('glib', type: 'feature', value: 'auto', + description: 'Enable GLib unicode functions') +option('gobject', type: 'feature', value: 'auto', + description: 'Enable GObject bindings') +option('cairo', type: 'feature', value: 'auto', + description: 'Use Cairo graphics library') +option('chafa', type: 'feature', value: 'auto', + description: 'Use Chafa terminal graphics library') +option('icu', type: 'feature', value: 'auto', + description: 'Enable ICU library unicode functions') +option('graphite', type: 'feature', value: 'disabled', + description: 'Enable Graphite2 complementary shaper') +option('freetype', type: 'feature', value: 'auto', + description: 'Enable freetype interop helpers') +option('gdi', type: 'feature', value: 'disabled', + description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)') +option('directwrite', type: 'feature', value: 'disabled', + description: 'Enable DirectWrite shaper backend on Windows (experimental)') +option('coretext', type: 'feature', value: 'disabled', + description: 'Enable CoreText shaper backend on macOS') + +# Common feature options +option('tests', type: 'feature', value: 'enabled', yield: true, + description: 'Enable or disable unit tests') +option('introspection', type: 'feature', value: 'auto', yield: true, + description: 'Generate gobject-introspection bindings (.gir/.typelib files)') +option('docs', type: 'feature', value: 'auto', yield: true, + description: 'Generate documentation with gtk-doc') + +option('benchmark', type: 'feature', value: 'disabled', + description: 'Enable benchmark tests') +option('icu_builtin', type: 'boolean', value: false, + description: 'Don\'t separate ICU support as harfbuzz-icu module') +option('experimental_api', type: 'boolean', value: false, + description: 'Enable experimental APIs') +option('fuzzer_ldflags', type: 'string', + description: 'Extra LDFLAGS used during linking of fuzzing binaries') diff --git a/mingw-ldd.py b/mingw-ldd.py deleted file mode 100755 index 1d659efa46db9da4ff9a922e9bc0783a2ba40a14..0000000000000000000000000000000000000000 --- a/mingw-ldd.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python - -# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py -# Modified to point to right prefix location on Fedora. - -# WTFPL - Do What the Fuck You Want to Public License -from __future__ import print_function -import pefile -import os -import sys - - -def get_dependency(filename): - deps = [] - pe = pefile.PE(filename) - for imp in pe.DIRECTORY_ENTRY_IMPORT: - deps.append(imp.dll.decode()) - return deps - - -def dep_tree(root, prefix=None): - if not prefix: - arch = get_arch(root) - #print('Arch =', arch) - prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin' - #print('Using default prefix', prefix) - dep_dlls = dict() - - def dep_tree_impl(root, prefix): - for dll in get_dependency(root): - if dll in dep_dlls: - continue - full_path = os.path.join(prefix, dll) - if os.path.exists(full_path): - dep_dlls[dll] = full_path - dep_tree_impl(full_path, prefix=prefix) - else: - dep_dlls[dll] = 'not found' - - dep_tree_impl(root, prefix) - return (dep_dlls) - - -def get_arch(filename): - type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686', - pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'} - pe = pefile.PE(filename) - try: - return type2arch[pe.PE_TYPE] - except KeyError: - sys.stderr.write('Error: unknown architecture') - sys.exit(1) - -if __name__ == '__main__': - filename = sys.argv[1] - for dll, full_path in dep_tree(filename).items(): - print(' ' * 7, dll, '=>', full_path) - diff --git a/mingw32.sh b/mingw32.sh deleted file mode 100755 index 77edffa98ce877a5e0686e1330332e21bafa977f..0000000000000000000000000000000000000000 --- a/mingw32.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec "$(dirname "$0")"/mingw-configure.sh i686 "$@" diff --git a/mingw64.sh b/mingw64.sh deleted file mode 100755 index 28724a48ed32d382c5e6dfe56eda174e5b5d938d..0000000000000000000000000000000000000000 --- a/mingw64.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@" diff --git a/perf/fonts/Amiri-Regular.ttf b/perf/fonts/Amiri-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e328e0630a2e348db268f285eae5b4f6db83bcbc Binary files /dev/null and b/perf/fonts/Amiri-Regular.ttf differ diff --git a/perf/fonts/NotoNastaliqUrdu-Regular.ttf b/perf/fonts/NotoNastaliqUrdu-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..891f633d802bbece8eb3a701a62bdcb69c45b74c Binary files /dev/null and b/perf/fonts/NotoNastaliqUrdu-Regular.ttf differ diff --git a/perf/fonts/NotoSansDevanagari-Regular.ttf b/perf/fonts/NotoSansDevanagari-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a9884a538942e61b27bb632b292011ad0f621e06 Binary files /dev/null and b/perf/fonts/NotoSansDevanagari-Regular.ttf differ diff --git a/perf/fonts/Roboto-Regular.ttf b/perf/fonts/Roboto-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..500b1045b0c94d83d2e6798aaf1faa55a2dab6fc Binary files /dev/null and b/perf/fonts/Roboto-Regular.ttf differ diff --git a/perf/meson.build b/perf/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..c3b0e3e4a0fe5c83e88b0357d8c71700c2807b42 --- /dev/null +++ b/perf/meson.build @@ -0,0 +1,27 @@ +google_benchmark = subproject('google-benchmark') +google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep') + +ttf_parser_dep = null_dep +if get_option('experimental_api') and add_languages('rust', required: false, native: true) + ttf_parser_dep = subproject('ttf-parser').get_variable('ttf_parser_dep') +endif + +if ttf_parser_dep.found() + benchmark_cpp_args = ['-DHAVE_TTFPARSER'] +else + benchmark_cpp_args = [] +endif + +benchmark('perf', executable('perf', 'perf.cc', + dependencies: [ + google_benchmark_dep, freetype_dep, + + # the last two, thread and dl, aren't nice as ttf-parser isn't no_std yet + # https://github.com/RazrFalcon/ttf-parser/issues/29 + ttf_parser_dep, thread_dep, cpp.find_library('dl'), + ], + cpp_args: benchmark_cpp_args, + include_directories: [incconfig, incsrc], + link_with: [libharfbuzz], + install: false, +), workdir: join_paths(meson.current_source_dir(), '..'), timeout: 100) diff --git a/perf/perf-draw.hh b/perf/perf-draw.hh new file mode 100644 index 0000000000000000000000000000000000000000..efca854a29caaa76baea955e041f929de0282424 --- /dev/null +++ b/perf/perf-draw.hh @@ -0,0 +1,177 @@ +#include "benchmark/benchmark.h" + +#include "hb.h" +#include "hb-ot.h" +#include "hb-ft.h" +#include FT_OUTLINE_H + +#ifdef HAVE_TTFPARSER +#include "ttfparser.h" +#endif + +#define HB_UNUSED __attribute__((unused)) + +static void +_hb_move_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} + +static void +_hb_line_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} + +static void +_hb_quadratic_to (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED, + hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +_hb_cubic_to (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED, + hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED, + hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +_hb_close_path (void *user_data HB_UNUSED) {} + +static void +_ft_move_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {} + +static void +_ft_line_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {} + +static void +_ft_conic_to (const FT_Vector* control HB_UNUSED, const FT_Vector* to HB_UNUSED, + void* user HB_UNUSED) {} + +static void +_ft_cubic_to (const FT_Vector* control1 HB_UNUSED, const FT_Vector* control2 HB_UNUSED, + const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {} + +#ifdef HAVE_TTFPARSER +static void _tp_move_to (float x HB_UNUSED, float y HB_UNUSED, void *data HB_UNUSED) {} +static void _tp_line_to (float x, float y, void *data) {} +static void _tp_quad_to (float x1, float y1, float x, float y, void *data) {} +static void _tp_curve_to (float x1, float y1, float x2, float y2, float x, float y, void *data) {} +static void _tp_close_path (void *data) {} +#endif + +static void draw (benchmark::State &state, const char *font_path, bool is_var, backend_t backend) +{ + hb_font_t *font; + unsigned num_glyphs; + { + hb_blob_t *blob = hb_blob_create_from_file (font_path); + assert (hb_blob_get_length (blob)); + hb_face_t *face = hb_face_create (blob, 0); + hb_blob_destroy (blob); + num_glyphs = hb_face_get_glyph_count (face); + font = hb_font_create (face); + hb_face_destroy (face); + } + + if (backend == HARFBUZZ) + { + if (is_var) + { + hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500}; + hb_font_set_variations (font, &wght, 1); + } + hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create (); + hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to); + hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to); + hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to); + hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to); + hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path); + + for (auto _ : state) + for (unsigned gid = 0; gid < num_glyphs; ++gid) + hb_font_draw_glyph (font, gid, draw_funcs, nullptr); + + hb_draw_funcs_destroy (draw_funcs); + } + else if (backend == FREETYPE) + { + if (is_var) + { + hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500}; + hb_font_set_variations (font, &wght, 1); + } + hb_ft_font_set_funcs (font); + FT_Face ft_face = hb_ft_font_get_face (font); + hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE); + + FT_Outline_Funcs draw_funcs; + draw_funcs.move_to = (FT_Outline_MoveToFunc) _ft_move_to; + draw_funcs.line_to = (FT_Outline_LineToFunc) _ft_line_to; + draw_funcs.conic_to = (FT_Outline_ConicToFunc) _ft_conic_to; + draw_funcs.cubic_to = (FT_Outline_CubicToFunc) _ft_cubic_to; + draw_funcs.shift = 0; + draw_funcs.delta = 0; + + for (auto _ : state) + for (unsigned gid = 0; gid < num_glyphs; ++gid) + { + FT_Load_Glyph (ft_face, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE); + FT_Outline_Decompose (&ft_face->glyph->outline, &draw_funcs, nullptr); + } + } + else if (backend == TTF_PARSER) + { +#ifdef HAVE_TTFPARSER + ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ()); + hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font)); + assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font)); + if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500); + + ttfp_outline_builder builder; + builder.move_to = _tp_move_to; + builder.line_to = _tp_line_to; + builder.quad_to = _tp_quad_to; + builder.curve_to = _tp_curve_to; + builder.close_path = _tp_close_path; + + ttfp_rect bbox; + for (auto _ : state) + for (unsigned gid = 0; gid < num_glyphs; ++gid) + ttfp_outline_glyph (tp_font, builder, &builder, gid, &bbox); + + hb_blob_destroy (blob); + free (tp_font); +#endif + } + else abort (); + + hb_font_destroy (font); +} + +#define FONT_BASE_PATH "test/subset/data/fonts/" + +BENCHMARK_CAPTURE (draw, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ); +BENCHMARK_CAPTURE (draw, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE); +BENCHMARK_CAPTURE (draw, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ); +BENCHMARK_CAPTURE (draw, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE); +BENCHMARK_CAPTURE (draw, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ); +BENCHMARK_CAPTURE (draw, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE); +BENCHMARK_CAPTURE (draw, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ); +BENCHMARK_CAPTURE (draw, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE); +BENCHMARK_CAPTURE (draw, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ); +BENCHMARK_CAPTURE (draw, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE); +BENCHMARK_CAPTURE (draw, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ); +BENCHMARK_CAPTURE (draw, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE); +BENCHMARK_CAPTURE (draw, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ); +BENCHMARK_CAPTURE (draw, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE); +BENCHMARK_CAPTURE (draw, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER); + +BENCHMARK_CAPTURE (draw, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ); +BENCHMARK_CAPTURE (draw, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE); +BENCHMARK_CAPTURE (draw, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER); diff --git a/perf/perf-extents.hh b/perf/perf-extents.hh new file mode 100644 index 0000000000000000000000000000000000000000..836fefe8f11139f42923d6e8e3001afa1af147f0 --- /dev/null +++ b/perf/perf-extents.hh @@ -0,0 +1,98 @@ +#include "benchmark/benchmark.h" + +#include "hb.h" +#include "hb-ft.h" +#include "hb-ot.h" + +#ifdef HAVE_TTFPARSER +#include "ttfparser.h" +#endif + +static void extents (benchmark::State &state, const char *font_path, bool is_var, backend_t backend) +{ + hb_font_t *font; + unsigned num_glyphs; + { + hb_blob_t *blob = hb_blob_create_from_file (font_path); + assert (hb_blob_get_length (blob)); + hb_face_t *face = hb_face_create (blob, 0); + hb_blob_destroy (blob); + num_glyphs = hb_face_get_glyph_count (face); + font = hb_font_create (face); + hb_face_destroy (face); + } + + if (is_var) + { + hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500}; + hb_font_set_variations (font, &wght, 1); + } + + if (backend == HARFBUZZ || backend == FREETYPE) + { + if (backend == FREETYPE) + { + hb_ft_font_set_funcs (font); + hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE); + } + + hb_glyph_extents_t extents; + for (auto _ : state) + for (unsigned gid = 0; gid < num_glyphs; ++gid) + hb_font_get_glyph_extents (font, gid, &extents); + } + else if (backend == TTF_PARSER) + { +#ifdef HAVE_TTFPARSER + ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ()); + hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font)); + assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font)); + if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500); + + ttfp_rect bbox; + for (auto _ : state) + for (unsigned gid = 0; gid < num_glyphs; ++gid) + ttfp_get_glyph_bbox(tp_font, gid, &bbox); + + hb_blob_destroy (blob); + free (tp_font); +#endif + } + + hb_font_destroy (font); +} + +#define FONT_BASE_PATH "test/subset/data/fonts/" + +BENCHMARK_CAPTURE (extents, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ); +BENCHMARK_CAPTURE (extents, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE); +BENCHMARK_CAPTURE (extents, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ); +BENCHMARK_CAPTURE (extents, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE); +BENCHMARK_CAPTURE (extents, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ); +BENCHMARK_CAPTURE (extents, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE); +BENCHMARK_CAPTURE (extents, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ); +BENCHMARK_CAPTURE (extents, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE); +BENCHMARK_CAPTURE (extents, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ); +BENCHMARK_CAPTURE (extents, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE); +BENCHMARK_CAPTURE (extents, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ); +BENCHMARK_CAPTURE (extents, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE); +BENCHMARK_CAPTURE (extents, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ); +BENCHMARK_CAPTURE (extents, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE); +BENCHMARK_CAPTURE (extents, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER); + +BENCHMARK_CAPTURE (extents, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ); +BENCHMARK_CAPTURE (extents, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE); +BENCHMARK_CAPTURE (extents, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER); + diff --git a/perf/perf-shaping.hh b/perf/perf-shaping.hh new file mode 100644 index 0000000000000000000000000000000000000000..73efd0a7eb378194386a580021c650bf33cdaec2 --- /dev/null +++ b/perf/perf-shaping.hh @@ -0,0 +1,65 @@ +#include "benchmark/benchmark.h" + +#include "hb.h" + +static void shape (benchmark::State &state, const char *text_path, + hb_direction_t direction, hb_script_t script, + const char *font_path) +{ + hb_font_t *font; + { + hb_blob_t *blob = hb_blob_create_from_file (font_path); + assert (hb_blob_get_length (blob)); + hb_face_t *face = hb_face_create (blob, 0); + hb_blob_destroy (blob); + font = hb_font_create (face); + hb_face_destroy (face); + } + + hb_blob_t *text_blob = hb_blob_create_from_file (text_path); + unsigned text_length; + const char *text = hb_blob_get_data (text_blob, &text_length); + assert (text_length); + + hb_buffer_t *buf = hb_buffer_create (); + for (auto _ : state) + { + hb_buffer_add_utf8 (buf, text, text_length, 0, -1); + hb_buffer_set_direction (buf, direction); + hb_buffer_set_script (buf, script); + hb_shape (font, buf, nullptr, 0); + hb_buffer_clear_contents (buf); + } + hb_buffer_destroy (buf); + + hb_blob_destroy (text_blob); + hb_font_destroy (font); +} + +BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - Amiri, + "perf/texts/fa-thelittleprince.txt", + HB_DIRECTION_RTL, HB_SCRIPT_ARABIC, + "perf/fonts/Amiri-Regular.ttf"); +BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - NotoNastaliqUrdu, + "perf/texts/fa-thelittleprince.txt", + HB_DIRECTION_RTL, HB_SCRIPT_ARABIC, + "perf/fonts/NotoNastaliqUrdu-Regular.ttf"); + +BENCHMARK_CAPTURE (shape, fa-monologue.txt - Amiri, + "perf/texts/fa-monologue.txt", + HB_DIRECTION_RTL, HB_SCRIPT_ARABIC, + "perf/fonts/Amiri-Regular.ttf"); +BENCHMARK_CAPTURE (shape, fa-monologue.txt - NotoNastaliqUrdu, + "perf/texts/fa-monologue.txt", + HB_DIRECTION_RTL, HB_SCRIPT_ARABIC, + "perf/fonts/NotoNastaliqUrdu-Regular.ttf"); + +BENCHMARK_CAPTURE (shape, en-thelittleprince.txt - Roboto, + "perf/texts/en-thelittleprince.txt", + HB_DIRECTION_LTR, HB_SCRIPT_LATIN, + "perf/fonts/Roboto-Regular.ttf"); + +BENCHMARK_CAPTURE (shape, en-words.txt - Roboto, + "perf/texts/en-words.txt", + HB_DIRECTION_LTR, HB_SCRIPT_LATIN, + "perf/fonts/Roboto-Regular.ttf"); diff --git a/perf/perf.cc b/perf/perf.cc new file mode 100644 index 0000000000000000000000000000000000000000..a364b910b397df37b143d04ab22396db51296adc --- /dev/null +++ b/perf/perf.cc @@ -0,0 +1,16 @@ +#include "benchmark/benchmark.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "perf-shaping.hh" +#ifdef HAVE_FREETYPE +enum backend_t { HARFBUZZ, FREETYPE, TTF_PARSER }; +#include "perf-extents.hh" +#ifdef HB_EXPERIMENTAL_API +#include "perf-draw.hh" +#endif +#endif + +BENCHMARK_MAIN (); diff --git a/perf/run.sh b/perf/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..c7dc6e0c2417bcbae261083044bc09c09f7293af --- /dev/null +++ b/perf/run.sh @@ -0,0 +1,25 @@ +#!/bin/bash +CXX=clang++ +FONT=fonts/NotoNastaliqUrdu-Regular.ttf +TEXT=texts/fa-monologue.txt + +$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \ + -lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \ + -I../src $FLAGS $SOURCES \ + -DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \ + -DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \ + -o hb-shape -g -O2 # -O3 \ + #-march=native -mtune=native \ + #-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \ + #-Rpass-analysis=loop-vectorize -fsave-optimization-record + +# -march=native: enable all vector instructions current CPU can offer +# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics + +#sudo rm capture.syscap > /dev/null +#sysprof-cli -c "./a.out $@" +#sysprof capture.syscap + +perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot +#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot +#perf report -g diff --git a/perf/texts/en-thelittleprince.txt b/perf/texts/en-thelittleprince.txt new file mode 100644 index 0000000000000000000000000000000000000000..7bf4abcc01262a48566678d9cb673ff36ed96962 --- /dev/null +++ b/perf/texts/en-thelittleprince.txt @@ -0,0 +1,1893 @@ +Downloaded from https://archive.org/details/TheLittlePrince-English + +THE LITTLE PRINCE + + + +Antoine De Saint-Exupery + + + + +Antoine de Saint-Exupery, who was a French author, journalist and pilot wrote +The Little Prince in 1943, one year before his death. + +The Little Prince appears to be a simple children’s tale, +some would say that it is actually a profound and deeply moving tale, +written in riddles and laced with philosophy and poetic metaphor. + + + + +Once when I was six years old I saw a magnificent picture in a book, called True Stories from +Nature, about the primeval forest. It was a picture of a boa constrictor in the act of swallowing an +animal. Here is a copy of the drawing. + +In the book it said: “Boa constrictors swallow their prey whole, without chewing it. After that they +are not able to move, and they sleep through the six months that they need for digestion.” I +pondered deeply, then, over the adventures of the jungle. And after some work with a coloured +pencil I succeeded in making my first drawing. My Drawing Number One. It looked like this: + + + + +I showed my masterpiece to the grown-ups, and asked them whether the drawing frightened them. +But they answered: “Frighten? Why should any one be frightened by a hat?” My drawing was not +a picture of a hat. It was a picture of a boa constrictor digesting an elephant. But since the grown- +ups were not able to understand it, I made another drawing: I drew the inside of the boa +constrictor, so that the grown-ups could see it clearly. They always need to have things explained. + + + +My Drawing Number Two looked like this: + + + + +The grown-ups’ response, this time, was to advise me to lay aside my drawings of boa +constrictors, whether from the inside or the outside, and devote myself instead to geography, +history, arithmetic and grammar. That is why, at the age of six, I gave up what might have been a +magnificent career as a painter. I had been disheartened by the failure of my Drawing Number +One and my Drawing Number Two. Grown-ups never understand anything by themselves, and it is +tiresome for children to be always and forever explaining things to them. + +So then I chose another profession, and learned to pilot air-planes. I have flown a little over all +parts of the world; and it is true that geography has been very useful to me. At a glance I can +distinguish China from Arizona. If one gets lost in the night, such knowledge is valuable. In the +course of this life I have had a great many encounters with a great many people who have been +concerned with matters of consequence. I have lived a great deal among grown-ups. I have seen +them intimately, close at hand. And that hasn’t much improved my opinion of them. + +Whenever I met one of them who seemed to me at all clear-sighted, I tried the experiment of +showing him my Drawing Number One, which I have always kept. I would try to find out, so, if this +was a person of true understanding. But, whoever it was, he, or she, would always say: “That is a +hat.” Then I would never talk to that person about boa constrictors, or primeval forests, or stars. I +would bring myself down to his level. I would talk to him about bridge, and golf, and politics, and +neckties. And the grown-up would be greatly pleased to have met such a sensible man. + +So I lived my life alone, without anyone that I could really talk to, until I had an accident with my +plane in the Desert of Sahara, six years ago. Something was broken in my engine. And as I had +with me neither a mechanic nor any passengers, I set myself to attempt the difficult repairs all +alone. It was a question of life or death for me: I had scarcely enough drinking water to last a +week. + +The first night, then, I went to sleep on the sand, a thousand miles from any human habitation. I +was more isolated than a shipwrecked sailor on a raft in the middle of the ocean. Thus you can +imagine my amazement, at sunrise, when I was awakened by an odd little voice. + + + + +It said: “If you please, draw me a sheep!” + +“What!” + +“Draw me a sheep!” + +I jumped to my feet, completely thunderstruck. I blinked my eyes hard. I looked carefully all +around me. And I saw a most extraordinary small person, who stood there examining me with +great seriousness. Here you may see the best portrait that, later, I was able to make of him. But +my drawing is certainly very much less charming than its model. + +That, however, is not my fault. The grown-ups discouraged me in my painter’s career when I was +six years old, and I never learned to draw anything, except boas from the outside and boas from +the inside. + +Now I stared at this sudden apparition with my eyes fairly starting out of my head in +astonishment. Remember, I had crashed in the desert a thousand miles from any inhabited region. +And yet my little man seemed neither to be straying uncertainly among the sands, nor to be +fainting from fatigue or hunger or thirst or fear. Nothing about him gave any suggestion of a child +lost in the middle of the desert, a thousand miles from any human habitation. + +When at last I was able to speak, I said to him: “But, what are you doing here?” And in answer he +repeated, very slowly, as if he were speaking of a matter of great consequence: + +“If you please, draw me a sheep...” + +When a mystery is too overpowering, one dare not disobey. Absurd as it might seem to me, a +thousand miles from any human habitation and in danger of death, I took out of my pocket a sheet +of paper and my fountain pen. But then I remembered how my studies had been concentrated on +geography, history, arithmetic, and grammar, and I told the little chap (a little crossly, too) that I +did not know how to draw. He answered me: “That doesn’t matter. Draw me a sheep...” + + + + +But I had never drawn a sheep. So I drew for him one of the two pictures I had drawn so often. It +was that of the boa constrictor from the outside. And I was astounded to hear the little fellow +greet it with, “No, no, no! I do not want an elephant inside a boa constrictor. A boa constrictor is a +very dangerous creature, and an elephant is very cumbersome. Where I live, everything is very +small. What I need is a sheep. Draw me a sheep. + + + + +So then I made a drawing. He looked at it carefully, then he said: “No. This sheep is already very +sickly. Make me another.” So I made another drawing. My friend smiled gently and indulgently. +“You see yourself,” he said, “that this is not a sheep. This is a ram. It has horns. + + + + +So then I did my drawing over once more. But it was rejected too, just like the others. “This one is +too old. I want a sheep that will live a long time. + +By this time my patience was exhausted, because I was in a hurry to start taking my engine apart. +So I tossed off this drawing. And I threw out an explanation with it. + +“This is only his box. The sheep you asked for is inside.” + + + + +I was very surprised to see a light break over the face of my young judge: + +“That is exactly the way I wanted it! Do you think that this sheep will have to have a great deal of +grass?” + +“Why?” + +“Because where I live everything is very small...” + +“There will surely be enough grass for him,” I said. + +“It is a very small sheep that I have given you.” + +He bent his head over the drawing: “Not so small that, Look! He has gone to sleep...” + +And that is how I made the acquaintance of the little prince. + +It took me a long time to learn where he came from. The little prince, who asked me so many +questions, never seemed to hear the ones I asked him. It was from words dropped by chance that, +little by little, everything was revealed to me. + +The first time he saw my air-plane, for instance (I shall not draw my air-plane; that would be much +too complicated for me), he asked me: “What is that object?” + +“That is not an object. It flies. It is an air-plane. It is my air-plane.” And I was proud to have him +learn that I could fly. He cried out, then: “What! You dropped down from the sky?” + + + +“Yes,” I answered, modestly. + + + +“Oh! That is funny!” And the little prince broke into a lovely peal of laughter, which irritated me +very much. I like my misfortunes to be taken seriously. + +Then he added: “So you, too, come from the sky! Which is your planet?” At that moment I caught +a gleam of light in the impenetrable mystery of his presence; and I demanded, abruptly: “Do you +come from another planet?” But he did not reply. He tossed his head gently, without taking his +eyes from my plane: “It is true that on that you can’t have come from very far away...” And he +sank into a reverie, which lasted a long time. Then, taking my sheep out of his pocket, he buried +himself in the contemplation of his treasure. + +You can imagine how my curiosity was aroused by this half-confidence about the “other planets.” I +made a great effort, therefore, to find out more on this subject. + +“My little man, where do you come from? What is this ‘where I live,’ of which you speak? Where +do you want to take your sheep?” + +After a reflective silence he answered: “The thing that is so good about the box you have given +me is that at night he can use it as his house.” + +“That is so. And if you are good I will give you a string, too, so that you can tie him during the day, +and a post to tie him to.” + +But the little prince seemed shocked by this offer: “Tie him! What a queer idea!” + +“But if you don’t tie him,” I said, “he will wander off somewhere, and get lost.” + +My friend broke into another peal of laughter: “But where do you think he would go?” +“Anywhere. Straight ahead of him.” + +Then the little prince said, earnestly: “That doesn’t matter. Where I live, everything is so small!” +And, with perhaps a hint of sadness, he added: “Straight ahead of him, nobody can go very far...” + + + + +I had thus learned a second fact of great importance: this was that the planet the little prince +came from was scarcely any larger than a house! But that did not really surprise me much. I knew +very well that in addition to the great planets, such as the Earth, Jupiter, Mars, Venus, to which +we have given names, there are also hundreds of others, some of which are so small that one has +a hard time seeing them through the telescope. + + + +When an astronomer discovers one of these he does not give it a name, but only a number. He +might call it, for example, “Asteroid 325.” + + + + +I have serious reason to believe that the planet from which the little prince came is the asteroid +known as B-612. This asteroid has only once been seen through the telescope. That was by a +Turkish astronomer, in 1909. + +On making his discovery, the astronomer had presented it to the International Astronomical +Congress, in a great demonstration. But he was in Turkish costume, and so nobody would believe +what he said. Grown-ups are like that... + +Fortunately, however, for the reputation of Asteroid B-612, a Turkish dictator made a law that his +subjects, under pain of death, should change to European costume. So in 1920 the astronomer +gave his demonstration all over again, dressed with impressive style and elegance. And this time +everybody accepted his report. + +If I have told you these details about the asteroid, and made a note of its number for you, it is on +account of the grown-ups and their ways. When you tell them that you have made a new friend, +they never ask you any questions about essential matters. They never say to you, “What does his +voice sound like? What games does he love best? Does he collect butterflies?” Instead, they +demand: “How old is he? How many brothers has he? How much does he weigh? How much +money does his father make?” + +Only from these figures do they think they have learned anything about him. + +If you were to say to the grown-ups: “I saw a beautiful house made of rosy brick, with geraniums +in the windows and doves on the roof,” they would not be able to get any idea of that house at all. + +You would have to say to them: “I saw a house that cost $ 20,000.” Then they would exclaim: “Oh, +what a pretty house that is!” Just so, you might say to them: “The proof that the little prince +existed is that he was charming, that he laughed, and that he was looking for a sheep. If anybody +wants a sheep, that is a proof that he exists.” And what good would it do to tell them that? They +would shrug their shoulders, and treat you like a child. But if you said to them: “The planet he +came from is Asteroid B-612,” then they would be convinced, and leave you in peace from their +questions. They are like that. One must not hold it against them. Children should always show +great forbearance toward grown-up people. But certainly, for us who understand life, figures are a +matter of indifference. + +I should have liked to begin this story in the fashion of the fairy-tales. I should have like to say: +“Once upon a time there was a little prince who lived on a planet that was scarcely any bigger + + + +than himself, and who had need of a sheep...” + + + +To those who understand life, that would have given a much greater air of truth to my story. Fori +do not want any one to read my book carelessly. I have suffered too much grief in setting down +these memories. Six years have already passed since my friend went away from me, with his +sheep. If I try to describe him here, it is to make sure that I shall not forget him. To forget a friend +is sad. Not every one has had a friend. And if I forget him, I may become like the grown-ups who +are no longer interested in anything but figures... It is for that purpose, again, that I have bought a +box of paints and some pencils. + +It is hard to take up drawing again at my age, when I have never made any pictures except those +of the boa constrictor from the outside and the boa constrictor from the inside, since I was six. I +shall certainly try to make my portraits as true to life as possible. But I am not at all sure of +success. One drawing goes along all right, and another has no resemblance to its subject. I make +some errors, too, in the little prince’s height: in one place he is too tall and in another too short. +And I feel some doubts about the colour of his costume. So I fumble along as best I can, now good, +now bad, and I hope generally fair-to- middling. In certain more important details I shall make +mistakes, also. But that is something that will not be my fault. My friend never explained anything +to me. He thought, perhaps, that I was like himself. But I, alas, do not know how to see sheep +through the walls of boxes. Perhaps I am a little like the grown-ups. I have had to grow old. + +As each day passed I would learn, in our talk, something about the little prince’s planet, his +departure from it, his journey. The information would come very slowly, as it might chance to fall +from his thoughts. It was in this way that I heard, on the third day, about the catastrophe of the +baobabs. + +This time, once more, I had the sheep to thank for it. For the little prince asked me abruptly, as if +seized by a grave doubt, + +“It is true, isn’t it, that sheep eat little bushes?” + +“Yes, that is true.” + +“Ah! I am glad!” + +I did not understand why it was so important that sheep should eat little bushes. But the little +prince added: “Then it follows that they also eat baobabs?” I pointed out to the little prince that +baobabs were not little bushes, but, on the contrary, trees as big as castles; and that even if he +took a whole herd of elephants away with him, the herd would not eat up one single baobab. + +The idea of the herd of elephants made the little prince laugh. “We would have to put them one on +top of the other,” he said. But he made a wise comment: + +“Before they grow so big, the baobabs start out by being little.” + +“That is strictly correct,” I said. “But why do you want the sheep to eat the little baobabs?” + +He answered me at once, “Oh, come, come!”, as if he were speaking of something that was self- +evident. And I was obliged to make a great mental effort to solve this problem, without any +assistance. + +Indeed, as I learned, there were on the planet where the little prince lived, as on all planets, good + + + + + +plants and bad plants. In consequence, there were good seeds from good plants, and bad seeds +from bad plants. But seeds are invisible. They sleep deep in the heart of the earth’s darkness, +until some one among them is seized with the desire to awaken. Then this little seed will stretch +itself and begin, timidly at first, to push a charming little sprig inoffensively upward toward the +sun. If it is only a sprout of radish or the sprig of a rose-bush, one would let it grow wherever it +might wish. But when it is a bad plant, one must destroy it as soon as possible, the very first +instant that one recognises it. + +Now there were some terrible seeds on the planet that was the home of the little prince; and these +were the seeds of the baobab. The soil of that planet was infested with them. A baobab is +something you will never, never be able to get rid of if you attend to it too late. It spreads over the +entire planet. It bores clear through it with its roots. And if the planet is too small, and the +baobabs are too many, they split it in pieces... + +“It is a question of discipline,” the little prince said to me later on. + +“When you’ve finished your own toilet in the morning, then it is time to attend to the toilet of your +planet, just so, with the greatest care. You must see to it that you pull up regularly all the baobabs, +at the very first moment when they can be distinguished from the rosebushes, which they +resemble so closely in their earliest youth. It is very tedious work,” the little prince added, “but +very easy.” And one day he said to me: “You ought to make a beautiful drawing, so that the +children where you live can see exactly how all this is. That would be very useful to them if they +were to travel some day. + + + + +Sometimes,” he added, “there is no harm in putting off a piece of work until another day. But +when it is a matter of baobabs, that always means a catastrophe. + +I knew a planet that was inhabited by a lazy man. He neglected three little bushes... So, as the +little prince described it to me, I have made a drawing of that planet. I do not much like to take +the tone of a moralist. But the danger of the baobabs is so little understood, and such considerable +risks would be run by anyone who might get lost on an asteroid, that for once I am breaking +through my reserve. “Children,” I say plainly, “watch out for the baobabs!” My friends, like +myself, have been skirting this danger for a long time, without ever knowing it; and so it is for +them that I have worked so hard over this drawing. + +The lesson which I pass on by this means is worth all the trouble it has cost me. Perhaps you will +ask me, “Why are there no other drawing in this book as magnificent and impressive as this +drawing of the baobabs?” The reply is simple. I have tried. But with the others I have not been +successful. When I made the drawing of the baobabs I was carried beyond myself by the inspiring +force of urgent necessity. + +Oh, little prince! Bit by bit I came to understand the secrets of your sad little life... For a long time +you had found your only entertainment in the quiet pleasure of looking at the sunset. + +I learned that new detail on the morning of the fourth day, when you said to me: + +“I am very fond of sunsets. Come, let us go look at a sunset now.” + +“But we must wait,” I said. + +“Wait? For what?” + +“For the sunset. We must wait until it is time.” + +At first you seemed to be very much surprised. And then you laughed to yourself. You said to me: +“I am always thinking that I am at home!” + +Just so. Everybody knows that when it is noon in the United States the sun is setting over France. +If you could fly to France in one minute, you could go straight into the sunset, right from noon. +Unfortunately, France is too far away for that. But on your tiny planet, my little prince, all you +need do is move your chair a few steps. You can see the day end and the twilight falling whenever +you like... + +“One day,” you said to me, “I saw the sunset forty-four times!” + +And a little later you added: “You know, one loves the sunset, when one is so sad...” “Were you so +sad, then?” I asked, “on the day of the forty-four sunsets?” + +But the little prince made no reply. + +On the fifth day, again, as always, it was thanks to the sheep, the secret of the little prince’s life +was revealed to me. + +Abruptly, without anything to lead up to it, and as if the question had been born of long and silent +meditation on his problem, he demanded: “A sheep; if it eats little bushes, does it eat flowers, +too?” + + + + +“A sheep,” I answered, “eats anything it finds in its reach.” + + + +“Even flowers that have thorns?” + +“Yes, even flowers that have thorns.” + +“Then the thorns, what use are they?” I did not know. + +At that moment I was very busy trying to unscrew a bolt that had got stuck in my engine. I was +very much worried, for it was becoming clear to me that the breakdown of my plane was +extremely serious. And I had so little drinking water left that I had to fear for the worst. + +“The thorns, what use are they?” + +The little prince never let go of a question, once he had asked it. As for me, I was upset over that +bolt. And I answered with the first thing that came into my head: “The thorns are of no use at all. +Flowers have thorns just for spite!” + +“Oh!” There was a moment of complete silence. + +Then the little prince flashed back at me, with a kind of resentfulness: “I don’t believe you! +Flowers are weak creatures. They are naive. They reassure themselves as best they can. They +believe that their thorns are terrible weapons...” + +I did not answer. At that instant I was saying to myself: “If this bolt still won’t turn, I am going to +knock it out with the hammer.” + +Again the little prince disturbed my thoughts. “And you actually believe that the flowers...” + +“Oh, no!” I cried. “No, no no! I don’t believe anything. I answered you with the first thing that +came into my head. Don’t you see, I am very busy with matters of consequence!” + +He stared at me, thunderstruck. “Matters of consequence!” + +He looked at me there, with my hammer in my hand, my fingers black with engine grease, bending +down over an object which seemed to him extremely ugly... + +“You talk just like the grown-ups!” That made me a little ashamed. But he went on, relentlessly: +“You mix everything up together... You confuse everything...” + +He was really very angry. He tossed his golden curls in the breeze. + +“I know a planet where there is a certain red-faced gentleman. He has never smelled a flower. He +has never looked at a star. He has never loved any one. He has never done anything in his life but +add up figures. And all day he says over and over, just like you: ‘I am busy with matters of +consequence!’ And that makes him swell up with pride. + +“But he is not a man, he is a mushroom!” + + + +“A what?” + + + +“A mushroom!” The little prince was now white with rage. “The flowers have been growing thorns +for millions of years. For millions of years the sheep have been eating them just the same. And is +it not a matter of consequence to try to understand why the flowers go to so much trouble to grow + + + + +' ' + +I \ + + + + +thorns, which are never of any use to them? Is the warfare between the sheep and the flowers not +important? Is this not of more consequence than a fat red-faced gentleman’s sums? And if I know, +I, myself, one flower which is unique in the world, which grows nowhere but on my planet, but +which one little sheep can destroy in a single bite some morning, without even noticing what he is +doing, Oh! You think that is not important! His face turned from white to red as he continued: “If +some one loves a flower, of which just one single blossom grows in all the millions and millions of +stars, it is enough to make him happy just to look at the stars. + +He can say to himself, ‘Somewhere, my flower is there...’ But if the sheep eats the flower, in one +moment all his stars will be darkened... And you think that is not important!” + +He could not say anything more. His words were choked by sobbing. The night had fallen. I had +let my tools drop from my hands. Of what moment now was my hammer, my bolt, or thirst, or +death? On one star, one planet, my planet, the Earth, there was a little prince to be comforted. I +took him in my arms, and rocked him. I said to him: “The flower that you love is not in danger. I +will draw you a muzzle for your sheep. I will draw you a railing to put around your flower. I will...” + +I did not know what to say to him. I felt awkward and blundering. I did not know how I could reach +him, where I could overtake him and go on hand in hand with him once more. + +It is such a secret place, the land of tears. + +I soon learned to know this flower better. On the little prince’s planet the flowers had always been +very simple. They had only one ring of petals; they took up no room at all; they were a trouble to +nobody. One morning they would appear in the grass, and by night they would have faded +peacefully away. But one day, from a seed blown from no one knew where, a new flower had come +up; and the little prince had watched very closely over this small sprout which was not like any +other small sprouts on his planet. + +It might, you see, have been a new kind of baobab. The shrub soon stopped growing, and began to +get ready to produce a flower. The little prince, who was present at the first appearance of a huge +bud, felt at once that some sort of miraculous apparition must emerge from it. But the flower was +not satisfied to complete the preparations for her beauty in the shelter of her green chamber. She + + + +chose her colours with the greatest care. She adjusted her petals one by one. She did not wish to +go out into the world all rumpled, like the field poppies. It was only in the full radiance of her +beauty that she wished to appear. Oh, yes! She was a coquettish creature! And her mysterious +adornment lasted for days and days. Then one morning, exactly at sunrise, she suddenly showed +herself. And, after working with all this painstaking precision, she yawned and said: “Ah! I am +scarcely awake. I beg that you will excuse me. My petals are still all disarranged...” But the little +prince could not restrain his admiration: + +“Oh! How beautiful you are!” + +“Am I not?” the flower responded, sweetly. “And I was born at the same moment as the sun...” + +The little prince could guess easily enough that she was not any too modest, but how moving, and +exciting she was! + +“I think it is time for breakfast,” she added an instant later. “If you would have the kindness to +think of my needs” And the little prince, completely abashed, went to look for a sprinkling can of +fresh water. + +So, he tended the flower. So, too, she began very quickly to torment him with her vanity, which +was, if the truth be known, a little difficult to deal with. + +One day, for instance, when she was speaking of her four thorns, she said to the little prince: “Let +the tigers come with their claws!” + +“There are no tigers on my planet,” the little prince objected. “And, anyway, tigers do not eat +weeds.” + +“I am not a weed,” the flower replied, sweetly. “Please excuse me...” “I am not at all afraid of +tigers,” she went on, “but I have a horror of drafts. I suppose you wouldn’t screen for me?" + +“A horror of drafts, that is bad luck, for a plant,” remarked the little prince, and added to himself, +“This flower is a very complex creature...” + +“At night I want you to put me under a glass globe. It is very cold where you live. In the place I +came from...” But she interrupted herself at that point. She had come in the form of a seed. She +could not have known anything of any other worlds. + +Embarrassed over having let herself be caught on the verge of such an untruth, she coughed two +or three times, in order to put the little prince in the wrong. + +“The screen?” + +“I was just going to look for it when you spoke to me...” + +Then she forced her cough a little more so that he should suffer from remorse just the same. So +the little prince, in spite of all the good will that was inseparable from his love, had soon come to +doubt her. He had taken seriously words which were without importance, and it made him very +unhappy. + +“I ought not to have listened to her,” he confided to me one day. + +“One never ought to listen to the flowers. One should simply look at them and breathe their + + + + +fragrance. Mine perfumed all my planet. But I did not know how to take pleasure in all her grace. +This tale of claws, which disturbed me so much, should only have filled my heart with tenderness +and pity.” + +And he continued his confidences: “The fact is that I did not know how to understand anything! I +ought to have judged by deeds and not by words. She cast her fragrance and her radiance over +me. I ought never to have run away from her... I ought to have guessed all the affection that lay +behind her poor little stratagems. Flowers are so inconsistent! But I was too young to know how to +love her...” + +I believe that for his escape he took advantage of the migration of a flock of wild birds. On the +morning of his departure he put his planet in perfect order. He carefully cleaned out his active +volcanoes. He possessed two active volcanoes; and they were very convenient for heating his +breakfast in the morning. He also had one volcano that was extinct. But, as he said, “One never +knows!” So he cleaned out the extinct volcano, too. If they are well cleaned out, volcanoes burn +slowly and steadily, without any eruptions. Volcanic eruptions are like fires in a chimney. + +On our earth we are obviously much too small to clean out our volcanoes. That is why they bring +no end of trouble upon us. The little prince also pulled up, with a certain sense of dejection, the +last little shoots of the baobabs. He believed that he would never want to return. But on this last +morning all these familiar tasks seemed very precious to him. And when he watered the flower for +the last time, and prepared to place her under the shelter of her glass globe, he realised that he +was very close to tears. “Goodbye,” he said to the flower. But she made no answer. “Goodbye,” +he said again. The flower coughed. But it was not because she had a cold. + +“I have been silly,” she said to him, at last. “I ask your forgiveness. Try to be happy...” He was +surprised by this absence of reproaches. He stood there all bewildered, the glass globe held +arrested in mid-air. He did not understand this quiet sweetness. + +“Of course I love you,” the flower said to him. “It is my fault that you have not known it all the +while. That is of no importance. But you, you have been just as foolish as I. Try to be happy... let +the glass globe be. I don’t want it any more.” + +“But the wind...” “My cold is not so bad as all that... the cool night air will do me good. I am a +flower.” + +“But the animals...” “Well, I must endure the presence of two or three caterpillars if I wish to +become acquainted with the butterflies. It seems that they are very beautiful. And if not the +butterflies and the caterpillars who will call upon me? You will be far away... as for the large +animals, I am not at all afraid of any of them. I have my claws.” + +And, naively, she showed her four thorns. + +Then she added: “Don’t linger like this. You have decided to go away. Now go!” + +For she did not want him to see her crying. She was such a proud flower... + + + +He found himself in the neighbourhood of the asteroids 325, 326, 327, 328, 329, and 330. He +began, therefore, by visiting them, in order to add to his knowledge. The first of them was +inhabited by a king. Clad in royal purple and ermine, he was seated upon a throne, which was at + + + + +the same time both simple and majestic. + + + +“Ah! Here is a subject,” exclaimed the king, when he saw the little prince coming. And the little +prince asked himself: “How could he recognise me when he had never seen me before?” + +He did not know how the world is simplified for kings. To them, all men are subjects. “Approach, +so that I may see you better,” said the king, who felt consumingly proud of being at last a king +over somebody. + +The little prince looked everywhere to find a place to sit down; but the entire planet was crammed +and obstructed by the king’s magnificent ermine robe. So he remained standing upright, and, since +he was tired, he yawned. + +“It is contrary to etiquette to yawn in the presence of a king,” the monarch said to him. “I forbid +you to do so.” + +“I can’t help it. I can’t stop myself,” replied the little prince, thoroughly embarrassed. + +“I have come on a long journey, and I have had no sleep...” + +“Ah, then,” the king said. “I order you to yawn. It is years since I have seen anyone yawning. +Yawns, to me, are objects of curiosity. Come, now! Yawn again! It is an order.” + +“That frightens me... I cannot, any more...” murmured the little prince, now completely abashed. + +“Hum! Hum!” replied the king. “Then I... I order you sometimes to yawn and sometimes to” He +sputtered a little, and seemed vexed. For what the king fundamentally insisted upon was that his +authority should be respected. He tolerated no disobedience. He was an absolute monarch. But, +because he was a very good man, he made his orders reasonable. + +“If I ordered a general,” he would say, by way of example, “if I ordered a general to change +himself into a sea bird, and if the general did not obey me, that would not be the fault of the +general. It would be my fault.” + +“May I sit down?” came now a timid inquiry from the little prince. “I order you to do so,” the king +answered him, and majestically gathered in a fold of his ermine mantle. But the little prince was +wondering... The planet was tiny. Over what could this king really rule? + +“Sire,” he said to him, “I beg that you will excuse my asking you a question” + +“I order you to ask me a question,” the king hastened to assure him. “Sire, over what do you +rule?” “Over everything,” said the king, with magnificent simplicity. + +“Over everything?” The king made a gesture, which took in his planet, the other planets, and all +the stars. “Over all that?” asked the little prince. “Over all that,” the king answered. For his rule +was not only absolute: it was also universal. “And the stars obey you?” “Certainly they do,” the +king said. “They obey instantly. I do not permit insubordination.” + +Such power was a thing for the little prince to marvel at. If he had been master of such complete +authority, he would have been able to watch the sunset, not forty-four times in one day, but +seventy-two, or even a hundred, or even two hundred times, with out ever having to move his +chair. And because he felt a bit sad as he remembered his little planet, which he had forsaken, he +plucked up his courage to ask the king a favour: + + + + + +“I should like to see a sunset... do me that kindness... Order the sun to set...” + +“If I ordered a general to fly from one flower to another like a butterfly, or to write a tragic +drama, or to change himself into a sea bird, and if the general did not carry out the order that he +had received, which one of us would be in the wrong?” the king demanded. “The general, or +myself?” + +“You,” said the little prince firmly. + +“Exactly. One much require from each one the duty which each one can perform,” the king went +on. “Accepted authority rests first of all on reason. If you ordered your people to go and throw +themselves into the sea, they would rise up in revolution. I have the right to require obedience +because my orders are reasonable.” + +“Then my sunset?” the little prince reminded him: for he never forgot a question once he had +asked it. + +“You shall have your sunset. I shall command it. But, according to my science of government, I +shall wait until conditions are favourable.” + +“When will that be?” inquired the little prince. “Hum! Hum!” replied the king; and before saying +anything else he consulted a bulky almanac. “Hum! Hum! That will be about... about... that will be +this evening about twenty minutes to eight. And you will see how well I am obeyed.” + +The little prince yawned. He was regretting his lost sunset. And then, too, he was already +beginning to be a little bored. “I have nothing more to do here,” he said to the king. “So I shall set +out on my way again.” “Do not go,” said the king, who was very proud of having a subject. “Do +not go. I will make you a Minister!” “Minister of what?” “Minster of...of Justice!” “But there is +nobody here to judge!” “We do not know that,” the king said to him. “I have not yet made a +complete tour of my kingdom. I am very old. There is no room here for a carriage. And it tires me +to walk.” “Oh, but I have looked already!” said the little prince, turning around to give one more +glance to the other side of the planet. + +On that side, as on this, there was nobody at all... “Then you shall judge yourself,” the king +answered, “that is the most difficult thing of all. It is much more difficult to j udge oneself than to +j udge others. If you succeed in j udging yourself rightly, then you are indeed a man of true +wisdom.” + + + +“Yes,” said the little prince, “but I can judge myself anywhere. I do not need to live on this planet. +“Hum! Hum!” said the king. “I have good reason to believe that somewhere on my planet there is +an old rat. I hear him at night. You can judge this old rat. From time to time you will condemn him +to death. Thus his life will depend on your j ustice. But you will pardon him on each occasion; for +he must be treated thriftily. He is the only one we have.” + +“I,” replied the little prince, “do not like to condemn anyone to death. And now I think I will go on +my way.” “No,” said the king. But the little prince, having now completed his preparations for +departure, had no wish to grieve the old monarch. “If Your Majesty wishes to be promptly +obeyed,” he said, “he should be able to give me a reasonable order. He should be able, for +example, to order me to be gone by the end of one minute. It seems to me that conditions are +favourable...” As the king made no answer, the little prince hesitated a moment. + +Then, with a sigh, he took his leave. “I made you my Ambassador,” the king called out, hastily. + +He had a magnificent air of authority. + +“The grown-ups are very strange,” the little prince said to himself, as he continued on his journey. +The second planet was inhabited by a conceited man. + + + + + + + + + + +“Ah! Ah! I am about to receive a visit from an admirer!” he exclaimed from afar, when he first +saw the little prince coming. For, to conceited men, all other men are admirers. + +“Good morning,” said the little prince. “That is a queer hat you are wearing.” + +“It is a hat for salutes,” the conceited man replied. “It is to raise in salute when people acclaim +me. Unfortunately, nobody at all ever passes this way.” + +“Yes?” said the little prince, who did not understand what the conceited man was talking about. + +“Clap your hands, one against the other,” the conceited man now directed him. The little prince +clapped his hands. The conceited man raised his hat in a modest salute. “This is more entertaining +than the visit to the king,” the little prince said to himself. And he began again to clap his hands, +one against the other. The conceited man against raised his hat in salute. After five minutes of + + + +this exercise the little prince grew tired of the game’s monotony. “And what should one do to +make the hat come down?” he asked. But the conceited man did not hear him. Conceited people +never hear anything but praise. + +“Do you really admire me very much?” he demanded of the little prince. “What does that mean, +‘admire’?” + +“To admire means that you regard me as the handsomest, the best-dressed, the richest, and the +most intelligent man on this planet.” “But you are the only man on your planet!” “Do me this +kindness. Admire me just the same.” + +“I admire you,” said the little prince, shrugging his shoulders slightly, “but what is there in that to +interest you so much?” + +And the little prince went away. “The grown-ups are certainly very odd,” he said to himself, as he +continued on his journey. + +The next planet was inhabited by a tippler. + + + + +This was a very short visit, but it plunged the little prince into deep dejection. “What are you +doing there?” he said to the tippler, whom he found settled down in silence before a collection of +empty bottles and also a collection of full bottles. + +“I am drinking,” replied the tippler, with a lugubrious air. + +“Why are you drinking?” demanded the little prince. + +“So that I may forget,” replied the tippler. “Forget what?” inquired the little prince, who already +was sorry for him. + +“Forget that I am ashamed,” the tippler confessed, hanging his head. + +“Ashamed of what?” insisted the little prince, who wanted to help him. + +“Ashamed of drinking!” The tippler brought his speech to an end, and shut himself up in an +impregnable silence. + +And the little prince went away, puzzled. “The grown-ups are certainly very, very odd,” he said to +himself, as he continued on his journey. + +The fourth planet belonged to a businessman. + +This man was so much occupied that he did not even raise his head at the little prince’s arrival. + + + +“Good morning,” the little prince said to him. “Your cigarette has gone out.” + + + +“Three and two make five. Five and seven make twelve. Twelve and three make fifteen. Good +morning. Fifteen and seven make twenty-two. Twenty-two and six make twenty-eight. I haven’t +time to light it again. Twenty-six and five make thirty-one. Phew ! Then that makes five-hundred- +and-one-million, six-hundred-twenty-two-thousand, seven-hundred-thirty-one.” + +“Five hundred million what?” asked the little prince. “Eh? Are you still there? Five-hundred-and- +one million, I can’t stop... I have so much to do! I am concerned with matters of consequence. I +don’t amuse myself with balderdash. Two and five make seven...” + +“Five-hundred-and-one million what?” repeated the little prince, who never in his life had let go of +a question once he had asked it. + +The businessman raised his head. “During the fifty-four years that I have inhabited this planet, I +have been disturbed only three times. The first time was twenty-two years ago, when some giddy +goose fell from goodness knows where. He made the most frightful noise that resounded all over +the place, and I made four mistakes in my addition. The second time, eleven years ago, I was +disturbed by an attack of rheumatism. I don’t get enough exercise. I have no time for loafing. The +third time, well, this is it! I was saying, then, five -hundred-and-one millions” + +“Millions of what?” The businessman suddenly realised that there was no hope of being left in +peace until he answered this question. + +“Millions of those little objects,” he said, “which one sometimes sees in the sky.” “Flies?” “Oh, +no. Little glittering objects.” “Bees?” “Oh, no. Little golden objects that set lazy men to idle +dreaming. As for me, I am concerned with matters of consequence. There is no time for idle +dreaming in my life.” “Ah! You mean the stars?” “Yes, that’s it. The stars.” “And what do you do +with five-hundred millions of stars?” “Five-hundred-and-one million, six-hundred-twenty-two +thousand, seven-hundred-thirty-one. I am concerned with matters of consequence: I am +accurate.” + +“And what do you do with these stars?” “What do I do with them?” “Yes.” “Nothing. I own them.” +“You own the stars?” “Yes.” “But I have already seen a king who...” “Kings do not own, they +reign over. It is a very different matter.” + +“And what good does it do you to own the stars?” “It does me the good of making me rich.” + +“And what good does it do you to be rich?” + +“It makes it possible for me to buy more stars, if any are ever discovered.” + +“This man,” the little prince said to himself, “reasons a little like my poor tippler...” Nevertheless, +he still had some more questions. “How is it possible for one to own the stars?” “To whom do they +belong?” the businessman retorted, peevishly. “I don’t know. To nobody.” “Then they belong to +me, because I was the first person to think of it.” “Is that all that is necessary?” “Certainly. + +When you find a diamond that belongs to nobody, it is yours. When you discover an island that +belongs to nobody, it is yours. When you get an idea before any one else, you take out a patent on +it: it is yours. So with me: I own the stars, because nobody else before me ever thought of owning +them.” + +“Yes, that is true,” said the little prince. “And what do you do with them?” + + + + +“I administer them,” replied the businessman. “I count them and recount them. It is difficult. But I +am a man who is naturally interested in matters of consequence.” + +The little prince was still not satisfied. “If I owned a silk scarf,” he said, “I could put it around my +neck and take it away with me. If I owned a flower, I could pluck that flower and take it away with +me. But you cannot pluck the stars from heaven...” + +“No. But I can put them in the bank.” “Whatever does that mean?” “That means that I write the +number of my stars on a little paper. And then I put this paper in a drawer and lock it with a key.” + +“And that is all?” + +“That is enough,” said the businessman. + +“It is entertaining,” thought the little prince. “It is rather poetic. But it is of no great +consequence.” On matters of consequence, the little prince had ideas, which were very different +from those of the grown-ups. + +“I myself own a flower,” he continued his conversation with the businessman, “which I water +every day. I own three volcanoes, which I clean out every week (for I also clean out the one that is +extinct; one never knows). It is of some use to my volcanoes, and it is of some use to my flower, +that I own them. But you are of no use to the stars...” + +The businessman opened his mouth, but he found nothing to say in answer. And the little prince +went away. “The grown-ups are certainly altogether extraordinary,” he said simply, talking to +himself as he continued on his journey. + +The fifth planet was very strange. It was the smallest of all. There was just enough room on it for +a street lamp and a lamplighter. + + + + +The little prince was not able to reach any explanation of the use of a street lamp and a +lamplighter, somewhere in the heavens, on a planet, which had no people, and not one house. + +But he said to himself, nevertheless: “It may well be that this man is absurd. But he is not so +absurd as the king, the conceited man, the businessman, and the tippler. For at least his work has + + + +some meaning. When he lights his street lamp, it is as if he brought one more star to life, or one +flower. When he puts out his lamp, he sends the flower, or the star, to sleep. That is a beautiful +occupation. And since it is beautiful, it is truly useful.” + +When he arrived on the planet he respectfully saluted the lamplighter. + +“Good morning. Why have you just put out your lamp?” + +“Those are the orders,” replied the lamplighter. “Good morning.” + +“What are the orders?” + +“The orders are that I put out my lamp. Good evening.” And he lighted his lamp again. “But why +have you just lighted it again?” + +“Those are the orders,” replied the lamplighter. + +“I do not understand,” said the little prince. + +“There is nothing to understand,” said the lamplighter. “Orders are orders. Good morning.” And +he put out his lamp. + +Then he mopped his forehead with a handkerchief decorated with red squares. + +“I follow a terrible profession. In the old days it was reasonable. I put the lamp out in the morning, +and in the evening I lighted it again. I had the rest of the day for relaxation and the rest of the +night for sleep.” + +“And the orders have been changed since that time?” + +“The orders have not been changed,” said the lamplighter. “That is the tragedy! From year to +year the planet has turned more rapidly and the orders have not been changed!” + +“Then what?” asked the little prince. + +“Then the planet now makes a complete turn every minute, and I no longer have a single second +for repose. Once every minute I have to light my lamp and put it out!” + +“That is very funny! A day lasts only one minute, here where you live!” + +“It is not funny at all!” said the lamplighter. “While we have been talking together a month has +gone by.” + +“A month?” + + + +“Yes, a month. Thirty minutes. Thirty days. Good evening.” And he lighted his lamp again. As the +little prince watched him, he felt that he loved this lamplighter who was so faithful to his orders. +He remembered the sunsets, which he himself had gone to seek, in other days, merely by pulling +up his chair; and he wanted to help his friend. + +“You know,” he said, “I can tell you a way you can rest whenever you want to...” + +“I always want to rest,” said the lamplighter. For it is possible for a man to be faithful and lazy at +the same time. + + + + +The little prince went on with his explanation: “Your planet is so small that three strides will take +you all the way around it. To be always in the sunshine, you need only walk along rather slowly. +When you want to rest, you will walk and the day will last as long as you like.” + +“That doesn’t do me much good,” said the lamplighter. “The one thing I love in life is to sleep.” + +“Then you’re unlucky,” said the little prince. + +“I am unlucky,” said the lamplighter. “Good morning.” And he put out his lamp. + +“That man,” said the little prince to himself, as he continued farther on his journey, “that man +would be scorned by all the others: by the king, by the conceited man, by the tippler, by the +businessman. Nevertheless he is the only one of them all who does not seem to me ridiculous. +Perhaps that is because he is thinking of something else besides himself.” + +He breathed a sigh of regret, and said to himself, again: “That man is the only one of them all +whom I could have made my friend. But his planet is indeed too small. There is no room on it for +two people...” What the little prince did not dare confess was that he was sorry most of all to leave +this planet, because it was blest every day with 1440 sunsets! + +The sixth planet was ten times larger than the last one. It was inhabited by an old gentleman who +wrote voluminous books. + + + + +“Oh, look! Here is an explorer!” he exclaimed to himself when he saw the little prince coming. + +The little prince sat down on the table and panted a little. He had already travelled so much and +so far! + +“Where do you come from?” the old gentleman said to him. + +“What is that big book?” said the little prince. “What are you doing?” + +“I am a geographer,” the old gentleman said to him. + +“What is a geographer?” asked the little prince. “A geographer is a scholar who knows the +location of all the seas, rivers, towns, mountains, and deserts.” + +“That is very interesting,” said the little prince. “Here at last is a man who has a real profession!” +And he cast a look around him at the planet of the geographer. + + + +It was the most magnificent and stately planet that he had ever seen. + +“Your planet is very beautiful,” he said. “Has it any oceans?” + +“I couldn’t tell you,” said the geographer. + +“Ah!” The little prince was disappointed. “Has it any mountains?” + +“I couldn’t tell you,” said the geographer. + +“And towns, and rivers, and deserts?” + +“I couldn’t tell you that, either.” + +“But you are a geographer!” + +“Exactly,” the geographer said. “But I am not an explorer. I haven’t a single explorer on my +planet. It is not the geographer who goes out to count the towns, the rivers, the mountains, the +seas, the oceans, and the deserts. The geographer is much too important to go loafing about. He +does not leave his desk. But he receives the explorers in his study. He asks them questions, and +he notes down what they recall of their travels. And if the recollections of any one among them +seem interesting to him, the geographer orders an inquiry into that explorer’s moral character.” + +“Why is that?” + +“Because an explorer who told lies would bring disaster on the books of the geographer. So would +an explorer who drank too much.” + +“Why is that?” asked the little prince. + +“Because intoxicated men see double. Then the geographer would note down two mountains in a +place where there was only one.” + +“I know some one,” said the little prince, “who would make a bad explorer.” + +“That is possible. Then, when the moral character of the explorer is shown to be good, an inquiry +is ordered into his discovery.” + +“One goes to see it?” + +“No. That would be too complicated. But one requires the explorer to furnish proofs. For example, +if the discovery in question is that of a large mountain, one requires that large stones be brought +back from it.” The geographer was suddenly stirred to excitement. “But you come from far away! +You are an explorer! You shall describe your planet to me!” And, having opened his big register, +the geographer sharpened his pencil. The recitals of explorers are put down first in pencil. One +waits until the explorer has furnished proofs, before putting them down in ink. “Well?” said the +geographer expectantly. + +“Oh, where I live,” said the little prince, “it is not very interesting. It is all so small. I have three +volcanoes. Two volcanoes are active and the other is extinct. But one never knows.” + +“One never knows,” said the geographer. + + + +“I have also a flower.” + + + + +“We do not record flowers,” said the geographer. + +“Why is that? The flower is the most beautiful thing on my planet!” + +“We do not record them,” said the geographer, “because they are ephemeral.” + +“What does that mean ‘ephemeral’?” + +“Geographies,” said the geographer, “are the books which, of all books, are most concerned with +matters of consequence. They never become old-fashioned. It is very rarely that a mountain +changes its position. It is very rarely that an ocean empties itself of its waters. We write of eternal +things.” + +“But extinct volcanoes may come to life again,” the little prince interrupted. + +“What does that mean ‘ephemeral’?” + +“Whether volcanoes are extinct or alive, it comes to the same thing for us,” said the geographer. +“The thing that matters to us is the mountain. It does not change.” + +“But what does that mean ‘ephemeral’?” repeated the little prince, who never in his life had let go +of a question, once he had asked it. + +“It means, ‘which is in danger of speedy disappearance.’ “ + +“Is my flower in danger of speedy disappearance?” + +“Certainly it is.” + +“My flower is ephemeral,” the little prince said to himself, “and she has only four thorns to +defend herself against the world. And I have left her on my planet, all alone!” + +That was his first moment of regret. But he took courage once more. “What place would you +advise me to visit now?” he asked. “The planet Earth,” replied the geographer. “It has a good +reputation.” And the little prince went away, thinking of his flower. + + + + +So then the seventh planet was the Earth. + +The Earth is not just an ordinary planet! + +One can count, there 111 kings (not forgetting, to be sure, the Negro kings among them), 7000 +geographers, 900,000 businessmen, 7,500,000 tipplers, 311,000,000 conceited men, that is to say, +about 2,000,000,000 grown-ups. + +To give you an idea of the size of the Earth, I will tell you that before the invention of electricity it +was necessary to maintain, over the whole of the six continents, a veritable army of 462,511 +lamplighters for the street lamps. Seen from a slight distance, that would make a splendid +spectacle. + +The movements of this army would be regulated like those of the ballet in the opera. First would +come the turn of the lamplighters of New Zealand and Australia. Having set their lamps alight, +these would go off to sleep. Next, the lamplighters of China and Siberia would enter for their steps +in the dance, and then they too would be waved back into the wings. After that would come the +turn of the lamplighters of Russia and the Indies; then those of Africa and Europe, then those of +South America; then those of North America. And never would they make a mistake in the order +of their entry upon the stage. It would be magnificent. + +Only the man who was in charge of the single lamp at the North Pole, and his colleague who was +responsible for the single lamp at the South Pole, only these two would live free from toil and +care: they would be busy twice a year. + +When one wishes to play the wit, he sometimes wanders a little from the truth. + +I have not been altogether honest in what I have told you about the lamplighters. And I realise +that I run the risk of giving a false idea of our planet to those who do not know it. + +Men occupy a very small place upon the Earth. If the two billion inhabitants who people its +surface were all to stand upright and somewhat crowded together, as they do for some big public +assembly, they could easily be put into one public square twenty miles long and twenty miles wide. +All humanity could be piled up on a small Pacific islet. + +The grown-ups, to be sure, will not believe you when you tell them that. They imagine that they fill +a great deal of space. They fancy themselves as important as the baobabs. You should advise +them, then, to make their own calculations. They adore figures, and that will please them. But do +not waste your time on this extra task. It is unnecessary. You have, I know, confidence in me. + +When the little prince arrived on the Earth, he was very much surprised not to see any people. He +was beginning to be afraid he had come to the wrong planet, when a coil of gold, the colour of the +moonlight, flashed across the sand. + +“Good evening,” said the little prince courteously. + +“Good evening,” said the snake. + +“What planet is this on which I have come down?” asked the little prince. + +“This is the Earth; this is Africa,” the snake answered. + +“Ah! Then there are no people on the Earth?” + + + + +“This is the desert. There are no people in the desert. The Earth is large,” said the snake. + +The little prince sat down on a stone, and raised his eyes toward the sky. + +“I wonder,” he said, “whether the stars are set alight in heaven so that one day each one of us +may find his own again... Look at my planet. It is right there above us. But how far away it is!” + +“It is beautiful,” the snake said. “What has brought you here?” + +“I have been having some trouble with a flower,” said the little prince. “Ah!” said the snake. And +they were both silent. + +“Where are the men?” the little prince at last took up the conversation again. “It is a little lonely +in the desert...” + +“It is also lonely among men,” the snake said. The little prince gazed at him for a long time. + +“You are a funny animal,” he said at last. “You are no thicker than a finger...” + +“But I am more powerful than the finger of a king,” said the snake. + +The little prince smiled. “You are not very powerful. You haven’t even any feet. You cannot even +travel...” + +“I can carry you farther than any ship could take you,” said the snake. He twined himself around +the little prince’s ankle, like a golden bracelet. + +“Whomever I touch, I send back to the earth from whence he came,” the snake spoke again. “But +you are innocent and true, and you come from a star...” + +The little prince made no reply. “You move me to pity, you are so weak on this Earth made of +granite,” the snake said. “I can help you, some day, if you grow too homesick for your own planet. +I can...” + +“Oh! I understand you very well,” said the little prince. “But why do you always speak in +riddles?” + +“I solve them all,” said the snake. And they were both silent. + +The little prince crossed the desert and met with only one flower. + +It was a flower with three petals, a flower of no account at all. + +“Good morning,” said the little prince. + +“Good morning,” said the flower. + +“Where are the men?” the little prince asked, politely. The flower had once seen a caravan +passing. + +“Men?” she echoed. “I think there are six or seven of them in existence. I saw them, several +years ago. But one never knows where to find them. The wind blows them away. They have no +roots, and that makes their life very difficult.” + + + +“Goodbye,” said the little prince. + + + + +“Goodbye,” said the flower. + + + +After that, the little prince climbed a high mountain. The only mountains he had ever known were +the three volcanoes, which came up to his knees. And he used the extinct volcano as a footstool. + +“From a mountain as high as this one,” he said to himself, “I shall be able to see the whole planet +at one glance, and all the people...” But he saw nothing, save peaks of rock that were sharpened +like needles. + + + + +“Good morning,” he said courteously. + +“Good morning...Good morning...Good morning,” answered the echo. + +“Who are you?” said the little prince. + +“Who are you...Who are you...Who are you?” answered the echo. + +“Be my friends. I am all alone,” he said. + +“I am all alone...all alone. ..all alone,” answered the echo. + +“What a queer planet!” he thought. “It is altogether dry, and altogether pointed, and altogether +harsh and forbidding. And the people have no imagination. They repeat whatever one says to +them... On my planet I had a flower; she always was the first to speak...” + +But it happened that after walking for a long time through sand, and rocks, and snow, the little +prince at last came upon a road. And all roads lead to the abodes of men. + +“Good morning,” he said. He was standing before a garden, all a-bloom with roses. + +“Good morning,” said the roses. + +The little prince gazed at them. They all looked like his flower. + +“Who are you?” he demanded, thunderstruck. + +“We are roses,” the roses said. And he was overcome with sadness. His flower had told him that +she was the only one of her kind in all the universe. And here were five thousand of them, all +alike, in one single garden! + +“She would be very much annoyed,” he said to himself, “if she should see that... she would cough + + + +most dreadfully, and she would pretend that she was dying, to avoid being laughed at. And I +should be obliged to pretend that I was nursing her back to life, for if I did not do that, to humble +myself also, she would really allow herself to die...” + +Then he went on with his reflections: “I thought that I was rich, with a flower that was unique in all +the world; and all I had was a common rose. A common rose, and three volcanoes that come up to +my knees — and one of them perhaps extinct forever... that doesn’t make me a very great +prince...” And he lay down in the grass and cried. + +It was then that the fox appeared. + +“Good morning,” said the fox. + +“Good morning,” the little prince responded politely, although when he turned around he saw +nothing. + +“I am right here,” the voice said, “under the apple tree.” “ + +Who are you?” asked the little prince, and added, “You are very pretty to look at.” + +“I am a fox,” said the fox. + +“Come and play with me,” proposed the little prince. + +“I am so unhappy.” “I cannot play with you,” the fox said. “I am not tamed.” + +“Ah! Please excuse me,” said the little prince. But, after some thought, he added: “What does +that mean, ‘tame’?” + + + + +“You do not live here,” said the fox. “What is it that you are looking for?” + +“I am looking for men,” said the little prince. “What does that mean, ‘tame’?” + +“Men,” said the fox. “They have guns, and they hunt. It is very disturbing. They also raise +chickens. These are their only interests. Are you looking for chickens?” + +“No,” said the little prince. “I am looking for friends. What does that mean, ‘tame’?” + +“It is an act too often neglected,” said the fox. It means to establish ties.” + + + +“‘To establish ties’?” + + + +“Just that,” said the fox. “To me, you are still nothing more than a little boy who is just like a +hundred thousand other little boys. And I have no need of you. And you, on your part, have no +need of me. To you, I am nothing more than a fox like a hundred thousand other foxes. But if you +tame me, then we shall need each other. To me, you will be unique in all the world. To you, I shall +be unique in all the world...” + +“I am beginning to understand,” said the little prince. “There is a flower... I think that she has +tamed me...” + +“It is possible,” said the fox. “On the Earth one sees all sorts of things.” + +“Oh, but this is not on the Earth!” said the little prince. The fox seemed perplexed, and very +curious. + +“On another planet?” + +“Yes.” + +“Are there hunters on this planet?” + +“No.” + +“Ah, that is interesting! Are there chickens?” + +“No.” + +“Nothing is perfect,” sighed the fox. But he came back to his idea. “My life is very monotonous,” +the fox said. “I hunt chickens; men hunt me. All the chickens are just alike, and all the men are +just alike. And, in consequence, I am a little bored. But if you tame me, it will be as if the sun +came to shine on my life. I shall know the sound of a step that will be different from all the others. +Other steps send me hurrying back underneath the ground. Yours will call me, like music, out of +my burrow. And then look: you see the grain-fields down yonder? I do not eat bread. Wheat is of +no use to me. The wheat fields have nothing to say to me. And that is sad. But you have hair that +is the colour of gold. Think how wonderful that will be when you have tamed me! The grain, which +is also golden, will bring me back the thought of you. And I shall love to listen to the wind in the +wheat...” The fox gazed at the little prince, for a long time. “Please, tame me!” he said. + +“I want to, very much,” the little prince replied. “But I have not much time. I have friends to +discover, and a great many things to understand.” + +“One only understands the things that one tames,” said the fox. “Men have no more time to +understand anything. They buy things all ready-made at the shops. But there is no shop anywhere +where one can buy friendship, and so men have no friends any more. If you want a friend, tame +me...” + +“What must I do, to tame you?” asked the little prince. + +“You must be very patient,” replied the fox. “First you will sit down at a little distance from me, +like that, in the grass. I shall look at you out of the corner of my eye, and you will say nothing. +Words are the source of misunderstandings. But you will sit a little closer to me, every day...” + + + + +The next day the little prince came back. + + + +“It would have been better to come back at the same hour,” said the fox. “If, for example, you +come at four o’clock in the afternoon, then at three o’clock I shall begin to be happy. I shall feel +happier and happier as the hour advances. At four o’clock, I shall already be worrying and +jumping about. I shall show you how happy I am! But if you come at just any time, I shall never +know at what hour my heart is to be ready to greet you... One must observe the proper rites...” + +“What is a rite?” asked the little prince. + +“Those also are actions too often neglected,” said the fox. “They are what make one day +different from other days, one hour from other hours. There is a rite, for example, among my +hunters. Every Thursday they dance with the village girls. So Thursday is a wonderful day for me! +I can take a walk as far as the vineyards. But if the hunters danced at just any time, every day +would be like every other day, and I should never have any vacation at all.” + +So the little prince tamed the fox. And when the hour of his departure drew near... + +“Ah,” said the fox, “I shall cry.” + +“It is your own fault,” said the little prince. “I never wished you any sort of harm; but you wanted +me to tame you...” + +“Yes, that is so,” said the fox. + +“But now you are going to cry!” said the little prince. + +“Yes, that is so,” said the fox. + +“Then it has done you no good at all!” + +“It has done me good,” said the fox, “because of the colour of the wheat fields.” And then he +added: “Go and look again at the roses. You will understand now that yours is unique in all the +world. Then come back to say goodbye to me, and I will make you a present of a secret.” + +The little prince went away, to look again at the roses. “You are not at all like my rose,” he said. +“As yet you are nothing. No one has tamed you, and you have tamed no one. You are like my fox +when I first knew him. He was only a fox like a hundred thousand other foxes. But I have made +him my friend, and now he is unique in all the world.” And the roses were very much embarrassed. +“You are beautiful, but you are empty,” he went on. “One could not die for you. To be sure, an +ordinary passer-by would think that my rose looked just like you, the rose that belongs to me. But +in herself alone she is more important than all the hundreds of you other roses: because it is she +that I have watered; because it is she that I have put under the glass globe; because it is she that +I have sheltered behind the screen; because it is for her that I have killed the caterpillars (except +the two or three that we saved to become butterflies); because it is she that I have listened to, +when she grumbled, or boasted, or even sometimes when she said nothing. Because she is my +rose. + +And he went back to meet the fox. “Goodbye,” he said. + +“Goodbye,” said the fox. “And now here is my secret, a very simple secret: It is only with the +heart that one can see rightly; what is essential is invisible to the eye.” + + + + +“What is essential is invisible to the eye,” the little prince repeated, so that he would be sure to +remember. + +“It is the time you have wasted for your rose that makes your rose so important.” + +“It is the time I have wasted for my rose...” said the little prince, so that he would be sure to +remember. + +“Men have forgotten this truth,” said the fox. “But you must not forget it. You become +responsible, forever, for what you have tamed. You are responsible for your rose...” + +“I am responsible for my rose,” the little prince repeated, so that he would be sure to remember. + +“Good morning,” said the little prince. + +“Good morning,” said the railway switchman. + +“What do you do here?” the little prince asked. + +“I sort out travellers, in bundles of a thousand,” said the switchman. “I send off the trains that +carry them; now to the right, now to the left.” And a brilliantly lighted express train shook the +switchman’s cabin as it rushed by with a roar like thunder. + +“They are in a great hurry,” said the little prince. “What are they looking for?” + +“Not even the locomotive engineer knows that,” said the switchman. And a second brilliantly +lighted express thundered by, in the opposite direction. + +“Are they coming back already?” demanded the little prince. “These are not the same ones,” said +the switchman. “It is an exchange.” + +“Were they not satisfied where they were?” asked the little prince. + +“No one is ever satisfied where he is,” said the switchman. And they heard the roaring thunder of +a third brilliantly lighted express. + +“Are they pursuing the first travellers?” demanded the little prince. + +“They are pursuing nothing at all,” said the switchman. “They are asleep in there, or if they are +not asleep they are yawning. Only the children are flattening their noses against the +windowpanes.” + +“Only the children know what they are looking for,” said the little prince. + +“They waste their time over a rag doll and it becomes very important to them; and if anybody +takes it away from them, they cry...” “They are lucky,” the switchman said. + +“Good morning,” said the little prince. + +“Good morning,” said the merchant. + +This was a merchant who sold pills that had been invented to quench thirst. You need only swallow +one pill a week, and you would feel no need of anything to drink. + + + + +“Why are you selling those?” asked the little prince. + + + +“Because they save a tremendous amount of time,” said the merchant. “Computations have been +made by experts. With these pills, you save fifty-three minutes in every week.” + +“And what do I do with those fifty-three minutes?” + +“Anything you like...” + +“As for me,” said the little prince to himself, “if I had fifty-three minutes to spend as I liked, I +should walk at my leisure toward a spring of fresh water.” + +It was now the eighth day since I had had my accident in the desert, and I had listened to the story +of the merchant as I was drinking the last drop of my water supply. + +“Ah,” I said to the little prince, “these memories of yours are very charming; but I have not yet +succeeded in repairing my plane; I have nothing more to drink; and I, too, should be very happy if +I could walk at my leisure toward a spring of fresh water!” + +“My friend the fox...” the little prince said to me. + +“My dear little man, this is no longer a matter that has anything to do with the fox!” + +“Why not?” + +“Because I am about to die of thirst...” + +He did not follow my reasoning, and he answered me: “It is a good thing to have had a friend, +even if one is about to die. I, for instance, am very glad to have had a fox as a friend...” + +“He has no way of guessing the danger,” I said to myself. “He has never been either hungry or +thirsty. A little sunshine is all he needs...” + +But he looked at me steadily, and replied to my thought: “I am thirsty, too. Let us look for a +well...” I made a gesture of weariness. It is absurd to look for a well, at random, in the immensity +of the desert. But nevertheless we started walking. + +When we had trudged along for several hours, in silence, the darkness fell, and the stars began to +come out. Thirst had made me a little feverish, and I looked at them as if I were in a dream. The +little prince’s last words came reeling back into my memory: “Then you are thirsty, too?” I +demanded. But he did not reply to my question. He merely said to me: “Water may also be good +for the heart...” + +I did not understand this answer, but I said nothing. I knew very well that it was impossible to +cross-examine him. He was tired. He sat down. I sat down beside him. And, after a little silence, +he spoke again: “The stars are beautiful, because of a flower that cannot be seen.” + +I replied, “Yes, that is so.” And, without saying anything more, I looked across the ridges of sand +that were stretched out before us in the moonlight. + +“The desert is beautiful,” the little prince added. + +And that was true. I have always loved the desert. One sits down on a desert sand dune, sees + + + + + +nothing, hears nothing. Yet through the silence something throbs, and gleams... + +“What makes the desert beautiful,” said the little prince, “is that somewhere it hides a well...” + +I was astonished by a sudden understanding of that mysterious radiation of the sands. When I was +a little boy I lived in an old house, and legend told us that a treasure was buried there. To be sure, +no one had ever known how to find it; perhaps no one had ever even looked for it. But it cast an +enchantment over that house. My home was hiding a secret in the depths of its heart... “Yes,” I +said to the little prince. “The house, the stars, the desert — what gives them their beauty is +something that is invisible!” + +“I am glad,” he said, “that you agree with my fox.” As the little prince dropped off to sleep, I took +him in my arms and set out walking once more. I felt deeply moved, and stirred. It seemed to me +that I was carrying a very fragile treasure. It seemed to me, even, that there was nothing more +fragile on all Earth. In the moonlight I looked at his pale forehead, his closed eyes, his locks of +hair that trembled in the wind, and I said to myself: + +“What I see here is nothing but a shell. What is most important is invisible...” + +As his lips opened slightly with the suspicious of a half-smile, I said to myself, again: “What +moves me so deeply, about this little prince who is sleeping here, is his loyalty to a flower — the +image of a rose that shines through his whole being like the flame of a lamp, even when he is +asleep...” + +And I felt him to be more fragile still. I felt the need of protecting him, as if he himself were a +flame that might be extinguished by a little puff of wind... And, as I walked on so, I found the well, +at daybreak. + +“Men,” said the little prince, “set out on their way in express trains, but they do not know what +they are looking for. Then they rush about, and get excited, and turn round and round...” And he +added: “It is not worth the trouble...” + + + +The well that we had come to was not like the wells of the Sahara. The wells of the Sahara are +mere holes dug in the sand. This one was like a well in a village. But there was no village here, +and I thought I must be dreaming... + +“It is strange,” I said to the little prince. “Everything is ready for use: the pulley, the bucket, the +rope...” He laughed, touched the rope, and set the pulley to working. And the pulley moaned, like +an old weathervane, which the wind has long since forgotten. + +“Do you hear?” said the little prince. “We have wakened the well, and it is singing...” + +I did not want him to tire himself with the rope. + +“Leave it to me,” I said. “It is too heavy for you.” I hoisted the bucket slowly to the edge of the +well and set it there, happy, tired as I was, over my achievement. The song of the pulley was still +in my ears, and I could see the sunlight shimmer in the still trembling water. + +“I am thirsty for this water,” said the little prince. “Give me some of it to drink...” + +And I understood what he had been looking for. I raised the bucket to his lips. He drank, his eyes +closed. It was as sweet as some special festival treat. This water was indeed a different thing from +ordinary nourishment. Its sweetness was born of the walk under the stars, the song of the pulley, +the effort of my arms. It was good for the heart, like a present. When I was a little boy, the lights +of the Christmas tree, the music of the Midnight Mass, the tenderness of smiling faces, used to +make up, so, the radiance of the gifts I received. + +“The men where you live,” said the little prince, “raise five thousand roses in the same garden +and they do not find in it what they are looking for.” + +“They do not find it,” I replied. + +“And yet what they are looking for could be found in one single rose, or in a little water.” + +“Yes, that is true,” I said. + +And the little prince added: “But the eyes are blind. One must look with the heart...” + +I had drunk the water. I breathed easily. At sunrise the sand is the colour of honey. And that +honey colour was making me happy, too. What brought me, then, this sense of grief? + +“You must keep your promise,” said the little prince, softly, as he sat down beside me once more. +“What promise?” “You know, a muzzle for my sheep... I am responsible for this flower...” + +I took my rough drafts of drawings out of my pocket. The little prince looked them over, and +laughed as he said: + +“Your baobabs, they look a little like cabbages.” + +“Oh!” I had been so proud of my baobabs! “Your fox, his ears look a little like horns; and they are +too long.” And he laughed again. + +“You are not fair, little prince,” I said. “I don’t know how to draw anything except boa constrictors +from the outside and boa constrictors from the inside.” + + + + + +“Oh, that will be all right,” he said, “children understand.” + +So then I made a pencil sketch of a muzzle. And as I gave it to him my heart was torn. + +“You have plans that I do not know about,” I said. But he did not answer me. He said to me, +instead: “You know, my descent to the earth... Tomorrow will be its anniversary.” Then, after a +silence, he went on: “I came down very near here.” And he flushed. + +And once again, without understanding why, I had a queer sense of sorrow. One question, +however, occurred to me: “Then it was not by chance that on the morning when I first met you — a +week ago — you were strolling along like that, all alone, a thousand miles from any inhabited +region? You were on the your way back to the place where you landed?” + +The little prince flushed again. And I added, with some hesitancy: “Perhaps it was because of the +anniversary?” The little prince flushed once more. He never answered questions, but when one +flushes does that not mean “Yes”? + +“Ah,” I said to him, “I am a little frightened...” + +But he interrupted me. “Now you must work. You must return to your engine. I will be waiting for +you here. Come back tomorrow evening...” + +But I was not reassured. I remembered the fox. One runs the risk of weeping a little, if one lets +himself be tamed... + +Beside the well there was the ruin of an old stone wall. When I came back from my work, the next +evening, I saw from some distance away my little prince sitting on top of a wall, with his feet +dangling. And I heard him say: “Then you don’t remember. This is not the exact spot.” Another +voice must have answered him, for he replied to it: “Yes, yes! It is the right day, but this is not the +place.” + +I continued my walk toward the wall. At no time did I see or hear anyone. The little prince, +however, replied once again: “...Exactly. You will see where my track begins, in the sand. You have +nothing to do but wait for me there. I shall be there tonight.” + + + +I was only twenty metres from the wall, and I still saw nothing. After a silence the little prince +spoke again: “You have good poison? You are sure that it will not make me suffer too long?” I +stopped in my tracks, my heart torn asunder; but still I did not understand. “Now go away,” said +the little prince. “I want to get down from the wall.” + +I dropped my eyes, then, to the foot of the wall... and I leaped into the air. There before me, facing +the little prince, was one of those yellow snakes that take just thirty seconds to bring your life to +an end. Even as I was digging into my pocked to get out my revolver I made a running step back. +But, at the noise I made, the snake let himself flow easily across the sand like the dying spray of +a fountain, and, in no apparent hurry, disappeared, with a light metallic sound, among the stones. I +reached the wall just in time to catch my little man in my arms; his face was white as snow. + +“What does this mean?” I demanded. “Why are you talking with snakes?” + +I had loosened the golden muffler that he always wore. I had moistened his temples, and had +given him some water to drink. And now I did not dare ask him any more questions. He looked at +me very gravely, and put his arms around my neck. I felt his heart beating like the heart of a +dying bird, shot with someone’s rifle... + +“I am glad that you have found what was the matter with your engine,” he said. “Now you can go +back home” + +“How do you know about that?” I was just coming to tell him that my work had been successful, +beyond anything that I had dared to hope. + +He made no answer to my question, but he added: “I, too, am going back home today...” Then, +sadly, “It is much farther... it is much more difficult...” I realised clearly that something +extraordinary was happening. I was holding him close in my arms as if he were a little child; and +yet it seemed to me that he was rushing headlong toward an abyss from which I could do nothing +to restrain him... His look was very serious, like some one lost far away. + +“I have your sheep. And I have the sheep’s box. And I have the muzzle...” + +And he gave me a sad smile. I waited a long time. I could see that he was reviving little by little. + +“Dear little man,” I said to him, “you are afraid...” He was afraid, there was no doubt about that. +But he laughed lightly. + +“I shall be much more afraid this evening...” + +Once again I felt myself frozen by the sense of something irreparable. And I knew that I could not +bear the thought of never hearing that laughter any more. For me, it was like a spring of fresh +water in the desert. + +“Little man,” I said, “I want to hear you laugh again.” But he said to me: “Tonight, it will be a +year... my star, then, can be found right above the place where I came to the Earth, a year ago...” + +“Little man,” I said, “tell me that it is only a bad dream, this affair of the snake, and the meeting- +place, and the star...” But he did not answer my plea. + +He said to me, instead: “The thing that is important is the thing that is not seen...” “Yes, I +know...” + + + + +“It is just as it is with the flower. If you love a flower that lives on a star, it is sweet to look at the +sky at night. All the stars are a-bloom with flowers...” + +“Yes, I know...” + +“It is just as it is with the water. Because of the pulley, and the rope, what you gave me to drink +was like music. You remember, how good it was.” + +“Yes, I know...” + +“And at night you will look up at the stars. Where I live everything is so small that I cannot show +you where my star is to be found. It is better, like that. My star will just be one of the stars, for +you. And so you will love to watch all the stars in the heavens... they will all be your friends. And, +besides, I am going to make you a present...” He laughed again. + +“Ah, little prince, dear little prince! I love to hear that laughter!” + +“That is my present. Just that. It will be as it was when we drank the water...” + +“What are you trying to say?” + +“All men have the stars,” he answered, “but they are not the same things for different people. For +some, who are travellers, the stars are guides. For others they are no more than little lights in the +sky. For others, who are scholars, they are problems. For my businessman they were wealth. But +all these stars are silent. You, you alone, will have the stars as no one else has them” + +“What are you trying to say?” + +“In one of the stars I shall be living. In one of them I shall be laughing. And so it will be as if all +the stars were laughing, when you look at the sky at night... you, only you, will have stars that can +laugh!” + +And he laughed again. “And when your sorrow is comforted (time soothes all sorrows) you will be +content that you have known me. You will always be my friend. You will want to laugh with me. And +you will sometimes open your window, so, for that pleasure... and your friends will be properly +astonished to see you laughing as you look up at the sky! Then you will say to them, ‘Yes, the +stars always make me laugh!’ And they will think you are crazy. It will be a very shabby trick that +I shall have played on you...” + +And he laughed again. “It will be as if, in place of the stars, I had given you a great number of +little bells that knew how to laugh...” + +And he laughed again. Then he quickly became serious: “Tonight, you know... do not come,” said +the little prince. + +“I shall not leave you,” I said. + +“I shall look as if I were suffering. I shall look a little as if I were dying. It is like that. Do not +come to see that. It is not worth the trouble...” + +“I shall not leave you.” + + + +But he was worried. “I tell you, it is also because of the snake. He must not bite you. Snakes, they + + + + +are malicious creatures. This one might bite you just for fun...” + + + +“I shall not leave you.” + +But a thought came to reassure him: “It is true that they have no more poison for a second bite.” + +That night I did not see him set out on his way. He got away from me without making a sound. +When I succeeded in catching up with him he was walking along with a quick and resolute step. He +said to me merely: “Ah! You are there...” And he took me by the hand. But he was still worrying. +“It was wrong of you to come. You will suffer. I shall look as if I were dead; and that will not be +true...” + +I said nothing. + +“You understand... it is too far. I cannot carry this body with me. It is too heavy.” + +I said nothing. + +“But it will be like an old abandoned shell. There is nothing sad about old shells...” + +I said nothing. He was a little discouraged. But he made one more effort: “You know, it will be +very nice. I, too, shall look at the stars. All the stars will be wells with a rusty pulley. All the stars +will pour out fresh water for me to drink...” + +I said nothing. + +“That will be so amusing! You will have five hundred million little bells, and I shall have five +hundred million springs of fresh water...” And he too said nothing more, because he was crying... + +“Here it is. Let me go on by myself.” And he sat down, because he was afraid. Then he said, +again: “You know, my flower... I am responsible for her. And she is so weak! She has four thorns, +of no use at all, to protect herself against all the world...” + +I too sat down, because I was not able to stand up any longer. “There now, that is all...” + +He still hesitated a little; then he got up. He took one step. I could not move. There was nothing +but a flash of yellow close to his ankle. He remained motionless for an instant. He did not cry out. +He fell as gently as a tree falls. There was not even any sound, because of the sand. + +And now six years have already gone by... I have never yet told this story. + +The companions who met me on my return were well content to see me alive. I was sad, but I told +them: “I am tired.” Now my sorrow is comforted a little. That is to say, not entirely. But I know +that he did go back to his planet, because I did not find his body at daybreak. It was not such a +heavy body... and at night I love to listen to the stars. It is like five hundred million little bells... +But there is one extraordinary thing... when I drew the muzzle for the little prince, I forgot to add +the leather strap to it. He will never have been able to fasten it on his sheep. + +So now I keep wondering: what is happening on his planet? Perhaps the sheep has eaten the +flower... At one time I say to myself: “Surely not! The little prince shuts his flower under her glass +globe every night, and he watches over his sheep very carefully...” Then I am happy. And there is +sweetness in the laughter of all the stars. + + + + +But at another time I say to myself: “At some moment or other one is absent-minded, and that is +enough! On some one evening he forgot the glass globe, or the sheep got out, without making any +noise, in the night...” And then the little bells are changed to tears... Here, then, is a great +mystery. + +For you who also love the little prince, and for me, nothing in the universe can be the same if +somewhere, we do not know where, a sheep that we never saw has eaten a rose... Look up at the +sky. Ask yourselves: is it yes or no? + +Has the sheep eaten the flower? And you will see how everything changes... And no grown-up will +ever understand that this is a matter of so much importance! This is, to me, the loveliest and +saddest landscape in the world. It is the same as that on the preceding page, but I have drawn it +again to impress it on your memory. It is here that the little prince appeared on Earth, and +disappeared. Look at it carefully so that you will be sure to recognise it in case you travel some +day to the African desert. And, if you should come upon this spot, please do not hurry on. Wait for +a time, exactly under the star. Then, if a little man appears who laughs, who has golden hair and +who refuses to answer questions, you will know who he is. If this should happen, please comfort +me. Send me word that he has come back. + + + +END diff --git a/perf/texts/en-words.txt b/perf/texts/en-words.txt new file mode 100644 index 0000000000000000000000000000000000000000..6ba78c0787466aeebb71cdf3a2151f8184012f57 --- /dev/null +++ b/perf/texts/en-words.txt @@ -0,0 +1,12391 @@ +a +A +aa +AA +aaa +AAA +aaae +AAAu +AAB +AAC +aacute +Aacute +Aacutesmall +AAD +aae +AAE +aaf +AAF +aalt +aao +aarch +Aari +aat +AAT +aatFeatureType +AAu +ab +AB +Abaza +abb +ABBREV +abc +ABC +abcde +abcdefghijklmnopqrstuvwxyz +ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +ABD +ABE +ABEu +ABF +ABFu +abh +ABI +ability +Abkhazian +able +Aboriginal +ABORIGINAL +abort +about +above +Above +ABOVE +abq +abs +absolute +absolutely +absorb +abstraction +abstractions +ABu +abuse +abv +ABVF +abvm +abvs +ABVS +ABx +ABxCD +ABxD +ac +AC +acb +ACBu +acc +ACC +accel +Accelerate +accelerator +ACCELERATOR +accels +accent +ACCENT +accents +accept +acceptable +accepted +accepting +accepts +access +Access +accessed +accessible +accessing +accessors +accommodate +Accommodate +accompanying +accomplish +according +According +account +accounting +ACCu +accumulate +Accumulate +accuracy +accurate +AccuT +ACDu +acf +ach +Achi +achieve +Acholi +achung +achVendID +acircumflex +Acircumflex +Acircumflexsmall +ack +acm +Acoli +acom +acq +ACQ +acquire +ACQUIRE +acr +across +act +action +Action +ACTION +actionable +actionClass +actionData +actionLength +actions +Actions +ActionSubrecord +ActionSubrecordHeader +actionType +ActionType +activated +activates +active +acts +actual +Actual +actualGlyphsCount +actually +ACu +acute +Acutesmall +acw +acx +acy +ad +AD +ada +Adamawa +Adangme +Adap +adapt +Adapted +Adaptors +aData +adb +ADBu +add +Add +addcnt +added +AddFontMemResourceEx +addGlyph +adding +Adding +addition +Addition +additional +Additional +additionalCount +additions +addr +AddRef +address +addressof +adds +ADDu +Adeni +adequate +adf +adieresis +Adieresis +Adieresissmall +Adilabad +adjacent +Adjacent +adjust +Adjust +adjusted +adjustment +adjustments +Adjusts +ADL +Adlam +ADLAM +adobe +Adobe +adopt +Adopted +adorned +adp +ADu +adv +advance +Advance +Advanced +advanceMax +advanceMeasurement +advanceOffset +advances +ADVANCES +Advancing +advantage +ADVISED +advMap +ady +Adyghe +ae +AE +aea +aeaf +aeb +aec +AEDu +AEEu +AEFu +Aegean +AEsmall +AEu +af +AF +afa +afadd +Afar +AFAu +afb +AFBAu +AFBu +AFDKO +AFEu +AFF +affect +affected +affecting +affects +affinity +Afghanistan +Africa +Afrikaans +after +After +AFTER +afterGrowLimit +afterShrinkLimit +AFu +AG +again +against +Agaw +Agfa +agnostic +agrave +Agrave +Agravesmall +agree +agreement +ahead +Aheri +ahg +Ahom +AHOM +aht +Ahtena +ai +AI +aii +AIN +aio +Aiton +aiw +AIX +ajp +ak +aka +AKA +Akan +AKAT +AKHN +alaph +ALAPH +alas +Alaska +Alaskan +Albania +Albanian +ALBANIAN +Albay +alef +Alef +ALEF +Algeria +Algerian +algorithm +Algorithm +algorithmic +algorithms +Algorithms +algs +ALGS +alias +aliased +aliases +aliasing +align +aligned +alignment +alignof +aligns +alive +all +All +ALL +ALLAH +AllDirections +Allison +alloc +Alloc +allocate +Allocate +ALLOCATE +allocated +allocates +allocating +allocation +Allocation +allocations +Allocations +allocator +allow +Allow +allowed +allowing +allows +almost +aln +alone +along +alpha +Alpha +alphabet +Alphabet +alphabetic +Alphabetic +alphabetical +alphabetically +Alphanumeric +Alphanumerics +already +als +Alsatian +also +Also +alt +ALT +Altai +alter +alternate +Alternate +ALTERNATE +alternates +ALTERNATES +alternateSet +AlternateSet +AlternateSubst +AlternateSubstFormat +alternative +Alternatively +ALTERNATIVES +although +Although +alts +always +Always +am +AM +ambiguity +ambiguous +Ambo +Amend +American +Americanist +amf +Amharic +among +amongst +amount +Amoy +amp +ampersand +ampersandsmall +amw +an +An +AN +Ana +analysis +Analysis +ANALYSIS +analyze +Analyze +analyzer +Analyzer +analyzers +Analyzes +AnalyzeScript +ANATOLIAN +Ancash +anchor +Anchor +anchorData +anchored +AnchorFormat +AnchorMatrix +anchorPoint +anchors +Ancient +and +And +AND +android +Android +ANDROID +ang +angle +Angle +ANGLE +Anglo +ankr +ANKR +ankrActionIndex +ankrData +annex +annotate +Annotated +annotation +ANNOTATION +annotations +another +Another +Ansi +Antankarana +Antillean +any +Any +ANY +anymore +anything +Anything +anyway +ap +Apache +apc +apd +Api +API +apis +APIs +apj +apk +apl +apm +APP +Apparently +appear +appearance +appearing +append +Append +APPEND +appended +appending +Appendix +AppendixF +Appends +Appl +APPL +apple +Apple +APPLE +AppleColorEmoji +applicable +Applicable +APPLICABLE +application +applications +Applications +ApplicationServices +applied +applies +apply +Apply +APPLY +applying +Applying +approach +approaches +appropriate +approxequal +approximate +appveyor +April +apt +Apurímac +apw +AQ +ar +Arabia +ARABIAN +arabic +Arabic +ARABIC +ArabicShaping +Aragonese +Arakanese +Arakwal +Aramaic +ARAMAIC +arb +Arbëreshë +arbitrarily +arbitrary +ARC +Archaic +architecturally +archive +archives +are +ARE +area +Area +Arequipa +arg +ARG +Argentina +Argh +args +ARGS +argStack +argument +arguments +aring +Aring +Aringsmall +ARISING +arith +arithmetic +Ariza +armcc +Armenia +Armenian +ARMENIAN +arn +Aromanian +around +arounds +Arpitan +arq +arr +arranged +array +Array +ARRAY +ArrayOf +ArrayOfM +arrays +arrayZ +arrive +Arrows +ars +Arsi +articles +Arvanitika +ary +arz +as +As +AS +Asat +ascender +ASCENDER +ascenderOffset +ascending +ascent +ASCENT +ascii +ASCII +asciicircum +asciitilde +Asho +Asian +aSize +asked +Asking +Asmall +Asomtavruli +aspect +aspects +aspx +Assamese +assembly +assert +ASSERT +assertion +ASSERTION +assign +Assign +ASSIGN +assignable +assigned +assigns +assistance +assisted +associated +associates +associating +Association +assume +Assume +assumed +Assumed +assuming +Assuming +assumption +Assumption +Assyrian +ast +asterisk +ASTERISK +Asturian +asuperior +at +At +atexit +ATEXIT +aTextPosition +ath +Athapascan +Athapaskan +Atikamekw +atilde +Atilde +Atildesmall +atj +Atlas +atleast +ATLEAST +atomic +Atomic +ATOMIC +Atomically +atomics +atsFont +ATSFontGetFileReference +ATSFontRef +attach +Attach +ATTACH +attached +ATTACHED +attaches +attaching +attachList +AttachList +attachment +Attachment +ATTACHMENT +attachments +attachPoint +AttachPoint +attempt +attempted +attempts +Attempts +attr +ATTR +attractive +attrib +attribute +ATTRIBUTE +attributed +attributes +Attributes +attrs +atv +au +Au +AU +audiences +augmented +Australia +Austria +Author +AUTHOR +authors +auto +AUTO +autoconf +autogen +automake +automatic +Automatic +automatically +auxiliary +Auxiliary +auz +av +AV +Avagraha +AVAGRAHA +avail +Availability +AvailabilityMacros +available +avar +Avar +AVAR +Avaric +AVESTAN +avl +avoid +Avoid +avoided +avoiding +avoids +aw +awa +Awa +Awadhi +aware +away +awful +ax +Ax +AxCD +AxD +axes +axesZ +axis +Axis +AXIS +axisCount +axisIndex +axisNameID +AxisRecord +axisSize +axisTag +AxisValue +axisValueCount +AxisValueFormat +AxisValueMap +AxisValueRecord +axisValues +ay +Ayacucho +ayc +ayh +AYIN +ayl +Aymara +ayn +ayp +ayr +az +azb +Azerbaijan +Azerbaijani +Azeri +azj +b +B +ba +BA +Babalia +Babine +BABu +Bacanese +back +backend +backends +background +Background +BACKGROUND +backing +backslash +backtrack +backtrackClassDef +backtrackCount +backtracking +backward +BACKWARD +backwards +Backwards +bad +Badaga +badly +BADLY +bae +BAEu +BAFu +Bagheli +Baghelkhandi +Bagirmi +Bagri +Baharna +Bahrain +bai +bail +Bakhtiari +bal +Balanta +Balante +Balinese +BALINESE +Balkan +Balkar +Balochi +Balti +Baltic +Baluchi +Bamanankan +Bambara +Bamileke +BAMUM +ban +Banda +Bandjalang +Bangka +Bangladesh +Bangun +Banjar +Banna +Baoulé +bar +Bara +BARREE +barrier +Barrier +bars +Bas +base +Base +BASE +baseArray +BaseArray +BaseCoord +BaseCoordFormat +baseCoords +baseCoverage +BaseCoverage +based +Based +BaseFontBlend +baseFontName +BaseFontName +BaseGlyph +BaseGlyphRecord +baseGlyphsZ +BaseLangSysRecord +baseLangSysRecords +BaseLangSysRecords +baseLangSysTag +baseline +Baseline +BASELINE +baselines +BaselineTableFormat +baselinetags +baselineTags +bases +baseScript +BaseScript +baseScriptList +BaseScriptList +BaseScriptRecord +baseScriptRecords +BaseScriptRecords +baseScriptTag +baseTagCount +baseTagList +BaseTagList +baseValues +BaseValues +Bashkir +basic +Basic +BASIC +basically +BASIS +Basque +BASSA +Batak +BATAK +batch +BAu +Baulé +Bavarian +Bawm +BB +BBAu +BBBu +bbc +bbee +BBEu +BBF +BBu +bbz +bc +BC +bca +BCA +BCAu +BCBu +bcc +BCCu +bcd +BCD +BCDu +BCEu +bci +bcl +bcp +BCP +bcq +bcr +BCu +bcursor +bd +BD +bdadd +bdfaab +bdu +BDu +bdy +be +Be +BE +bea +BEAM +bearing +bearings +bearingX +bearingY +Beaver +beb +Bebele +Bebil +bec +because +Because +become +BECOME +becomes +bed +Bedawi +BEEH +been +BEEN +BEEu +before +Before +BEFORE +beforeGrowLimit +beforehand +beforeShrinkLimit +BeforeSub +began +begin +BEGIN +beginning +Beginning +BEH +behave +behaved +behaving +behavior +behaviors +behaviour +Behdad +BEHEH +behind +Bei +being +Being +BEInt +Belarus +Belarusian +Belarussian +Belgium +Belize +belong +belonging +belongs +below +Below +BELOW +bem +Bemba +Bench +bend +benefits +BENG +Bengali +BENGALI +ber +Berau +Berber +best +Bet +BET +Beti +bets +Betsimisaraka +better +between +BEu +beyond +bf +BF +bfaeafe +BFAu +bfb +BFF +bffc +BFFu +bfind +BFIND +bfq +bft +bfu +BFu +bfy +bg +bgc +bgn +bgp +bgq +bgr +BGRAColor +Bhaiksuki +BHAIKSUKI +Bhasha +bhb +bhi +Bhilali +Bhili +bhk +bho +Bhojpuri +bhr +bi +Bi +bias +biased +biasedSubrs +Bible +Bicolano +bidi +bidirectional +BiDirectional +bidirectionality +big +Big +BIG +BigGlyphMetrics +bik +Bikol +BILD +Bilen +Bilin +billion +bimap +BIMAP +bin +binaries +binary +Binary +BINARY +bindings +Bindu +BINDU +Bindus +BinSearchArrayOf +BinSearchHeader +Bishnupriya +Bislama +bit +Bit +bitcount +bitDepth +bitfield +bithacks +Bithacks +bitmap +Bitmap +BITMAP +bitmaps +BitmapSizeTable +bits +Bits +BITS +BitScanForward +BitScanReverse +bitset +bitsize +bitwise +bjj +bjn +BJN +bjq +bjt +bl +BL +bla +black +Black +BLACK +Blackfoot +blackhole +blacklist +BLACKLIST +blacklisted +blacklisting +Blas +ble +blend +Blend +BLEND +blendcs +blenddict +blended +blending +BlendInterpEnv +blends +Blink +blk +bln +blob +BLOB +blobs +Blobs +block +Block +BLOCK +blocked +Blocked +blocks +Blocks +Bloom +blow +blown +blue +Blue +BlueFuzz +BlueScale +BlueShift +BlueValues +blwf +BLWF +blwm +blws +BLWS +bm +bmg +bmm +bmp +BMP +bn +bo +Bodo +body +bok +Bokmal +Bokmål +bold +Bold +BOLD +bolder +Bolivia +Bolivian +book +Book +bookbold +bookkeeping +bool +BOOL +Boolean +Booleans +BOOM +Bopomofo +BOPOMOFO +Borana +BORDERS +Borgu +Borrowed +Bosnia +Bosnian +BOT +both +bother +bottom +Bottom +BOTTOM +bottomSide +bound +Bound +boundaries +boundary +Boundary +bounding +bounds +Bounds +BOUNDS +Bouyei +box +Box +BOX +boxed +BOXED +boxes +bpy +bqi +br +BR +bra +braceleft +braceright +braces +Bracket +BRACKET +bracketleft +bracketright +Brahmi +BRAHMI +Brahui +Braille +BRAILLE +Braj +branches +brand +Brawer +Brazil +break +BREAK +breakfast +breaking +breakpoint +BREAKPOINT +breaks +bretagne +Breton +breve +Brevesmall +brew +brh +brief +broken +Broken +brokenbar +Brunei +Bruno +bruteforce +brx +bs +bsb +bsearch +bsk +bsln +BSLN +Bsmall +bsuperior +bswap +btb +btj +bto +bts +btt +BTT +bu +Bu +Bualkhaw +Bubble +bucket +buf +buff +buffArray +buffer +Buffer +BUFFER +buffers +Buffers +BUFSIZ +bug +BUG +buggy +Buginese +BUGINESE +Bugis +bugs +bugzilla +Buhi +Buhid +BUHID +build +builder +Builder +building +Building +builds +built +builtin +BUILTIN +builtins +Bukit +Bukusu +Bulgaria +Bulgarian +bulk +bullet +Bulu +bum +Bumthangkha +bundles +burden +Buriat +Burmese +Burushaski +business +but +But +BUT +BV +bve +bvu +bxk +bxp +bxr +by +By +BY +Byagowi +Byelorussian +byes +byn +byte +Byte +BYTE +byteArray +byteOffsetToIndex +bytes +Bytes +BYTES +bytesArray +bytesX +bytesZ +byv +Byzantine +bzc +c +C +ca +Ca +CA +CABu +caca +cache +Cache +CACHE +cacheable +cached +caches +caching +Caching +cacute +Cacute +caf +cairo +Cairo +cairographics +Cajamarca +Cajatambo +Cajun +cak +calcOffSize +CalcTableChecksum +calculate +Calculate +calculated +calculates +calculation +Calderón +Calibry +call +Call +callback +Callback +callbacks +CALLBACKS +called +Called +caller +callers +callgsubr +calling +calloc +calls +Calls +callStack +callsubr +calt +Cambodia +Cameroon +Campidanese +can +Can +Canada +Canadian +CANADIAN +Cañar +CANCEL +candidate +candidates +cannot +Cannot +canon +canonical +Canonical +CANONICAL +canonically +cantarell +Cantarell +Cantillation +CANTILLATION +cap +Cap +CAP +capabilities +capable +capital +CAPS +care +careful +carefully +caret +Caret +CARET +caretOffset +carets +caretSlopeDenominator +caretSlopeNumerator +caretSlopeRise +caretSlopeRun +CaretValue +caretValueFormat +CaretValueFormat +caretValuePoint +Carian +CARIAN +Caribbean +caron +Caronsmall +Carpathian +Carrier +carry +cas +cascade +cascading +case +CASE +cases +cast +Cast +casting +casts +Casts +cat +Cat +CAT +Catalan +Catanduanes +catch +categories +Categories +CATEGORIES +categorization +categorize +categorized +categorizes +category +Category +CATEGORY +Cateories +CAu +CAUCASIAN +cause +caused +causes +causing +cautious +cb +CB +cbb +CBCu +cbdt +CBDT +CBEu +CBFu +cbk +cbl +cblc +CBLC +CBu +cc +Cc +CC +ccaron +Ccaron +CCAu +CCBu +ccc +CCC +ccccae +cccf +CCCu +CCD +CCDu +ccedilla +Ccedilla +Ccedillasmall +CCEu +cChars +ccmp +cco +ccq +CCu +cd +CD +CDATA +cdd +cdo +CDu +CDx +CDxA +CDxAB +CDxBA +ce +CE +ceb +Cebuano +CECu +cedilla +Cedillasmall +CEDu +CEEu +ceil +CEIL +cent +center +Center +centered +CENTERED +centinferior +centoldstyle +CentOS +central +Central +centsuperior +ceparams +certain +Certain +CEu +cf +Cf +CF +cfar +CFAR +CFArrayAppendValue +CFArrayCreate +CFArrayCreateMutable +CFArrayGetCount +CFArrayGetValueAtIndex +CFArrayRef +CFAttributedStringCreateMutable +CFAttributedStringRemoveAttribute +CFAttributedStringReplaceString +CFAttributedStringSetAttribute +CFComparisonResult +cfd +CFData +CFDataGetBytePtr +CFDataGetLength +CFDataRef +CFDictionaryCreate +CFDictionaryGetValue +CFDictionaryRef +CFDu +CFEqual +cff +CFF +cfff +CFFIndex +CFFIndexOf +CFFTag +CFFu +CFIndex +cfm +CFMutableArrayRef +CFMutableAttributedStringRef +CFNumberCreate +CFNumberRef +CFRange +CFRangeMake +CFRelease +CFRetain +CFSTR +CFStringCompare +CFStringCreateWithCharactersNoCopy +CFStringCreateWithCStringNoCopy +CFStringGetCharacterAtIndex +CFStringHasPrefix +CFStringHasSuffix +CFStringRef +CFu +CFURLCreateFromFSRef +CFURLRef +cg +CGDataProviderCreateWithData +CGDataProviderRef +CGDataProviderRelease +CGFloat +CGFont +CGFontCopyPostScriptName +CGFontCopyTableForTag +CGFontCreateWithDataProvider +CGFontRef +CGFontRelease +CGFontRetain +cgg +CGGlyph +cgi +cgit +CGJ +cGlyphs +CGPoint +ch +Chachapoyas +Chadian +Chaha +chain +Chain +chainContext +ChainContext +ChainContextApplyLookupContext +ChainContextClosureLookupContext +ChainContextCollectGlyphsLookupContext +ChainContextFormat +ChainContextPos +ChainContextSubst +chainCount +chaining +Chaining +ChainRule +ChainRuleSet +chains +Chains +ChainSubtable +Chakma +CHAKMA +Chaldean +Cham +CHAM +Chamorro +chance +chandas +change +Change +changed +changes +Changes +changing +channel +channels +Chap +chapter +Chapter +char +Char +CHAR +character +Character +CHARACTER +characterCode +characterize +characters +Characters +CHARACTERS +characterVariants +charmap +Charmap +charMirror +CHARPROP +chars +charset +Charset +CHARSET +CharsetID +charsetInfo +CharsetOffset +charstreing +charstring +CharString +charstrings +charStrings +CharStrings +charStringsInfo +charStringsOffset +CharstringType +charts +chattawa +CHATTAWA +Chattisgarhi +Chaungtha +Chavacano +cheaper +Chechen +check +Check +CHECK +checked +CHECKED +checking +Checking +checks +Checks +checksum +checkSum +CheckSum +checkSumAdjustment +Cherokee +CHEROKEE +Chetco +Chewa +Cheyenne +Chhattisgarhi +Chichewa +Chiga +Chiki +CHIKI +Chilcotin +child +children +Chile +Chilean +Chillus +Chiltepec +Chimborazo +Chin +China +Chinantec +Chinbon +Chincha +Chinese +Chipewyan +Chippewa +Chiquián +Chiricahua +Chiripá +Chittagonian +chj +chk +CHL +cho +Choctaw +choice +choices +choose +Choose +chooses +choosing +chop +Chop +chosen +CHOSEONG +chp +chq +chr +chris +Chris +chromium +Chromium +Chuanqiandian +Chukchi +Chukot +chunk +ChunkLen +chunks +Church +Chuukese +Chuvash +chy +chz +ci +CI +CID +cidCount +CIDCount +CIDFontRevision +CIDFontType +CIDFontVersion +CIN +cInChars +CIP +circle +CIRCLE +circles +circuit +CIRCUIT +circumflex +Circumflexsmall +circumstances +circumvents +citer +CITI +ciw +cja +CJCT +CJK +cjm +cjy +ck +CK +cka +ckb +ckt +cl +Clamp +clang +clarity +Clasen +class +Class +CLASS +classArray +classCount +classDef +ClassDef +ClassDefFormat +classes +classFormat +Classic +Classical +classifications +classified +classify +classTable +ClassTable +ClassType +ClassTypeNarrow +ClassTypeWide +classValue +classValueArray +clc +cld +cle +clean +Clean +cleanest +clear +Clear +cleared +clearing +clearly +clears +Clears +ClearType +ClearType™ +client +Client +clients +Clients +clig +clipping +CLIPPING +clockwise +close +Close +CLOSE +CloseHandle +closely +closer +closest +CLOSEST +closure +Closure +CLOSURE +closures +cluster +Cluster +CLUSTER +clustering +clusterMap +clusters +Clusters +CLUSTERS +clz +clzl +clzll +CM +CMAbv +cmake +cmap +CMAP +cmapsubtable +CmapSubtable +CmapSubtableFormat +CmapSubtableLongGroup +CmapSubtableLongSegmented +CmapSubtableTrimmed +cMaxGlyphs +cMaxItems +CMBlw +cmn +cmp +cmpexch +cmplexch +cmpswap +cmr +cn +Cn +cnb +cnh +cnk +cnl +cnt +cntrmask +cnw +co +Co +coa +Cocos +code +Code +CODE +codebase +coded +codepath +codepoint +CODEPOINT +codepoints +codepont +codes +Codethink +Coeng +COENG +coengs +col +Col +collect +Collect +COLLECT +collected +collection +Collection +collections +Collections +collects +Colombia +colon +COLON +colonmonetary +color +Color +COLOR +colorIdx +colorLabelsZ +ColorRecord +colorRecordIndicesZ +colorRecordsZ +colorRef +colors +colorType +Colour +colr +COLR +cols +COLS +columnCount +columnIndexTable +com +Comaltepec +combination +combinations +combine +COMBINE +combined +combiner +combiners +combining +Combining +COMBINING +come +comes +comfortably +coming +comma +COMMA +commainferior +command +Command +commands +commas +commasuperior +comment +Commenting +comments +commit +commitcomment +commits +common +Common +COMMON +commonly +Comorian +comp +compact +Compact +compar +compare +Compare +compared +compares +comparing +Comparing +comparison +compat +compatibility +Compatibility +COMPATIBILITY +compatible +COMPATIBLE +compensate +compilable +compile +Compile +compiled +compiler +Compiler +compilers +compiles +COMPILES +compiling +complains +complang +Complement +complete +Complete +completely +complex +Complex +COMPLEX +COMPLEXITY +complicated +component +COMPONENT +componentData +ComponentGlyph +components +Components +COMPONENTS +ComponentsArray +composable +compose +composed +COMPOSED +composePair +composes +Composes +composing +composite +COMPOSITE +CompositeGlyph +CompositeGlyphChain +composites +composition +Composition +COMPOSITION +COMPOUND +compressed +compressionMethod +comprise +comprising +comps +compute +Compute +Computes +computing +concepts +Concepts +conceptual +Conceptually +concern +concerned +Conchucos +cond +Cond +condensed +Condensed +CONDENSED +condition +Condition +conditional +conditionalAddGlyphAction +ConditionalAddGlyphAction +conditionally +ConditionFormat +conditions +Conditions +ConditionSet +config +CONFIG +configs +configuration +Configuration +configurations +configure +configured +conflicting +confused +confusing +Congo +conjunct +connect +CONNECT +connected +CONNECTED +connecting +connection +CONNECTION +connector +CONNECTOR +Cons +CONS +consecutive +CONSEQUENTIAL +Consequently +consider +Consider +considerably +consideration +considerations +considered +consist +consistent +consists +consonant +Consonant +CONSONANT +consonants +const +CONST +constant +CONSTANT +constants +Constants +constexpr +constituent +constitute +constitutes +constraints +CONSTRAINTS +construct +constructed +constructible +construction +constructor +constructors +Constructors +constructs +consult +consumed +contain +contained +container +containers +containing +contains +ContainsTextPosition +contemporary +content +CONTENT +contents +context +Context +CONTEXT +ContextApplyFuncs +ContextApplyLookupContext +ContextClosureFuncs +ContextClosureLookupContext +ContextCollectGlyphsFuncs +ContextCollectGlyphsLookupContext +ContextFormat +ContextPos +contexts +ContextSubst +contextual +Contextual +CONTEXTUAL +ContextualSubtable +contiguous +continuation +CONTINUATION +continuations +continue +continues +contour +Contour +contours +contract +CONTRACT +contrary +contrast +contributing +Contributor +control +Control +CONTROL +controlling +controls +convenience +conveniences +convenient +conventions +Conversely +conversion +Conversion +Conversions +convert +Convert +converted +Converted +converters +convertible +converting +Converts +convoluted +coord +coordinate +Coordinate +coordinates +Coordinates +COORDINATES +coordinatesZ +coordPoint +coords +coorinates +cop +copied +Copied +copies +Copies +Coptic +COPTIC +copy +Copy +COPY +copyable +copying +copyright +Copyright +COPYRIGHT +coq +Coquille +core +CoreGraphics +coretext +CoreText +CORETEXT +corner +CORNER +corners +Cornish +Corongo +correct +correction +correctionHeight +correctly +Correctly +correctness +correlate +correspond +corresponding +corresponds +corrupt +Corsican +cost +Costa +costs +costy +cotfRecords +could +Could +count +Count +COUNT +countChar +counted +counter +counting +Counting +CountMask +countries +counts +couple +Courier +course +courtesy +cover +coverage +Coverage +COVERAGE +coverageFormat +CoverageFormat +coverageZ +covered +COVERED +covering +covers +cp +CP +cpa +cpal +CPAL +CPALV +cpe +cpf +cplusplus +cpp +cppreference +CPR +CPrf +cpx +cqd +cqu +cr +CRAMPED +cRanges +crap +Crap +CRAP +CrapHelper +CrapOrNull +CrapOrNullHelper +CrapPool +crash +crashes +crazy +crbug +create +Create +CREATE +CreateCustomFontFileReference +created +CreateFile +CREATEFILE +CreateFileMapping +CreateFileMappingFromApp +CreateFileW +CreateFontFace +CreateFontIndirectW +creates +Creates +CreateStreamFromKey +CreateTextAnalyzer +creating +Creating +creation +creator +Cree +Creek +Creole +creoles +Creoles +crh +Crimean +Crioulo +criteria +CRITICAL +crj +crk +crl +crm +Croatia +Croatian +cross +Cross +crossStream +CrossStream +crp +crucial +crx +cs +Cs +CS +csa +csb +csh +Csmall +cso +csop +CSOPSET +CSR +CSS +CSType +csw +cswh +csy +ct +ctc +ctd +cte +CTFont +CTFontCopyAttribute +CTFontCopyGraphicsFont +CTFontCopyName +CTFontCopyPostScriptName +CTFontCreateCopyWithAttributes +CTFontCreateUIFontForLanguage +ctfontcreatewithgraphicsfont +CTFontCreateWithGraphicsFont +CTFontDescriptorCreateWithAttributes +CTFontDescriptorCreateWithNameAndSize +CTFontDescriptorRef +CTFontGetPlatformFont +CTFontGetSize +CTFontRef +CTFontUIFontType +ctg +CTGetCoreTextVersion +ctl +CTLineGetGlyphRuns +CTLineGetTrailingWhitespaceWidth +CTLineRef +ctlPoints +ctor +CTRunGetAttributes +CTRunGetGlyphCount +CTRunGetGlyphs +CTRunGetGlyphsPtr +CTRunGetPositions +CTRunGetPositionsPtr +CTRunGetStatus +CTRunGetStringIndices +CTRunGetStringIndicesPtr +CTRunGetStringRange +CTRunGetTypographicBounds +CTRunRef +CTRunStatus +cts +CTTypesetterCreateLine +CTTypesetterCreateWithAttributedStringAndOptions +CTTypesetterRef +CTYPE +ctz +ctzl +ctzll +cu +Cu +cuc +cuk +cumulated +Cumulative +Cuneiform +CUNEIFORM +cur +curEntry +Curiously +CURISVE +CURLY +curr +curradv +curradvx +curradvy +currAnchor +currAnchorPoint +currclus +currControlPoint +currency +Currency +CURRENCY +current +Current +CurrentCategory +currentIndex +currentInsertBefore +CurrentInsertBefore +currentInsertCount +CurrentInsertCount +currentInsertIndex +currentInsertList +CurrentIsKashidaLike +currently +Currently +currX +currY +curs +cursive +Cursive +CURSIVE +CursivePos +CursivePosFormat +cursor +Cursor +cursoring +curve +CURVE +Cusco +custom +Custom +customization +customize +customizing +Customizing +CustomRange +cut +CUT +cutting +cv +cvn +CVT +cvXX +cwd +CWS +cx +cy +CYGWIN +Cypriot +CYPRIOT +Cyrillic +CYRILLIC +Czech +czh +czo +czt +d +D +da +DA +Daai +DAD +DAFu +dagesh +DAGESH +dagger +daggerdbl +DAHAL +Dai +DAL +DALATH +DALET +dam +DAMAGE +DAMAGES +damma +dammatan +Dan +dance +dangerous +Dangme +Danish +dao +dap +dar +Dargwa +Dari +dark +DARK +Darkhat +Darussalam +Darwazi +DASH +data +Data +DATA +dataArray +dataArrayLen +Database +dataLen +dataLength +DataMap +dataMaps +dataOffset +dataset +dataSets +dataSize +dataSizeArray +dataZ +Date +DAu +David +Daw +dax +day +Dayi +db +DB +DBAu +DBBu +DBCu +DBEu +DBF +dbfo +DBL +DBu +dc +DC +DCA +DCAu +DCBu +DCFu +dcroat +DCu +DCx +DCxA +DCxAB +DCxBA +dd +DD +DDA +DDAHAL +DDAL +DDAu +DDCu +DDD +DDDu +dde +DDEu +ddf +DDF +DDFu +DDu +de +DE +deabc +Dead +DEAD +deal +deallocate +Deallocate +DEALLOCATE +deallocation +dealt +DEAu +Debian +debug +Debug +DEBUG +debugging +Debugging +dec +decay +decender +decide +Decide +deciding +DECIMAL +decipoints +decision +decisions +declaration +declarations +declare +Declare +DECLARE +declared +declaring +decls +DECLS +declspec +decltype +declval +decode +DECODE +decomp +decompose +Decompose +DECOMPOSE +decomposed +DECOMPOSED +decomposedglyphs +decomposes +decomposing +decomposition +DECOMPOSITION +decompositionAction +DecompositionAction +decompositions +decompressed +deconstructed +DECORATIVE +DecorativeBorders +decrease +decreased +decreases +Decreases +decreasing +deduce +deduced +deduces +deem +deemed +deep +def +DEF +defaul +default +Default +DEFAULT +defaultBaseline +defaultFlags +defaultIndex +DefaultJstfLangSys +defaultLangSys +DefaultLangSys +defaultMinMax +defaults +defaultUVS +DefaultUVS +defaultValue +defaultVertOriginY +defaultWidthX +define +DEFINE +defined +Defined +DEFINED +defines +Defines +defining +Defining +definition +Definition +definitions +Definitions +DEFu +Degexit +degree +DEGREE +degrees +Dehong +DejaVu +del +delayed +delete +DELETE +DeleteCriticalSection +deleted +DELETED +DeleteObject +deleting +delimited +DELIMITED +delta +Delta +DELTA +deltaFormat +deltaGlyphID +deltas +DELTAS +DeltaSetIndexMap +DeltaValue +deltaValueZ +Democratic +demonstrate +den +DENIED +Denmark +denom +DENOM +DENOMINATOR +denote +density +depend +dependant +dependencies +dependency +dependent +Dependent +DEPENDENT +depending +depends +deprecated +Deprecated +DEPRECATED +depth +deref +dereference +dereferenced +dereferencing +derived +Derived +DerivedCoreProperties +desc +descendent +descender +DESCENDER +descending +descent +DESCENT +describe +described +describes +describing +description +Description +DESCRIPTION +descriptor +descriptors +Deseret +DESERET +deserialize +DESERIALIZE +design +Design +DESIGN +designated +designates +designAxesOffset +designAxisCount +designAxisSize +designed +designer +DESIGNER +designSize +desirable +desired +desktop +dest +destroy +Destroy +DESTROY +destroyed +destroying +destroys +Destroys +destruct +destructed +destructible +destruction +desubroutinize +detail +detailed +details +detect +detected +determine +Determine +determined +determines +determining +Determining +DEu +dev +DEVA +devanagari +Devanagari +DEVANAGARI +devel +develop +developed +developer +developers +developing +development +Deviate +device +Device +DeviceHeader +DeviceRecord +devices +deviceTable +devnet +df +DF +DFAu +dfde +DFDu +dfe +DFF +DFFu +dflt +DFLT +dfont +DFont +DFontTag +DFu +dgo +dgr +Dhangu +dhd +dhg +Dhivehi +Dhofari +Dhundari +Dhuwal +Dhuwaya +diacritic +Diacritical +diacritics +DIACRITICS +diagnostic +DIAGNOSTIC +DIAGONAL +DIAMOND +dib +dict +Dict +DICT +dictionary +dicts +dictsSize +dictval +DICTVAL +did +didn +Didn +didnt +dieresis +Dieresissmall +diff +DIFF +differ +difference +differences +different +Different +differentiate +differently +differing +differs +difficult +difficulty +digest +DIGEST +digests +digit +Digit +DIGIT +digital +Digits +dik +dimensional +dimensions +Dimli +din +Dingbats +DINGBATS +Dinka +dip +DIPHTHONG +diq +dir +DIR +direct +DIRECT +direction +Direction +DIRECTION +directional +directionality +directions +directive +directly +directory +directwrite +DirectWrite +DIRECTWRITE +dirty +disable +Disable +DISABLE +disabled +disableFlags +disables +disabling +disallow +disallows +disambiguated +Disc +discard +Discarding +discards +discern +DISCLAIMS +discover +Discovered +discretionary +discussed +Discussion +dispatch +Dispatch +DISPATCH +displacement +display +Display +DISPLAY +displaying +dist +distance +Distance +DISTANCE +distances +distinct +distinction +distinguish +distinguishes +distinguishing +distribute +distribution +ditto +div +DIV +Divehi +divert +divide +DIVIDE +divided +divisible +diw +Djambarrpuyngu +dje +djr +dks +DLBAR +dlig +dll +DLL +dllexport +dm +dng +dnj +dnom +do +Do +DO +DOACHASHMEE +doc +Doc +docbook +DocBook +docbookx +docs +DOCTYPE +document +Document +documentation +DOCUMENTATION +documented +documents +Documents +does +Does +doesn +Doesn +doesnt +Dogra +DOGRA +Dogri +Dogrib +doi +doing +dollar +dollarinferior +dollaroldstyle +dollarsuperior +Domain +dominant +Dominican +Domino +don +Don +DON +done +Done +DONE +Dong +dont +DONT +DontAdvance +Dos +DoS +dot +Dot +DOT +dotaccent +Dotaccentsmall +dotlessi +dotsection +dotted +DOTTED +dottedcircle +DOTTEDCIRCLE +Dotyali +double +DOUBLE +down +DOWN +download +downloaded +Downloading +downstream +downward +DPI +DR +dragons +drain +draw +Draw +drawing +Drawing +DRAWINGS +drawn +Drepper +drh +drive +driver +Driver +drop +Drop +DROP +dropped +dropping +drops +drw +ds +dsb +Dsmall +dsohowto +dst +dsuperior +dtd +DTD +dtor +dty +du +Du +dual +Duano +duct +ductile +ductileGlyphAction +DuctileGlyphAction +ductility +due +duj +DUL +dumb +dumber +Dumbest +dummy +Dummy +Dungan +dup +dupe +duplicate +DUPLICATE +duplicated +Duplicated +duplicates +duplication +DUPLOYAN +dupped +duration +during +During +Dutch +dv +dw +dwFeatures +dwFileAttributes +dwFileFlags +DWORD +dwrite +DWrite +DWRITE +DWriteCreateFactory +dwriteFactory +DWriteFontFileLoader +DWriteFontFileStream +dwSecurityQosFlags +dwSize +dwu +dwy +dx +Dx +DxA +DxAB +DxBA +dy +DYEH +dynamic +dyu +Dyula +dz +Dzongkha +e +E +ea +EA +EAAu +EABu +each +Each +eachother +EACu +eacute +Eacute +Eacutesmall +EADu +eae +EAEu +EAFu +eager +earlier +Earlier +early +EARLY +easier +East +eastasian +Eastern +easy +EAu +eb +EB +EBAu +EBBu +EBCu +ebdt +EBDT +EBDu +EBEu +EBFu +Ebira +eblc +Ebrahim +EBu +ec +EC +ECAu +ECBu +ECCu +ECD +ecde +ECDu +ECE +ECEu +ecfb +ECFu +ecircumflex +Ecircumflex +Ecircumflexsmall +ECu +Ecuador +ed +ED +eda +EDAu +EDBu +EDCu +EDDu +EDEu +EDFu +edge +edges +edieresis +Edieresis +Edieresissmall +edit +edits +EDITS +Edo +EDu +ee +EE +EEAu +EEBu +EECu +EEDu +EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE +EEELLLGGGGEEEE +EEEu +EEFu +EEu +ef +EF +EFEu +EFF +effect +effectively +effects +efficiency +efficiently +effort +efi +Efik +EFu +eg +Eg +egrave +Egrave +Egravesmall +Egypt +Egyptian +EGYPTIAN +eight +EIGHT +EIGHTEEN +eightinferior +eightoldstyle +eightsuperior +EINTR +either +Either +EK +ekk +el +El +ELBASAN +ELEM +element +ELEMENT +elements +Elements +ELEVEN +elidable +ELIDABLE +elidedFallbackNameID +elie +Elie +elif +ellipsis +ELLIPSIS +else +Else +elt +ELT +ELYMAIC +em +EM +embed +embedded +EmbeddedPeakTuple +embedding +EMBEDDING +emboldening +EMBOX +emdash +emk +emoji +Emoji +EMOJI +emphasis +empty +Empty +EMPTY +ems +en +EN +enable +Enable +enabled +ENABLED +enableFlags +enables +enabling +enb +enc +Enclosed +enclosing +ENCLOSING +encode +ENCODE +encoded +Encoded +encoder +Encodes +encoding +Encoding +ENCODING +encodingID +EncodingID +encodingOffset +EncodingOffset +encodingrec +EncodingRecIter +encodingRecord +EncodingRecord +encodings +encounter +encountered +end +End +END +endash +endchar +endCharCode +endcode +endCode +endConnectorLength +endCoord +endCount +endcp +ended +endGlyphID +endGlyphIndex +endian +Endian +ENDIAN +endif +ending +EndPtr +endPtsOfContours +ends +endSize +Enets +enf +enforce +engine +Engine +engines +English +ENGRAVED +enh +ENHANCEMENTS +enlarge +Enlarge +enough +ensure +Ensure +ensures +enter +EnterCriticalSection +entire +entirely +entirety +ENTITY +entries +Entries +entry +Entry +entryAnchor +EntryAnchor +EntryData +EntryExit +entryExitRecord +EntryExitRecord +entrySelector +EntryT +entryTable +enum +enumerate +enumerated +Enumerates +enumeration +enumerations +enums +env +ENV +environment +eo +eof +EOT +epsilon +eq +equal +EQUAL +equality +equally +equals +Equatorial +equivalent +Eric +err +Err +Erratic +erratically +erring +errno +ERRNO +error +Error +ERROR +errors +errs +Erzya +es +ESC +escape +escapes +eScript +Esfahbod +esg +esi +esk +Esmall +esp +especially +Esperanto +esque +essence +essentially +Estero +estimate +estimated +estimates +Estonia +Estonian +Estrangela +Estrangelo +esu +esuperior +et +etc +eth +Eth +Ethiopia +Ethiopic +ETHIOPIC +Ethsmall +eto +Eton +eu +Eu +eval +evaluate +evaluating +eve +even +Even +EVEN +Evenki +event +EVENT +events +eventual +ever +every +Every +everyone +everything +evidence +evident +evn +Ewe +ewo +Ewondo +exact +exactly +examine +examines +examining +example +examples +exceed +exceeds +except +Except +exception +exceptional +exceptions +excess +excessive +exch +exchange +exclam +EXCLAMATION +exclamdown +exclamdownsmall +exclamsmall +excluded +exclusion +exclusive +Exclusive +exclusivity +exe +executable +execute +EXECUTE +exhaust +exist +existence +existent +existing +EXISTING +exists +exit +exitAnchor +ExitAnchor +exp +EXP +expand +expanded +EXPANDED +ExpansionFactor +expect +expected +expects +expensive +experience +experimental +experimentally +expert +EXPERT +ExpertCharset +ExpertEncoding +ExpertSubsetCharset +explanation +explicit +EXPLICIT +explicitLevel +explicitly +explore +exponent +EXPONENTS +export +EXPORT +exported +exports +expose +Expose +exposed +exposing +Exposing +expr +EXPR +express +Express +expressed +expression +expressions +extend +Extend +extended +Extended +EXTENDED +extendedShapeCoverage +ExtendedTypes +Extender +EXTENDER +ExtenderGlyph +extenderGlyphs +ExtenderGlyphs +extensibility +extension +Extension +extensionDisableGPOS +extensionDisableGSUB +extensionEnableGPOS +extensionEnableGSUB +ExtensionFormat +extensionJstfMax +extensionLookupType +extensionOffset +ExtensionOffset +ExtensionPos +extensions +Extensions +EXTENSIONS +ExtensionSubst +extensively +extent +Extent +extents +EXTENTS +extern +EXTERN +external +externally +externs +extlang +extra +Extra +EXTRA +extract +extracted +EXTRAS +extreme +extremely +eye +Eye +eyelash +eyo +f +F +fa +FA +FAAu +fabs +FABu +FAbv +faca +face +Face +FACE +faceBlob +Facebook +faces +FACESIZE +facet +faceType +facilities +facility +fact +factor +FACTOR +factors +factory +FACTORY +factoryType +FACu +FADu +FAEu +FAFu +fail +Fail +FAIL +failed +Failed +FAILED +failing +FAILLING +fails +Fails +failure +FAILURE +failures +fairly +Falam +fall +Fall +fallback +Fallback +FALLBACK +falling +falls +fallthrough +FALLTHROUGH +false +FALSE +family +Family +FAMILY +FamilyBlues +familyName +FamilyName +FamilyOtherBlues +fan +Fancy +Fang +Fanti +faq +far +Faroe +Faroese +Farsi +FARSI +fashion +fast +faster +fat +fatha +FATHA +fathatan +FAu +faulty +favor +fb +FB +fba +FBAu +FBBu +FBCu +FBDu +fbe +FBFu +fbl +FBlw +FBu +fc +FC +FCAu +fcc +FCCu +FCDu +FCEu +FCFu +fclose +fcntl +FCu +fd +FD +fda +fdArray +FDArray +FDArrayInfo +FDArrayOffset +FDAu +fdcount +fdCount +FDDu +fde +FDEFs +FDEu +FDF +FDFu +FDIndex +fdmap +fds +fdsc +FDSC +fdselect +fdSelect +FDSelect +FDSELECT +FDSelectInfo +FDSelectOffset +FDu +fe +Fe +FE +feat +FEAT +FeatMinMaxRecord +featMinMaxRecords +FeatMinMaxRecords +feats +featUILableNameID +featUITooltipTextNameID +feature +Feature +FEATURE +featureCount +featureFlags +featureIndex +featureList +FeatureList +FeatureName +featureNameCount +featureParams +FeatureParams +FeatureParamsCharacterVariants +FeatureParamsSize +FeatureParamsStylisticSet +featureRangeLengths +features +Features +FEATURES +featureSetting +FeatureTableSubstitution +FeatureTableSubstitutionRecord +featureTableTag +featureType +featureval +FeatureVariationRecord +FeatureVariations +featureVars +featureZ +FEAu +Feb +February +FEBu +FECu +Fedora +FEDu +fee +feed +feel +fees +FEFF +FEH +fence +feof +ferror +fetch +Fetch +fetched +fetches +Fetches +fetching +FetchNextRun +FEu +few +fewer +ff +FF +FFA +FFAu +ffbfea +ffcdf +FFCu +FFEu +FFF +FFFD +FFFF +FFFFF +FFFFFF +FFFFFFF +FFFFFFFFULL +FFFFFu +FFFFu +FFFFULL +FFFu +ffi +ffl +ffm +FFu +FFULL +ffuncs +ffunctions +fh +fi +fi +fid +field +fields +FIFTEEN +figure +FIGURE +figuredash +Fijian +fil +file +File +FILE +filename +fileOffset +files +fileSize +fileType +Filipino +fill +Fill +filled +FILLER +filling +Filling +filter +Filter +filtered +filtering +filterMethod +filterRangeMaxValue +filterRangeMinValue +filters +FIN +fina +FINA +final +Final +FINAL +finalcode +finalize +finalizer +Finalizer +finally +Finally +finaLookup +finaSubLookup +find +Find +FINDFONT +finding +finds +Finds +fine +fini +finish +Finish +finished +finite +Finland +Finnish +Firefox +first +First +FIRST +firstAxis +firstAxisSegmentMaps +firstChain +firstDeviceRecord +firstGlyph +firstGlyphIndex +FirstGlyphs +firstLayerIdx +firstPairValueRecord +firstParamUILabelNameID +firstSubtable +firstSubTable +fit +FITNESS +fitting +five +FIVE +fiveeighths +fiveinferior +fiveoldstyle +fivesuperior +fix +Fix +fixed +Fixed +FIXED +fixedcs +FixedType +FixedVersion +Fixes +fixup +Fixup +fj +fl +flag +Flag +FLAG +flags +Flags +FLAGS +flat +flatStr +flatten +Flatten +FLATTENED +flattener +fLayoutRTL +Flemish +Fleurons +FLEURONS +flex +flip +flm +float +floating +fLogicalOrder +flooded +floor +florin +flow +Flowery +FLT +flush +fly +FM +FMAbv +FMBlw +fMergeNeutralItems +fmp +FMPst +fmt +fNoGlyphIndex +fo +folded +follow +followed +Followed +following +Following +follows +fon +Fon +fonipa +fonnapa +font +Font +FONT +FontBBox +fontconfig +Fontconfig +FontConfig +FontDescriptor +fontdict +FontDict +fontdicts +fontDicts +fontDictStr +fontDirectionHint +fontEmSize +fontFace +fontFile +fontFileKey +fontFileLoader +fontFileReferenceKey +fontFileReferenceKeySize +fontFileStream +FontInfo +fontlab +FontMatrix +fontName +FontName +fontRevision +fonts +Fonts +fontSzr +fonttools +fontTools +FontTools +foo +fopen +for +For +FOR +forbid +Force +ForceBold +forced +foreach +foreground +Forest +forget +forgives +fork +Fork +form +Form +FORM +format +Format +FORMAT +formatReserved +formats +Formats +formatting +formed +former +Former +formerly +forms +Forms +FORMS +FORMULA +forum +forw +forward +FORWARD +forwards +found +Found +FOUND +Foundation +four +Four +FOUR +fourinferior +fouroldstyle +foursuperior +FOURTEEN +fourth +fOverrideDirection +fp +fprintf +FPst +fr +frac +FRACT +fraction +FRACTION +fractional +fractions +FRACTIONS +fragmentContext +fragmentSize +fragmentStart +frame +framework +franc +France +frc +fread +Frédéric +free +Free +FREE +freed +freedesktop +Freedesktop +freeing +FreeLibrary +freelocale +freely +freetype +FreeType +FREETYPE +fref +French +frequent +frequently +fribidi +friend +Frisian +Friulian +from +From +FROM +fromCoord +FromGlyphs +front +frozen +frp +fRTL +fscale +Fsmall +fsref +FSRef +fsSelection +fstat +fsType +ft +FT +FTStringRange +fu +Fu +fub +fuc +fue +fuf +fuh +fui +Fujian +Fukien +Fulah +fulfilled +Fulfulde +full +Full +FULL +fullAdvance +fullName +FullName +fullset +Fullwidth +FULLWIDTH +fully +Fully +fun +func +Func +FUNC +FUNCOBJ +funcs +Funcs +FUNCS +FUNCSIG +function +Function +FUNCTION +functionality +functions +Functions +FuncType +funcZ +fundamental +fundamentals +FUnit +FUnits +fuq +fur +further +Furthermore +Futa +future +fuv +Fuzhou +fuzz +fvar +FVAR +FVSes +FWIDTH +FWORD +fy +FYROM +g +G +ga +Ga +gaa +Gade +Gaelic +GAF +gag +Gagauz +Gah +Gahri +Galice +Galician +Galla +Gallurese +gan +Gan +Ganda +Ganja +gap +GAP +gaps +garbage +Garhwali +Garo +Garret +Garshuni +gasp +GASP +GaspRange +gaspRanges +gather +gaw +gax +gaz +GB +gbm +GBoxedCopyFunc +GBoxedFreeFunc +gbreve +Gbreve +gbytes +GBytes +gc +GC +gcc +GCC +gce +gchar +gconstpointer +gd +gda +gdef +GDEF +gdi +GDI +Ge +Geez +Gemination +GEMINATION +gen +Gen +GEN +general +General +GENERAL +generally +Generally +generate +generated +GenerateResults +generates +Generates +Generating +generic +Generic +GENERIC +geok +Geok +Geometric +Georgia +Georgian +GEORGIAN +German +germandbls +Germany +get +Get +GET +GetCharVariantIndex +getCombiningClass +GetDC +getenv +GETENV +GetFileSize +GetFileSizeEx +GetFontData +GetGlyphPlacements +getglyphs +GetGlyphs +getIntPropertyMaxValue +getIntPropertyValue +GetJustificationOpportunities +getjustifiedglyphs +GetJustifiedGlyphs +GetLastWriteTime +GetLocaleName +GetModuleHandle +getNFCInstance +getNFDInstance +GetNumberSubstitution +getpagesize +GETPAGESIZE +GetParagraphReadingDirection +GetProcAddress +getRawDecomposition +gets +Gets +getScript +GetScriptProperties +getShortName +getter +getters +GetTextAtPosition +GetTextBeforePosition +getting +Getting +gez +gfxShapedWord +ggo +GHAIN +Gheg +GHUNNA +gid +GID +gidDDD +gids +gih +Gikuyu +gil +Gilaki +Gilbertese +Gilyak +GIMEL +ginfo +git +Githabul +github +GitHub +give +Give +given +Given +gives +giving +gju +gkp +gl +Glagolitic +GLAGOLITIC +gld +glib +GLib +GLIB +glibc +GLIBC +glk +global +Global +GLOBAL +GlobalSubr +globalsubrs +globalSubrs +globalSubrsInfo +glue +glyf +GLYF +glyid +glyID +glyph +Glyph +GLYPH +glyphAdvances +GlyphAnchors +glyphArray +glyphAssembly +GlyphAssembly +GlyphBitmapDataFormat +glyphClassDef +GlyphClasses +glyphConstruction +glyphCount +glyphDataFormat +glyphDataOffsets +glyphFormat +GlyphHeader +glyphid +glyphId +glyphID +GlyphID +GLYPHID +glyphIdArray +glyphIdArrayLength +GlyphIDs +glyphIndex +glyphIndices +glyphMetrics +glyphNameIndex +glyphOffsets +GLYPHPROP +glyphProperties +glyphs +Glyphs +GLYPHS +glyphset +GlyphVarData +GM +gmappedfile +GMT +gn +gname +gnn +gno +gnome +gnu +GNU +GNUC +gnw +go +goal +GOAL +goals +Goan +gobject +GObject +GOBJECT +GOFFSET +gog +Gogo +going +gom +gon +Gondi +GONDI +gone +good +google +Google +Goronzy +got +Got +Gothic +GOTHIC +goto +gpos +GPOS +GPOSProxy +gr +grab +graduated +grained +granted +GRANTED +Grantha +GRANTHA +granular +granularly +graph +grapheme +Grapheme +GRAPHEME +graphemes +Graphemes +GRAPHEMES +graphic +graphics +Graphics +graphicType +graphite +Graphite +GRAPHITE +grave +Gravesmall +greater +greaterequal +Greece +Greek +GREEK +green +Green +Greenland +Greenlandic +greg +grep +grface +Grid +GRID +Grigori +grigorig +group +GROUP +grouped +Groupings +grouprecord +groups +grow +growFlags +growing +grows +growth +grt +gru +gsize +Gsmall +gsub +GSUB +gsubgpos +GSUBGPOS +GSUBProxy +gsw +gt +gtk +GTK +gtype +GType +gu +Guarani +Guaraní +guarantee +guaranteed +guarantees +guards +Guatemala +guc +GUEH +guess +guessing +guf +gug +gui +Guibei +Guibian +guillemotleft +guillemotright +guilsinglleft +guilsinglright +Guinea +Guiyang +Gujarati +GUJARATI +Gujari +Guji +GUJR +guk +Gulf +Gumatj +Gumuz +gun +GUnicodeScript +GUnicodeType +Gunjala +GUNJALA +Gupapuyngu +Gurage +Gurmukhi +GURMUKHI +GURU +Gusii +guz +gv +gvar +GVAR +gwi +Gwich +GX +gxFontDescriptor +gzip +h +H +ha +haa +hack +HACKMEM +had +Hadothi +Hadrami +hae +HAFS +HAH +Haible +HAIR +Haitian +Haji +hak +Hakha +Hakka +Halam +halant +Halant +HALANT +halants +half +Half +HALF +Halfwidth +HALFWIDTH +Halh +HALN +Hamer +Hammer +HAMZA +HAMZAH +Han +HAN +hand +Hand +handed +handing +handle +Handle +HANDLE +handled +handler +handles +handling +hang +hanging +Hanging +HANGING +hangul +Hangul +HANGUL +Hanifi +HANIFI +HANJA +hans +Hans +hant +Hant +Hanunoo +HANUNOO +happen +happened +happening +happens +Happens +happier +happy +har +Harari +Harauti +hard +harder +hardest +harfbuzz +HarfBuzz +HarffBuzz +Haryanvi +has +Has +HAS +hash +hashmap +Hat +hataf +HATRAN +HAU +Hausa +have +Have +HAVE +having +haw +Hawaiian +hAxis +hay +Haya +haz +Hazaragi +hb +HB +HBASELINE +HBFixed +HBGlyphID +HBINT +hbot +hbotABCD +hbsc +hbshape +hbsubset +HBUCHAR +HBUINT +HBUSHORT +hbview +hdc +HDC +hdmx +HDMX +he +HE +hea +head +Head +HEAD +header +Header +HEADER +headerfile +headers +Headers +headerSize +HeadlessArrayOf +heap +heavier +heavily +hebrew +Hebrew +HEBREW +HEH +height +HEIGHT +heightCount +heights +help +helper +Helper +helpers +helpful +helps +hence +Hence +here +Here +hereby +Herero +HEREUNDER +Herzegovina +HET +heuristic +Hexagram +hflex +hfont +HFONT +hh +HH +hhcurveto +hhea +HHEA +hi +hidden +HIDDEN +hide +HIDE +hiding +HIEROGLYPHS +high +High +HIGH +higher +highest +Highland +HIGHLEVEL +highlight +highlighting +highly +Hijazi +hil +Hiligaynon +himalaya +Himalaya +Hindi +Hindko +hinstLib +hint +hinted +hinting +HINTING +HintingDevice +hintmask +hints +Hiragana +HIRAGANA +Hiri +hiriq +HIRIQ +historical +HISTORICAL +history +hit +hji +hk +HK +hlineto +hlt +hma +hmc +hmd +hme +hmetrics +hmg +hmh +hmi +hmj +hml +hmm +hmn +HMODULE +Hmong +HMONG +hmoveto +hmp +hmq +hms +hmtx +HMTX +hmtxvmtx +hmw +hmy +hmz +HN +hnd +hne +hnj +hno +ho +Ho +hoc +hoi +hoj +HOJO +Hokkien +Hoklo +holam +HOLAM +hold +holder +Holder +HOLDER +holding +holds +Holikachuk +home +Homebrew +Honduras +Hong +Hongshuihe +hood +hook +Hook +hooks +horiBearingX +horiBearingY +horiz +HORIZ +horizData +horizGlyphCount +horizGlyphCoverage +horizontal +Horizontal +HORIZONTAL +horizontally +Horned +Hosken +Hosny +hosted +house +House +how +however +However +HOWEVER +HP +hr +HRESULT +hrm +hsb +Hsmall +hsn +hstem +hstemhm +ht +hTemplateFile +html +http +https +hu +Huallaga +Huamalíes +Huánuco +Huaylas +Huaylla +huge +Huishui +Huizhou +huj +human +Humm +Hungarian +HUNGARIAN +hungarumlaut +Hungarumlautsmall +Hungary +hup +Hupa +hvar +HVAR +HVARTag +HVARVVAR +hvcurveto +HVM +hy +hyphen +HYPHEN +hyphenation +hypheninferior +HYPHENS +hyphensuperior +hyw +hz +i +I +ia +iacute +Iacute +Iacutesmall +iba +Iban +ibb +Ibibio +IBMCPP +ibmxl +ibo +ic +Iceland +Icelandic +iCharPos +iche +icircumflex +Icircumflex +Icircumflexsmall +icu +ICU +id +ID +ida +Idakho +idDelta +idea +ideal +Ideally +ideas +IDEFs +idempotent +identical +identically +identification +identified +identifier +identifiers +identifies +identify +identifying +identity +IDEO +Ideograms +Ideographic +IDEOGRAPHIC +Ideographs +IDEOGRAPHS +idieresis +Idieresis +Idieresissmall +Ido +Idotaccent +idRangeOffset +ids +IDs +IDWriteFactory +IDWriteFontFace +IDWriteFontFile +IDWriteFontFileLoader +IDWriteFontFileStream +IDWriteNumberSubstitution +IDWriteTextAnalysisSink +IDWriteTextAnalysisSource +IDWriteTextAnalyzer +idx +ie +Ie +ietf +IETF +if +If +IF +IFACEMETHOD +IFACEMETHODIMP +ifdef +ifelse +iff +ifndef +ig +Igalia +igb +Igbo +ignorable +Ignorable +IGNORABLE +ignorables +IGNORABLES +ignore +Ignore +IGNORE +IgnoreBaseGlyphs +ignored +Ignored +IGNORED +IgnoreFlags +IgnoreLigatures +IgnoreMarks +ignoring +igrave +Igrave +Igravesmall +IHDR +ii +II +iid +IID +ijc +ijo +Ijo +ik +ike +ikt +ill +illegal +ILLUMINATED +illustrates +ilo +Ilokano +Iloko +image +imageDataOffset +imageFormat +imageOffsetsZ +images +imagine +Imbabura +IMC +immediately +immutable +IMPERIAL +impl +IMPL +implement +Implement +IMPLEMENT +implementation +IMPLEMENTATION +implementations +Implementations +implemented +IMPLEMENTED +implementing +Implementing +implementor +implements +Implements +implicit +IMPLICIT +implied +IMPLIED +implies +important +Important +impose +impossible +improve +improved +iMu +in +In +IN +inaccuracy +Inari +inc +Inc +inch +INCIDENTAL +Incidentally +include +Include +included +includes +Includes +including +Including +INCLUDING +inclusion +inclusive +incoming +incompatible +incomplete +inconsistencies +incorporating +incorrect +incorrectly +incorrectness +increase +Increase +increased +increases +Increases +increasing +incrementally +incurs +IND +indeed +indefinitely +indented +independent +Independent +INDEPENDENT +independently +index +Index +INDEX +IndexArray +indexed +Indexed +indexes +indexFormat +indexing +IndexMask +IndexOf +IndexSubtable +IndexSubtableArray +indexSubtableArrayOffset +IndexSubtableFormat +IndexSubtableHeader +IndexSubtableRecord +indexSubtablesZ +indexTablesSize +indexToLocFormat +India +indic +Indic +INDIC +indicate +indicated +indicates +Indicates +indicating +indication +indices +indicies +IndicPositionalCategory +IndicShapingInvalidCluster +IndicSMatraCategory +IndicSyllabicCategory +IndicSyllableCategory +INDIRECT +indirection +individual +Individual +individually +indivisible +Indonesia +Indonesian +inds +industry +IndV +indx +indy +ineffective +inefficient +INEQUALITY +inert +INERT +inf +infer +Infer +INFERIORS +inferred +infinite +infinitum +infinity +info +INFO +informaltable +informatimago +information +Information +infos +infrequent +ing +Ingush +inh +INHERENT +inherit +Inherit +INHERITED +inherits +inhibit +init +Init +INIT +initial +Initial +INITIAL +Initialization +initialize +InitializeCriticalSection +InitializeCriticalSectionEx +initialized +initializer +INITIALIZER +initializers +initially +Initially +initialRandomSeed +initiated +initLookup +initmediSubLookup +initpos +initSubLookup +InitT +ink +inline +inner +innerIndex +inout +INOUT +inplace +input +Input +INPUT +inputClassDef +inputCount +inputs +inputX +inputZ +Inremental +ins +insane +INSCRIPTIONAL +insert +Insert +INSERT +inserted +insertion +Insertion +insertionAction +insertions +InsertionSubtable +inserts +inside +Inside +inspect +inspecting +inspects +install +Install +installed +installing +Installing +instance +INSTANCE +instanceCoords +instanceCount +InstanceRecord +instances +Instances +instanceSize +INSTANTIATE +instantiated +instead +Instead +instruct +instruction +instructionLength +instructions +Instructions +INSTRUCTIONS +INSUFFICIENT +int +Int +INT +integer +Integer +INTEGER +integers +integral +integrate +integrating +integration +Integration +intel +INTEL +intended +intentional +intentionally +Intentionally +Inter +interact +InterCharacter +interest +interested +interface +interfaces +interfering +interim +Interix +interlaceMethod +Interlingua +Interlingue +InterlockedCompareExchangePointer +InterlockedExchange +InterlockedExchangeAdd +intermediate +intermediateEndTuple +IntermediateRegion +intermediateStartTuple +intermixed +intern +internal +Internal +INTERNAL +internally +Internally +internals +International +INTERNATIONAL +InternationalSymbols +interp +INTERP +interpolate +Interpolate +interpolation +interpret +interpretation +Interpretation +interpreter +interpreting +INTERROBANG +intersect +intersections +intersects +INTERSECTS +interviews +intl +into +intOp +intptr +intrin +intro +introduced +Introduced +introducing +Introduction +ints +IntType +INTTYPE +inttypes +intuition +Inuinnaqtun +Inuktitut +Inupiaq +Inupiat +Inupiatun +invalid +Invalid +INVALID +invert +INVERTED +inverts +investigated +investigation +invisible +Invisible +INVISIBLE +invocation +invoke +invoked +invol +involve +involved +involves +io +iOS +iota +IOTA +ip +IPA +IPHONE +Iran +Iranian +IranNastaliq +Iraq +Ireland +Irish +irrelevant +is +Is +IS +Isaac +ISALNUM +ISALPHA +ISC +isCombinedS +isCombiningL +isCombiningT +isCombiningV +isEmojiFont +isFixedPitch +ish +isHangulTone +isiXhosa +isiZulu +isL +Islamic +Islands +Ismall +isn +iso +ISO +ISOAdobeCharset +ISOL +ISOLATE +isolated +ISOLATED +Israel +isRightToLeft +ISSPACE +issue +issuecomment +issues +issuetracker +isSupported +isT +Isukha +isuperior +isV +it +It +ital +Italian +italic +Italic +ITALIC +italicAngle +ItalicAngle +italics +Italics +italicsCorrection +Italy +item +Item +ITEM +itemCount +itemizedlist +itemizer +items +Items +ITEMS +ItemSize +iter +Iter +ITER +iterable +Iterable +iterables +iterate +Iterate +iterated +iteration +iterations +iterator +Iterator +IteratorIn +IteratorOut +iterators +iters +its +Its +ITS +itself +iu +IUnknown +ivs +iw +Izon +izzi +j +J +ja +jak +Jakun +jam +Jamaica +Jamaican +Jambi +jamo +Jamo +January +Japan +Japanese +Jauja +Javanese +JAVANESE +jax +jbo +jct +JEEM +JEH +jg +ji +Jicarilla +Jing +Jinyu +JIS +JMO +job +join +joiner +Joiner +JOINER +joiners +JOINERS +joining +Joining +JOINING +Jonathan +Jordan +jpg +Jsmall +json +JSON +jstf +JSTF +JstfLangSys +JstfLangSysRecords +JstfMax +JstfModList +JstfPriority +JstfScript +JstfScripts +jt +Jula +JUNGSEONG +Junín +junk +just +Just +JUST +justClass +JustClass +justClassTable +justification +Justification +JUSTIFICATION +JustificationCategory +justificationCharacter +JustificationHeader +justificationOpportunities +justified +justifiedGlyphAdvances +justifiedGlyphOffsets +justify +JustifyGlyphAdvances +JustWidthDeltaEntry +jv +jw +jy +k +K +ka +kaa +kab +Kabardian +Kabras +Kabuverdianu +Kabyle +Kachchi +Kachhi +KAF +Kaithi +KAITHI +Kalenjin +Kalmyk +Kalo +Kalpak +kam +Kamba +Kambaata +kana +KANA +Kanaq +Kanauji +Kanbun +Kangri +Kangxi +Kanji +Kannada +KANNADA +Kanuri +Kaqchikel +kar +Kara +Karachay +Karaim +Karakalpak +Karelian +Karen +kashida +Kashida +KashidaLike +Kashmiri +Kashubian +Kaska +kasra +kasratan +Katakana +KATAKANA +Katanga +Kato +kau +Kaur +Kayah +KAYAH +Kazakh +Kazakhstan +Kazim +kb +kbd +kby +kByte +kca +kCFAllocatorDefault +kCFAllocatorNull +kCFBooleanTrue +kCFCompareEqualTo +kCFNumberIntType +kCFStringEncodingUTF +kCFTypeArrayCallBacks +kCFTypeDictionaryKeyCallBacks +kCFTypeDictionaryValueCallBacks +kCTFontAttributeName +kCTFontCascadeListAttribute +kCTFontEmphasizedSystemFontType +kCTFontFeatureSelectorIdentifierKey +kCTFontFeatureSettingsAttribute +kCTFontFeatureTypeIdentifierKey +kCTFontPostScriptNameKey +kCTFontSystemFontType +kCTFontUIFontEmphasizedSystem +kCTFontUIFontSystem +kCTFontURLAttribute +kCTKernAttributeName +kCTLanguageAttributeName +kCTRunStatusNonMonotonic +kCTRunStatusRightToLeft +kCTTypesetterOptionForcedEmbeddingLevel +kCTVersionNumber +kCTVerticalFormsAttributeName +kde +kdr +kdt +kea +Kebena +Kedah +keep +Keep +keeping +KEHEH +Keith +Keiyo +kek +Kekchi +Kentohe +Kenya +kept +Kerinci +kern +KERN +KernAAT +KernAATSubTableHeader +kernAction +kernActionIndex +KERNEL +kernIndex +kerning +Kerning +KERNING +kerningv +KernOT +KernOTSubTableHeader +KernPair +kerns +KernSubTable +KernSubTableFormat +KernSubTableHeader +kernValue +kernValueCount +kernValueZ +kerx +KERX +KerxSubTable +KerxSubTableFormat +KerxSubTableHeader +KerxTable +kerxTupleKern +Kew +kex +key +Key +KEY +keys +kfa +KFGQPC +kfr +kfx +kfy +kg +kha +KHAH +Khakas +Khakass +Khaled +Khamti +Khanty +Kharoshthi +KHAROSHTHI +Khasi +Khayo +khb +Khengkha +Khimi +khk +khmer +Khmer +KHMER +KhmerUI +Khojki +KHOJKI +Khorasani +Khowar +kht +Khudawadi +KHUDAWADI +Khumi +Khutsuri +khw +ki +kick +KIKAKUI +Kikongo +Kikuyu +Kildin +Killer +KILLER +Kimbundu +kind +kinda +kinds +Kingdom +kinoho +kINVALID +Kinyarwanda +Kiowa +Kipsigis +Kirghiz +KIRGHIZ +Kiribati +Kirmanjki +Kisa +Kisi +Kisii +Kissi +Kistane +Kiswahili +Kita +Kituba +kiu +Kiwai +kj +kjd +kjh +kjp +kjz +kk +kkz +kl +klass +klasses +kln +km +kMaxCallLimit +kmb +kmr +kmw +kmz +kn +knc +KNDA +kng +knn +know +knowing +Knowing +knowledge +known +Known +knows +Knuth +ko +Ko +Kodagu +Kodava +koi +kok +Kokni +Kölsch +Komi +Komo +Komso +Kong +Kongo +Konkani +Konso +Konyanka +Koongo +Koorete +Korea +Korean +Koryak +kos +Kosraean +Kota +koy +Koyukon +kpe +Kpelle +kpv +kpy +kqs +kqy +kr +krc +kri +Krio +krl +krt +kru +Krymchak +ks +ksh +kShort +kSizeLimit +Ksmall +kss +ksw +ktb +ktu +ktw +ku +Kuanyama +Kubu +Kui +Kukna +Kullu +Kulvi +kum +Kumaoni +Kumyk +Kumzari +Kuna +Kurdish +Kurukh +Kuskokwim +Kutai +kuu +Kuwait +Kuy +kv +kvb +kvr +kw +KW +kwy +kxc +kxd +kxu +ky +Kyrgyz +Kyrgyzstan +kyu +kZero +l +L +la +La +Laari +label +LABEL +labels +lack +lad +Ladakhi +Ladin +Ladino +Lahuli +laid +Lak +Laki +Lalana +Lam +LAM +lamAlefLigaturesSubLookup +Lambadi +Lambani +Lambayeque +LAMED +lamInitLigature +lamLigatureSet +Lampung +lang +langs +langsys +langSys +LangSys +LANGSYS +LangSysRecords +LangSysTag +LangTag +language +Language +LANGUAGE +LanguageGroup +languageID +languages +Languages +LANGUAGES +languagetags +Lanka +Lao +LAO +large +Large +LARGE +larger +largest +Largest +LArrayOf +lash +last +Last +LAST +lastCode +lastGlyphIndex +LastResort +lastWriteTime +LATE +later +latest +latg +Latg +Latgalian +latin +Latin +LATIN +latn +latter +Latvia +Latvian +Lauricocha +Lawoi +lay +layer +Layer +layering +LayerRecord +layers +layersZ +layout +Layout +LAYOUT +LayoutRTL +lays +Laz +lazily +lazy +Lazy +lb +LBAR +LBase +LBASE +lbe +lbj +lbl +LC +lcar +LCAR +lcarFormat +lce +lcf +LCount +LCOUNT +ld +ldi +Le +LE +lead +LEADER +leading +Leading +LEADING +leadingBearingX +Lealao +LEAN +leans +least +leave +Leave +LeaveCriticalSection +leaving +Lebanon +Leboa +left +Left +LEFT +leftC +leftClass +leftClassCount +leftClassTable +leftSide +legacy +Legacy +LEGACY +legally +legit +Lemberg +len +LEN +LENG +length +Length +LENGTH +lengthed +lengths +lengthy +lenient +lenM +lenP +LENTICULAR +LenType +Leone +Lepcha +LEPCHA +less +lessequal +let +Let +lets +Lets +letter +Letter +LETTER +Letterlike +letters +Letters +Levantine +level +Level +LEVEL +levels +leverage +lexicographic +lez +Lezghian +Lezgi +lf +LF +lfCharSet +lfFaceName +lfHeight +lg +lhs +Lhs +li +Li +LI +LIABLE +Lianshan +libc +libcairo +Liberia +libfreetype +libglib +libharfbuzz +libkern +Libon +libraries +Libraries +library +Library +LibreOffice +libs +libstdc +libtool +Libya +Libyan +license +LICENSE +lidentity +Liechtenstein +lif +life +lifecycle +lifecycles +lig +LIG +liga +ligAction +LigActionFlags +ligActionIndex +LigActionLast +LigActionOffset +LigActionStore +ligActionTable +ligate +ligated +LIGATED +ligating +ligation +ligature +Ligature +LIGATURE +ligatureArray +LigatureArray +LigatureAttach +ligatureCoverage +LigatureCoverage +ligatureData +LigatureEntry +LigatureEntryT +LigatureGlyph +ligatures +Ligatures +LIGATURES +ligatureSet +LigatureSet +LigatureSetOffsets +LigatureSetOffsetsArray +LigatureSubst +LigatureSubstFormat +LigatureSubtable +ligbase +LIGBASE +LigCaretClassEntry +ligCaretList +LigCaretList +ligGlyph +LigGlyph +light +Light +LIGHT +lighter +lightweight +ligs +Ligurian +lij +like +Like +likely +Likewise +Lima +Limbu +LIMBU +Limburgish +limit +Limit +LIMIT +limitation +limited +Limited +LIMITED +limiting +limits +lindex +line +LINE +linear +Linear +LINEAR +linearly +Linebreak +lineBreakpoints +lineGap +lines +lineWidth +Lingala +lingo +linguistic +LINGUISTIC +linguistically +linguistics +link +linked +linkedValue +linking +links +linux +Linux +Lipan +lis +list +List +LIST +listed +listinfo +listitem +lists +Lisu +LISU +literal +Literary +Lithuania +Lithuanian +little +LITTLE +Liujiang +Liuqian +liw +ljmo +LJMO +ljp +lkb +lki +lklug +lko +lks +ll +Ll +lld +LLLEEEEEEEGGGG +LLONG +LLVM +lm +Lm +lmn +lmo +ln +LNNOffsetTo +lo +Lo +load +Load +LOAD +loaded +loader +loaders +loading +LoadLibrary +loc +loca +local +locale +Locale +LOCALE +localeName +localized +localsubr +LocalSubr +localsubrs +localSubrs +localSubrsInfos +Locate +located +location +Location +locations +lock +lockable +Lockable +locl +locName +LOffsetArrayOf +LOffsetLArrayOf +LOffsetTo +log +LOG +LOGFONT +logfontw +LOGFONTW +logic +logical +Logical +logicalnot +LogicalOrder +Logo +logograms +Logooli +LOGOS +Logudorese +Lohar +lohit +Lohit +Loja +lojban +Lojban +lom +Loma +Lombard +Lomwe +Loncong +lone +Lonely +long +Long +LONG +LONGDATETIME +longer +longint +longintdict +LongMetric +longMetricZ +longword +look +Look +lookahead +lookaheadClassDef +lookaheadCount +lookaheadX +looked +looking +Looking +looks +Looks +lookup +Lookup +LOOKUP +lookupCount +lookupFlag +LookupFlag +LookupFlags +LookupFormat +lookupIndex +lookupList +LookupList +lookupListIndex +lookupOffset +lookupOrderZ +lookupRecord +LookupRecord +LookupRecords +lookupRecordX +lookups +Lookups +LOOKUPS +LookupSegmentArray +LookupSegmentSingle +LookupSingle +lookupTable +lookupType +LookupType +lookupX +loop +Loop +loops +loose +loosely +Lortie +lose +LOSS +lossless +lost +lot +Lots +low +Low +LOW +lower +Lower +LOWER +lowercase +LOWERCASE +lowercased +lowerLimit +lowest +lowestRecPPEM +Lowland +LowPart +lozenge +lParameter +lps +lpSecurityAttributes +LR +lrc +lri +lrm +lsb +lsbMap +lsearch +lslash +Lslash +Lslashsmall +lsm +Lsmall +lsuperior +lt +Lt +ltag +LTAG +ltg +lto +ltr +LTR +lts +lu +Lu +Lü +lua +Luba +Lubu +Lucian +Lue +LUE +Lule +Lulua +luo +Luo +Luopohe +Luri +lus +Lushai +lux +Luxembourg +Luxembourgish +luy +Luyia +luz +lv +LV +lvalue +lvalues +lvs +LVT +lwg +lwsync +lx +Lycian +LYCIAN +Lydian +LYDIAN +lzh +lzz +m +M +ma +Maasina +MAbv +mac +Mac +MAC +Macao +Macedonia +Macedonian +machine +MACHINE +machinery +MACHINERY +machines +Macintosh +macos +macOS +MacPorts +macro +macrolanguage +macroman +MACROMAN +macron +Macronsmall +macros +Macros +macStyle +mad +MADDA +MADDAH +made +Madura +Madurese +mag +Magahi +magic +magicNumber +Mahafaly +Mahajani +MAHAJANI +Mahjong +mai +MAI +mailing +mailman +main +Main +MAIN +mainly +maintain +maintained +MAINTENANCE +MAITAIKHU +Maithili +Majang +major +Major +MAJOR +mak +Makasar +MAKASAR +make +Make +MAKE +makeotf +makeOTF +MakeOTF +makes +Makes +Makhuwa +making +Making +Makonde +MAKSURA +Malagasy +Malay +Malayalam +MALAYALAM +Malaysia +Maldives +Maldivian +Male +Malinke +malloc +Malta +Maltese +Malvi +mam +Mam +man +Manado +manage +managed +management +manages +Manchu +Mandaic +MANDAIC +Mandar +Mandarin +Mandingo +Mandinka +Manga +Manichaean +MANICHAEAN +manifest +Manifest +MANIFEST +manifestData +ManifestLookup +Maninka +Maninkakan +Manipuri +manner +manpage +Mansi +manual +Manual +MANUAL +manufacturer +MANUFACTURER +Manx +many +Many +Maore +Maori +map +Map +MAP +mapCount +mapDataZ +mapLen +mapped +mapper +mapping +Mapping +mappings +maps +Maps +Mapudungun +MapViewOfFile +MapViewOfFileFromApp +Mara +Marachi +Marama +Marathi +MARBUTA +March +Marchen +MARCHEN +margins +Margos +Mari +mark +Mark +MARK +markAnchor +markAnchorPoint +markArray +MarkArray +markAttachClassDef +MarkAttachmentType +markBase +MarkBase +MarkBasePos +MarkBasePosFormat +MarkCategory +markControlPoint +markCoverage +MarkCoverage +marked +markedInsertBefore +MarkedInsertBefore +markedInsertCount +MarkedInsertCount +markedInsertIndex +markedInsertList +MarkedIsKashidaLike +markers +markFilteringSet +markFilteringSetX +MarkFirst +MarkGlyph +MarkGlyphSets +markGlyphSetsDef +MarkGlyphSetsFormat +markIndex +marking +MarkLast +markLig +MarkLig +MarkLigPos +MarkLigPosFormat +markMark +MarkMark +MarkMarkPos +MarkMarkPosFormat +MarkRecord +MarkRecords +marks +Marks +MARKS +Markweeta +markX +markY +Marma +Marshallese +Martin +Martín +Marwari +Masaram +MASARAM +Mashan +Masikoro +mask +Mask +MASK +masks +Masks +master +Master +MASTERS +match +Match +MATCH +matched +matcher +matches +matching +material +math +Math +MATH +mathConstants +MathConstants +mathematical +Mathematical +MATHEMATICAL +mathematics +MathGlyphAssembly +MathGlyphConstruction +mathGlyphInfo +MathGlyphInfo +MathGlyphPartRecord +mathGlyphVariantRecord +MathGlyphVariantRecord +MathGlyphVariantRecords +mathItalicsCorrectionInfo +MathItalicsCorrectionInfo +mathKern +MathKern +mathKernCoverage +mathKernInfo +MathKernInfo +MathKernInfoRecord +mathKernInfoRecords +MathKernInfoRecords +MathSymbols +mathTopAccentAttachment +MathTopAccentAttachment +MathValueRecord +mathValueRecords +MathValueRecords +mathValueRecordsZ +mathVariants +MathVariants +matra +Matra +MATRA +matras +Matras +matrix +Matrix +matrixZ +matter +Matthias +Mattole +Matu +max +Max +MAX +maxBeforeBL +maxComponentDepth +maxComponentElements +maxCompositeContours +maxCompositePoints +maxContours +maxCoord +MaxDebugDepth +maxExtent +maxFunctionDefs +maxGlyphCount +maximum +Maximum +maximumLimit +maximums +maxInstructionDefs +maxMemType +maxp +MAXP +maxPoints +maxpV +maxSizeOfInstructions +maxStackElements +maxStorage +maxTwilightPoints +maxVal +maxValue +maxWidth +maxZones +may +May +MAY +Mayan +maybe +Maybe +MAYBE +Mayek +MAYEK +Mayo +Mazanderani +mb +MB +mbarrier +Mbembe +mBidiLevel +MBlw +mbo +Mbo +mbstowcs +Mbundu +Mbyá +Mc +mcm +mct +mCurrentRun +md +MD +mdash +mData +mdf +mdr +mdy +me +Me +mean +MEAN +meaning +meaningfully +meanings +means +Meanwhile +measurable +measure +MEASURE +measured +measuring +mechanical +mechanism +MED +MEDEFAIDRIN +medi +MEDI +medial +Medial +MEDIAL +median +medifinaLamAlefSubLookup +mediLookup +mediSubLookup +Medium +MEDIUM +Medumba +MEEM +Meetei +MEETEI +Meh +MEM +memaccess +member +members +Members +memcmp +memcpy +memmove +memoize +memory +Memory +MEMORY +MemoryBarrier +memset +men +Mende +MENDE +Mengisa +mentioned +mentions +menu +meo +mer +MERCHANTABILITY +merge +Merge +merged +merger +merges +merging +Merging +MEROITIC +Meru +Merwari +Mescalero +Mesopotamian +message +MESSAGE +messaging +messed +meta +Meta +META +metadata +Metadata +metamorphosis +Metamorphosis +meteg +method +methods +Methods +metric +METRIC +metricDataFormat +metrics +Metrics +METRICS +Mewari +Mewati +Mexico +mfa +mfb +mfe +mFontFileStream +mg +mGlyphCount +mGlyphStart +mh +MH +mhr +mhv +mi +Miao +MIAO +Michiharu +micro +MICRO +microsoft +Microsoft +microsqoft +MicroType +mid +middle +Middle +midnight +might +Might +min +Min +MIN +minAdvanceSB +minAfterBL +Minangkabau +minConnectorOverlap +minCoord +mind +mingw +MinGW +MINGW +minHeight +MINI +minimal +minimum +Minimum +minimumLimit +minimums +Minjangbal +Minjungbal +minLeadingBearing +minlen +minMax +MinMax +minMaxCoord +minMemType +Minnan +minor +MINOR +minOriginSB +minorVersion +minstd +minTrailingBearing +minus +MINUS +minVal +minValue +minVersion +Minz +Mirandese +Miraya +mirror +mirroring +Mirroring +misc +Misc +Miscellaneous +MISMATCH +mIsSideways +missing +MIT +mix +mixed +mixin +Mixin +Mixing +mixture +Mizo +mk +mkmk +mku +mkw +ml +ML +mLocaleName +mlq +MLYM +mm +MM +mman +MMAN +mmap +Mmap +MMAP +mmr +mn +Mn +mnc +mnemonics +mni +mnk +mnp +mns +mnw +mo +mod +MOD +mode +Mode +MODE +model +models +Modern +modes +Modi +MODI +modification +Modification +modifications +MODIFICATIONS +modified +Modified +MODIFIED +modifiedClusterMap +modifiedGlyphAdvances +modifiedGlyphIndices +modifiedGlyphOffsets +modifier +Modifier +MODIFIER +modifiers +modify +Modify +modifying +Modifying +MODIFYING +modulo +moh +Mohawk +Moksha +Moldavian +Moldova +Moldovan +Moluccan +Mon +Monaco +Mongolia +mongolian +Mongolian +MONGOLIAN +Mono +monospaced +MONOSPACED +monotone +MONOTONE +monotonic +monotonically +monster +Months +Moose +more +More +MORE +MoreToolbox +Morisyen +Moroccan +Morocco +morphHeader +mort +MORT +mortmorx +morx +MORX +mos +Mossi +most +Most +mostly +Motorola +Motu +move +Move +moved +moves +moveto +moving +Moving +mozilla +Mozilla +mpe +MPre +mprotect +MPROTECT +MPst +mqg +mr +MR +mReadingDirection +mrh +mrj +Mro +MRO +mRunHead +ms +MS +msc +MSC +mScript +msdn +msg +MSG +msgidx +msgstr +msh +msi +mSize +Msmall +msuperior +MSVC +mt +MT +mText +mTextLength +mTextStart +mtr +mtx +mu +much +mui +MUJ +mul +MulFix +Muller +mult +Multani +MULTANI +multi +multiple +Multiple +MULTIPLE +MultipleSubst +MultipleSubstFormat +multiplication +multiplicative +multiplied +MULTIPLIED +multiply +MULTIPLY +multiplying +mults +Mundari +munmap +mup +muq +mus +Muscogee +Musi +Musical +MUSICAL +must +Must +MUST +mutable +mutex +MUTEX +mutually +mvar +MVAR +mvb +mve +mvf +MW +Mwali +mwk +mwl +mwr +mww +my +MY +myanmar +Myanmar +MYANMAR +mym +mymr +myn +myq +myv +mzn +n +N +na +NABATAEAN +Nacional +nag +Naga +Nagari +Nagri +NAGRI +nags +nah +Nahuatl +naive +Najdi +nalf +nalfType +name +Name +NAME +named +Named +nameid +nameID +NameID +nameids +nameIndex +NameIndex +nameIndexOffset +nameList +namely +Namely +nameOffset +NameRecord +nameRecordZ +names +Names +NAMES +nameSIDs +namespace +Namespace +NAMESPACE +namesX +namesZ +nameTag +Naming +nan +Nan +Nanai +Nandi +Nandinagari +NANDINAGARI +nap +Napo +NARROW +narrowing +nasalization +Naskapi +native +NativeFontResourceDWrite +natural +Nauru +Nauruan +navajo +Navajo +nb +NC +nClasses +nCodes +NCount +NCOUNT +nd +Nd +ndash +Ndau +ndc +Ndebele +NDEBUG +Ndonga +nds +Ndzwani +ne +Neapolitan +necessarily +necessary +need +Need +needed +needing +needs +Needs +neg +NEG +negation +negative +Negative +NEGATIVE +Negeri +NEGLIGENCE +negotiate +neighboring +neither +nel +Nenets +Neo +Nepal +Nepali +nesting +NESTING +net +NetBSD +Netherlands +neuter +neutrals +never +Never +nevertheless +new +New +NEW +Newa +NEWA +Newari +newBits +newCount +newer +newlocale +NEWLOCALE +newly +newRun +newState +next +Next +NEXT +nextRun +NFC +NFD +ng +NG +nga +Ngawn +Ngazidja +Ngbaka +ngl +ngo +NGOEH +Ngoni +nhd +nibble +Nibble +nibbles +Nicaragua +nice +Niger +Nigeria +Nigerian +nikhahit +Nikhahit +NIKHAHIT +nil +NIL +Nimadi +nindex +nine +NINE +nineinferior +nineoldstyle +ninesuperior +NINETEEN +niq +Nirmala +Nisi +niu +Niuean +niv +NJ +Njua +njz +NKD +nko +NKo +NKO +Nkoo +nl +Nl +NLCCHARACTERS +nle +nLeft +nmemb +nn +NNOffsetTo +no +No +NO +nod +node +nodes +noe +noErr +nog +Nogai +nominal +NOMINAL +nominalValue +nominalWidthX +non +Non +NON +Nonaka +NonAlphabetic +nonbreakingspace +noncontextual +Noncontextual +NoncontextualSubtable +nonDefault +nonDefaultUVS +NonDefaultUVS +none +NONE +nonexistent +Nong +nonliteral +nonmarkingreturn +nonmonotonic +nonnull +nonspacing +NonStop +nonzero +NOON +NOP +noporpoise +nor +Nor +NORESERVE +Norfolk +normal +NORMAL +normalization +Normalization +NORMALIZATION +normalize +NORMALIZE +normalized +normalizer +normally +Normally +North +NORTH +Northeastern +Northern +Northwest +Northwestern +Norway +Norwegian +noStretchValue +not +Not +NOT +notable +notably +Notably +Notation +notdef +NOTDEF +NotDefault +note +Note +NOTE +noted +notequal +notes +NOTES +nothing +Nothing +notice +Notice +noticeably +notification +notified +notifiers +NOTIMPL +noting +notionally +Noto +NotoSerif +nounihan +nov +novalidate +NOVAR +Novial +now +Now +np +npi +nqo +nr +nRanges +nSettings +nSizes +nsk +NSLanguage +Nsmall +nso +nSubrs +nsuperior +nSups +ntilde +Ntilde +Ntildesmall +nTracks +Nüa +Nuke +NUKT +nukta +Nukta +NUKTA +nul +NUL +null +Null +NULL +nullable +NullHelper +NullPool +NullPriority +nullptr +num +Num +NUM +numBaseGlyphs +number +Number +NUMBER +numberOfContours +numberOfFaces +numberOfIndexSubtables +numberOfLongMetrics +numbers +Numbers +NUMBERS +numbersign +numberSubstitution +numBlends +numColorRecords +numColors +numeral +NUMERAL +numerals +Numerals +numeration +NUMERATOR +numeric +numerical +Numerical +numGlyphs +numLayers +numNamedParameters +numOfHMetrics +numPalettes +numParameters +numr +numRecords +numScriptCode +numTables +numValues +NUN +nUnits +NUSHU +Nuskhuri +nv +ny +Nyala +Nyamwezi +Nyanja +Nyankole +nyd +NYEH +NYIAKENG +Nyishi +nym +nyn +Nynorsk +Nyore +nza +o +O +oacute +Oacute +Oacutesmall +oasis +OASIS +obj +OBJ +object +Object +OBJECT +objects +Objects +objidx +OBLIGATION +oblique +Oblique +OBLIQUE +obliqueing +obscure +Obsolete +obsoleted +ObsoleteTypes +obtained +obvious +oc +occasionally +Occitan +occupancy +occupy +occurrence +occurrences +occurring +occurs +ocircumflex +Ocircumflex +Ocircumflexsmall +odd +oddly +Odia +odieresis +Odieresis +Odieresissmall +oe +OE +OEM +OEsmall +of +Of +OF +off +Off +OFF +offer +offers +offload +offs +OFFS +offset +Offset +OFFSET +OffsetArrayOf +offsetArrayZ +OffsetListOf +offsetof +offsets +Offsets +OffsetTable +OffsetTables +OffsetTo +offsetToAxisValueOffsets +offsetToIndex +offsetToSubtable +OffsetType +offsetZ +offSize +ofs +Ofs +often +Often +og +Ogham +OGHAM +ogonek +Ogoneksmall +ograve +Ograve +Ogravesmall +Oh +Oirat +oj +ojb +ojc +ojg +Oji +Ojibwa +Ojibway +Ojitlán +ojs +ojw +ok +Ok +OK +oki +Okiek +okm +Ol +OL +old +Old +OLD +older +Older +OLDER +om +Oman +Omani +Omega +omitted +on +On +ON +once +Once +one +One +ONE +OneByteIntFirst +OneByteIntLast +onedotenleader +oneeighth +onefitted +onehalf +oneinferior +oneoldstyle +onequarter +ones +onesuperior +onethird +only +Only +ONLY +onto +OOP +op +Op +OP +opaque +Opaque +opbd +OPBD +opbdFormat +opcode +OpCode +opcodes +opeator +open +Open +OPEN +OpenBSD +opentype +OpenType +OPENTYPE +OpenTypeFontFace +OpenTypeFontFile +OpenTypeTable +operand +operands +operate +operates +operating +operation +operations +Operations +operator +Operator +OPERATOR +operators +Operators +opportunities +OPPORTUNITY +opposite +ops +OPS +opset +OPSET +opStart +opstr +OPSTR +opsz +opszr +optical +Optical +OPTICAL +OpticalBounds +OpticalSize +optimal +optimally +optimization +optimizations +optimize +Optimize +OPTIMIZE +optimized +opting +option +OPTION +optional +Optional +OPTIONAL +optionally +options +OPTIONS +opts +or +Or +OR +oracle +Orang +orc +order +Order +ORDER +ordered +orderedlist +ordering +ordfeminine +ordinal +ORDINALS +ordmasculine +org +Organization +oriented +orig +origin +Origin +original +originally +Originally +originated +origins +origRun +Oriya +ORIYA +Orma +orn +ORNAMENT +ORNAMENTS +Oromo +ors +orthogonal +orthographic +Orthographic +orthographically +ory +ORYA +os +OS +OSAGE +OSAtomic +OSAtomicAdd +OSAtomicCompareAndSwap +OSAtomicCompareAndSwapPtrBarrier +oslash +Oslash +Oslashsmall +Osmall +Osmanya +OSMANYA +OSMemoryBarrier +Ossetian +OSStatus +osuperior +ot +OT +otf +otFeatureTag +OTFontFileVal +OTHeader +other +Other +OTHER +OtherBlues +others +otherwise +Otherwise +OTHERWISE +otilde +Otilde +Otildesmall +otspec +Ottawa +OTTO +otw +Ouch +OUCH +ought +our +Our +ourself +ourselves +out +Out +OUT +outbuffer +outcome +outer +Outer +outerIndex +outline +Outline +OUTLINE +OUTLINED +outlines +OUTOFMEMORY +outOfRange +output +Output +OutputArray +outside +outward +over +OVERBAR +overflow +OVERFLOW +Overflowed +overflows +Overflows +overhead +overlap +OVERLAP +OVERLAPPED +overlapping +OVERLAPPING +OVERLAY +overloaded +overloading +overridden +override +Override +OVERRIDE +overriden +overrides +Overrides +overriding +overstrike +Overstruck +OVERSTRUCK +overview +overwrite +Owen +own +owned +ownership +Ozumacín +p +P +pa +Pa +PA +pABC +Pacaraos +pack +package +packages +packed +pad +padauk +Padauk +padded +padding +PADMA +pag +page +PAGE +pages +pagesize +PAGESIZE +Pahari +PAHAWH +Pahlavi +PAHLAVI +PaintType +pair +Pair +Paired +pairing +PairPos +PairPosFormat +pairs +Pairs +pairSet +PairSet +PairValueRecord +PairValueRecords +pairwise +Paite +Pakistan +Palantla +Palauan +Palaung +Palestinian +palette +Palette +PALETTE +paletteFlagsZ +paletteLabelsZ +palettes +Pali +PALMYRENE +Palpa +pam +Pampanga +Pampangan +Panama +Panao +Pangasinan +pango +Pango +Panjabi +panose +Pao +pap +Papiamento +Papiamentu +para +paragraph +PARAGRAPH +paragraphs +Paraguay +Paraguayan +parallel +param +PARAM +parameter +parameters +Parameters +PARAMETERS +params +PARAMS +paren +parenleft +parenleftinferior +parenleftsuperior +parenright +parenrightinferior +parenrightsuperior +parent +Parent +parentheses +PARENTHESIS +parity +parse +parsed +parser +PARSER +parses +Parses +parsing +part +Part +PART +partFlags +PartFlags +PARTHIAN +partial +Partial +partialdiff +PARTIALIZE +partially +PARTIALLY +partically +participate +participates +particular +PARTICULAR +particularly +partRecords +parts +Parts +PARTY +Pascal +Pasco +Pashto +pass +Pass +passed +PASSED +passes +passing +passthru +past +Pastaza +paste +PASTE +patah +path +PATH +Pattani +pattern +patterns +Patterns +pau +PAU +pause +pauses +pb +pbt +pbu +Pc +PC +pcc +pcd +pce +pcGlyphs +pCharProps +pchars +pcItems +pck +pcTable +pd +Pd +pdc +pdefault +pdf +PDF +pdfs +pe +Pe +PE +peak +peakCoord +peakTuple +peculiarities +peculiarity +pedantic +Pedi +peek +PEH +PEHEH +Pekal +pel +pend +Pennsylvania +people +People +per +Per +PER +percent +Percent +PERCENT +percentage +percentScaleDown +perfect +perform +Perform +performAction +PerformAction +performance +PERFORMANCE +performed +performing +Performing +performs +Performs +perhaps +period +PERIOD +periodcentered +periodinferior +PERIODS +periodsuperior +peripheral +Peripheral +permanently +PERMIC +permissible +permission +Permission +permissions +permissive +permitted +permute +Permyak +perpendicular +Persian +PERSIAN +persistent +person +perspective +pertaining +perthousand +Peru +pes +PETITE +Pf +pg +pga +pglyph +pGlyphProps +pGoffset +pgwide +Phags +PHAGS +Phaistos +Phake +Phalaa +phantom +PHANTOM +phantoms +phase +Phase +phases +Phases +phi +Philippines +PHINTHU +phk +Phoenician +PHOENICIAN +PHONE +Phonetic +phrase +PHRASE +PHRU +pi +Pi +PI +piAdvance +Picard +PiCharacters +pick +picks +pictographic +Pictographic +Pictures +PICTURES +Pidgin +pidgins +piece +piecemeal +pieces +Piemontese +pih +pinfo +pipes +Pisin +Pitcairn +pItems +pivot +Pivot +pivots +pixel +Pixel +pixels +pixelSize +pj +pk +PK +pkey +pkg +pkgconfig +pko +pl +place +Place +placed +placeholder +Placeholder +PLACEHOLDER +placeholders +placement +PLACEMENT +placements +plain +Plains +plan +Plan +PLAN +plane +Plane +planes +planned +planner +planning +plans +Plans +Plateau +platform +Platform +platformID +platforms +ple +please +plen +plevel +pll +plookups +plp +plt +plus +PLUS +plusminus +pms +pnb +png +PNG +PNGHeader +po +Po +Pocomchi +poh +Pohnpeian +point +Point +POINT +pointed +pointer +Pointer +pointers +pointing +points +POINTS +POISON +Pökoot +Poland +Polish +polyton +polytonic +Polytonic +pon +pool +POOL +pools +poor +pop +popcount +popcountl +popcountll +popped +pops +populate +Populate +population +Poqomchi +port +Port +portability +portal +Portugal +Portuguese +pos +Pos +POS +positinoing +position +Position +POSITION +Positional +positioned +positioning +Positioning +positions +POSITIONS +positive +Positive +POSIX +PosLookup +PosLookupSubTable +possibility +POSSIBILITY +possible +Possible +possibly +post +Post +POST +PosTable +postcompensation +PostcompensationActionChain +posted +postfix +Postfixed +POSTFIXED +postponing +postprocess +postscript +Postscript +PostScript +POSTSCRIPT +postScriptNameIDX +postV +potential +potentially +potfRecords +Pournader +pOutGlyphProps +pow +power +powers +pp +ppa +ppc +ppem +PPEM +ppemX +ppemY +PPI +ppObject +pPos +pr +practical +practice +pragma +PRAGMA +pragmas +PRC +pre +Pre +PRE +precede +precedence +preceding +Preceding +PRECEDING +precious +precision +precomposed +Pred +predef +predefined +Predicate +predicates +predictable +pref +PREF +prefer +Prefer +preferable +preference +preferences +preferred +Preferred +prefers +prefix +PREFIX +prefixed +Prefixed +PREFIXED +preloadAll +prepare +Prepare +preparing +preprocess +preprocessor +PREREQ +pres +PRES +presence +present +PRESENT +presentation +Presentation +preserve +PRESERVE +preserved +preserving +presForm +presidential +pressure +PRETTY +prev +PREV +prevent +PREVENT +prevented +preventing +prevents +previous +previously +Previously +Pri +primarily +primary +prime +primitives +PRIMITIVES +Principality +print +Print +printed +printer +Printer +printf +PRINTF +printing +prints +prior +priorities +prioritize +priority +Priority +priv +private +Private +PRIVATE +PrivateDict +privateDictInfo +privateDictInfos +privateDicts +privateDictsOffset +privateInfos +PrivatePointNumbers +privDictStr +PRIVDICTVAL +privInfo +PRIVOPSET +privSzr +pro +probable +probably +Probably +Probing +problem +problems +Procedure +proceed +proceeding +process +Process +processed +processes +processing +procs +produce +produced +Produced +produces +product +Profile +PROFITS +program +programlisting +programming +programs +Programs +Proj +project +projection +Projection +promise +promotion +propagate +Propagate +proper +properly +properties +PROPERTIES +property +PROPORTIONAL +proportionally +props +PROPS +PROT +protected +Protection +prototypes +provenc +Provençal +proves +provide +PROVIDE +provided +PROVIDED +provider +provides +Provides +Province +proxy +Proxy +prs +prune +ps +Ps +PS +psa +Psalter +PSALTER +psc +psControl +pScriptTags +pse +pseudo +Psmall +psState +pst +pstf +PSTF +PString +PSTS +psva +pt +PT +ptem +pthread +PTHREAD +ptr +PTR +ptrdiff +Pu +pua +PUA +PUACHUE +public +Public +PUBLIC +publicly +published +Puerto +Pulaar +Pular +pull +Pull +punctuation +Punctuation +PUNCTUATION +Punjabi +Puno +pure +Pure +PURE +purely +purpose +PURPOSE +purposes +push +Push +put +Put +puts +pv +pval +pwcChars +pwcInChars +pwGlyphs +pwLogClust +pwo +Pwo +pwOutGlyphs +px +py +Python +q +Q +Qaai +QAF +qamats +QAMATS +Qatar +Qiandong +Qimant +Qiubei +QOF +Qsmall +qsort +QSORT +QType +qu +QUAD +QuadPart +qualifiers +quantity +QUARTER +qub +qubuts +quc +qud +Quechua +queried +queries +query +querying +QueryInterface +question +QUESTION +questiondown +questiondownsmall +questions +questionsmall +quf +qug +quh +Quichua +quick +quickly +quicksort +Quicksort +Quiotepec +quite +quk +qul +quot +quotation +quotations +quote +quotedbl +quotedblbase +quotedblleft +quotedblright +quoteleft +quoteright +QUOTES +quotesinglbase +quotesingle +Quotient +Quoting +qup +qur +qus +qut +quw +qux +quy +quz +qva +qvc +qve +qvh +qvi +qvj +qvl +qvm +qvn +qvo +qvp +qvs +qvw +qvz +qwa +qwc +qwh +qws +qxa +qxc +qxh +qxl +qxn +qxo +qxp +qxr +qxt +qxu +qxw +r +R +ra +Ra +RA +race +races +radical +RADICAL +radicalDegreeBottomRaisePercent +Radicals +rafe +RAFE +rag +ragel +Raise +RAISE +raises +raj +Rajasthani +Rakhine +ran +rand +random +Random +RANDOM +randomize +Randomly +range +Range +RANGE +rangeCount +rangeEnd +rangeGaspBehavior +rangeMaxPPEM +rangeMaxValue +rangeMinValue +rangeoffset +rangeOffset +rangeRecord +RangeRecord +ranges +Ranges +RANGES +rangeShift +RangeShift +rangeStart +Ranglong +rar +rare +RARE +Rarely +Rarotongan +rasterizer +rate +rather +ratio +raw +rb +rbb +rbl +RC +rclt +rcRangeChars +RCU +rcurveline +RD +RDONLY +re +Re +reach +reaches +read +Read +READ +readable +reader +ReadFileFragment +READING +readingDirection +readjusting +readonly +READONLY +ready +real +Real +realistic +reality +realloc +reallocate +Reallocate +reallocating +really +Really +rearranged +rearrangement +Rearrangement +REARRANGEMENT +RearrangementSubtable +reason +reasons +reassign +reassigned +reassignment +reassignSIDs +rebuild +REBUS +rec +recalculated +recategorize +receive +recent +recently +Recognition +recognizable +recognize +recognized +recognizes +recom +recommended +recompose +recomposed +recomposing +recomposition +reconfiguration +reconfigured +reconfiguring +record +Record +RECORD +RecordArrayOf +recording +RecordList +RecordListOf +records +Records +Recover +recovery +recreate +recurring +recurse +recursed +Recursed +recursing +recursion +recursive +recursively +Recursively +red +Red +redefine +redefined +redirected +redone +Redu +reduce +redundant +reenabling +ref +refcount +refer +reference +Reference +REFERENCE +referenced +referenceGlyph +references +referred +referring +refers +REFIID +refine +refinements +reflect +reflecting +reflects +Reformed +refs +REGARD +regardless +Regex +region +Region +regionCount +regionIndices +regions +register +Register +REGISTER +registered +RegisterFontFileLoader +registers +registry +Registry +regular +Regular +REGULAR +REH +reinterpret +rej +Rejang +REJANG +reject +Reject +rejection +rel +REL +related +relation +relationship +relative +relax +relaxed +RELAXED +release +Release +RELEASE +released +releasedc +ReleaseDC +ReleaseFileFragment +ReleaseFontTable +releases +relevant +relicensed +relies +relocating +rely +Rely +relying +remain +remainder +remained +remaining +remains +remap +remapping +remaps +Remarks +remember +Remember +remembered +Removable +removal +remove +Remove +REMOVE +removed +RemoveFontMemResourceEx +removing +rename +render +rendered +renderer +rendering +renders +renum +renumber +Renumber +renumbering +renumbers +reorder +Reorder +reordered +REORDERED +reordering +Reordering +reorders +Reorders +Repack +repeat +REPEAT +repeated +repeatedAddGlyphAction +RepeatedAddGlyphAction +repeating +REPEATING +reph +Reph +REPH +repha +Repha +REPHA +replace +Replace +replaced +REPLACEME +replacement +REPLACEMENT +replaces +Replaces +replacing +replicate +report +Report +reports +Reports +repositioned +repositioning +repository +represent +representation +representations +represented +representing +represents +Represents +reproduces +Republic +reqFeatureIndex +request +requested +requests +require +Require +required +REQUIRED +requirement +requirements +requires +Requires +requiring +res +resCountM +research +reserved +Reserved +RESERVED +reservedESC +ReservedESC +reservedPad +reset +Reset +Resets +RESH +reshaping +reside +resize +resizing +resolution +resolutions +resolve +Resolved +resolvedLevel +resolver +resolves +resort +Resort +resource +Resource +ResourceForkHeader +ResourceMap +ResourceRecord +resources +resourcesZ +ResourceTypeRecord +respect +respective +respectively +responsibilities +responsibility +responsible +resreved +rest +RESTORE +restrict +restructuring +result +resulted +resulting +RESULTING +results +resume +ret +Ret +RET +retain +Retain +retained +retains +RETAINS +retired +retrieve +retrieved +retrieves +Retrieves +retry +return +Return +RETURN +returned +Returned +returning +returns +Returns +reuse +reused +reusing +reverse +REVERSE +reverseChainContextSingle +ReverseChainSingle +ReverseChainSingleSubst +ReverseChainSingleSubstFormat +reversed +Reverses +reversing +revert +revised +rewind +Rewind +rewinding +Rewinding +Rewrite +rfHeader +RHA +RHEL +rhs +Rhs +ri +ria +Riang +Rica +Rico +ridentity +Rieger +rif +right +Right +RIGHT +rightC +rightClass +rightClassCount +rightClassTable +rightSide +RightToLeft +Rinconada +ring +Ringsmall +Ripuarian +rise +RISE +RISH +risking +rit +Ritarungo +rki +RKRF +rkw +rl +rlig +rligLookup +rligMarksLookup +rlinecurve +rlineto +rm +RM +rmc +rmf +rml +rmn +rmo +rmoveto +rmw +rmy +rmz +rn +rnl +RNOON +ro +Ro +RO +road +Robatic +Roberts +rock +Rod +Roderick +Rohingya +ROHINGYA +role +roll +rom +Roman +ROMAN +Romani +Romania +Romanian +ROMANIZATION +Romansh +Romany +room +root +rooted +Roozbeh +ros +ROS +rotate +rotated +Rotuman +round +ROUND +ROUNDED +roundf +ROUNDF +rounding +rounds +routine +routines +roux +Roux +row +rowCount +rowIndexTable +rows +rowWidth +royalty +RP +rpc +rphf +RPHF +rpRangeProperties +RRA +rrcurveto +RREH +RS +rsb +rsbMap +Rsmall +rsuperior +Rsv +rt +rtl +RTL +rtlm +rtm +ru +Ruanda +RUBY +Ruching +rue +rule +Rule +RULE +rules +Rules +ruleSet +RuleSet +rulesets +ruleSets +Rumai +run +Run +RUN +Rundi +runHead +Runic +RUNIC +running +runs +runtime +Runtime +rup +rupiah +Russia +Russian +Rusyn +rvalue +rvalues +Rvalues +rw +Rwanda +rwr +Ryan +s +S +sa +Saamia +Sabah +Sabaot +Sad +SAD +Sadri +safe +safely +safest +sah +Saharan +said +Saidi +Saint +Sakalava +sake +Sakha +sakot +SAKOT +sal +Salasaca +salt +Salvador +sam +Samaritan +SAMARITAN +Sambalpuri +same +Same +SAME +SAMEKH +Sami +Samoan +Samogitian +sample +SAMPLE +sampleTextNameId +sampleTextNameID +San +Sanaani +sandboxed +sane +Sango +sanitization +sanitizations +sanitize +Sanitize +SANITIZE +sanitized +sanitizer +sanitizing +Sanitizing +sanity +Sankaran +Sans +Sanskrit +Santa +Santali +Santiago +santization +SAR +sara +SARA +Saraiki +Sardinian +Sarsi +sas +Sasak +Sascha +Sassarese +sat +Saterfriesisch +Saterland +Saudi +Saurashtra +SAURASHTRA +save +Save +SAVE +saved +savedprops +Saves +saw +Saxon +say +Sayisi +says +sb +SBase +SBASE +SBitLineMetrics +sbix +SBIX +SBIXGlyph +SBIXStrike +sbl +SBL +SBLHebrewUserManual +sc +Sc +SC +Scalable +scalar +Scalar +scalars +scale +SCALE +scaled +SCALED +scalef +scaler +scaling +scan +Scan +sCapHeight +scaron +Scaron +Scaronsmall +scedilla +Scedilla +scenario +scenarios +SCHAR +sched +SCHED +scheme +Schouten +science +SCIENTIFIC +sck +scn +sco +sconsumed +scope +score +Scots +Scottish +scount +SCount +SCOUNT +scratch +SCRATCH +screen +script +Script +SCRIPT +scriptAnalysis +scriptCode +ScriptExtensions +ScriptFreeCache +ScriptItemize +ScriptItemizeOpenType +scriptList +ScriptList +ScriptPlace +ScriptPlaceOpenType +scriptProperties +scripts +Scripts +SCRIPTS +ScriptShape +ScriptShapeOpenType +ScriptTag +scripttags +scs +scursor +sd +SD +sDageshForms +sdc +sdh +SDL +sdn +se +seac +search +Search +SEARCH +searched +searching +searchRange +Sebat +sec +second +Second +secondGlyph +seconds +sect +section +SECTION +sections +security +sed +see +See +seeing +seek +seem +seems +Seems +seen +SEEN +seenCrossStream +seequence +sees +seg +segcount +segCount +segCountX +segment +Segment +SEGMENT +segmented +segmenting +SegmentMaps +segments +segol +seh +Seigo +sek +Sekani +Sekota +sel +select +Select +selected +selecting +selection +selections +selectively +SelectObject +selector +Selector +SELECTOR +selectors +Selectors +SELECTORs +selectorToDisable +selectorToEnable +selects +Seletar +self +Selkup +semantic +semantical +SEMANTICS +Sembilan +semi +SEMI +Semibold +semicolon +SEMICOLON +Sena +send +sending +Senegal +sense +sensible +sensitive +SENSITIVE +sensitivity +sent +sentence +Senthang +sentinel +SENTINEL +separate +separated +separately +separation +Separator +SEPARATOR +seq +sequence +Sequence +sequenceIndex +sequences +SEQUENCES +sequential +sequentially +Serbia +Serbian +Serer +serial +serialization +serialize +Serialize +SERIALIZE +serialized +serializer +SERIALIZER +Serializes +series +Serif +serve +servers +serves +Sesotho +set +Set +SET +SetBidiLevel +SetComponent +SetCurrentRun +SetLineBreakpoints +setlocale +SETLOCALE +SetMark +SetNumberSubstitution +sets +Sets +SETS +SetScriptAnalysis +Setswana +setter +setters +setting +Setting +SettingName +settings +settingTableZ +setup +Setup +seven +SEVEN +seveneighths +seveninferior +sevenoldstyle +sevensuperior +SEVENTEEN +several +severely +Severn +sez +sFamilyClass +sfinae +SFINAE +sfm +SFNSDisplay +SFNSText +sfnt +Sfnt +SFNT +sfntVersion +sg +sga +sgc +sgi +sgs +sgw +sh +sha +shadda +Shadda +SHADDA +shaddaLigature +shaddaLigatureSet +shaddaLigaturesSubLookup +Shadow +SHADOW +shall +SHALL +shallow +Shan +shape +Shape +SHAPE +shaped +shaper +Shaper +SHAPER +shaperprefs +shapers +Shapers +SHAPERS +shapes +Shapes +SHAPES +shaping +Shaping +SHAPING +Sharada +SHARADA +share +SHARE +shared +Shared +SHARED +SharedPointNumbers +sharedTupleCount +sharedTuples +Shavian +SHAVIAN +SHEEN +Sheeter +Shekhawati +shell +SHELL +sheva +shi +shift +Shift +SHIFT +shifted +Shifter +SHIFTER +shifting +Shifting +Shihhi +shin +SHIN +ship +shipped +shn +Shona +short +Short +SHORT +shortCount +shortcut +shortcuts +shortest +shortfall +Shorthand +SHORTHAND +shortint +shoudln +should +Should +shouldn +Shouldn +show +SHOW +showing +shows +shrink +Shrinkage +shrinkageDisableGPOS +shrinkageDisableGSUB +shrinkageEnableGPOS +shrinkageEnableGSUB +shrinkageJstfMax +shrinkFlags +SHRT +shu +Shua +shuffle +Shurishkar +shut +Shut +Shwe +si +Sibe +SIBLING +Sichuan +Sicilian +sid +SID +Sidamo +Siddham +SIDDHAM +side +sidebearing +sides +sidmap +sids +SIDs +Sierra +sign +Sign +signature +signed +Signed +SIGNED +signedness +significance +significant +significantly +signifying +signs +SIGNWRITING +Sihuas +Siksika +sil +SIL +silently +Silesian +silf +Silf +SILF +Silt +Silte +Simalungun +similar +Similar +similarly +Similarly +SIMP +simple +Simple +SIMPLE +SimpleGlyph +simpler +simplest +simplicity +simplification +simplified +Simplified +SIMPLIFIED +simplifies +Simplifies +simplify +simply +SIMULATIONS +sin +SIN +since +Since +Sindhi +Singapore +single +Single +SINGLE +SinglePos +SinglePosFormat +SingleSubst +SingleSubstFormat +singleton +singletons +singular +SINH +sinhala +Sinhala +SINHALA +Sinhalese +sink +Sink +sinks +Sinte +SIOT +Sit +site +sites +situations +six +SIX +sixinferior +sixoldstyle +sixsuperior +sixteen +SIXTEEN +Siyin +size +Size +SIZE +sized +SIZED +sizeDeviceRecord +sizeof +sizes +sizeTable +sizeTables +sizing +sjd +sjo +sk +Sk +SKEWED +skg +skip +Skip +SKIP +skippable +skipped +skipping +Skipping +skippy +Skolt +skr +sl +SL +slant +Slant +SLANT +slanted +slash +SLASH +SLASHED +Slave +Slavey +Slavonic +slen +slightly +slim +slnt +slope +slot +slots +Slovak +Slovakia +Slovenia +Slovenian +slower +sm +Sm +SM +sma +SMAbv +small +Small +SMALL +smaller +smallest +Smallest +SmallGlyphMetrics +smart +SMART +SMBlw +smj +smn +smoking +sms +SMVD +sn +snap +snapshot +sniff +snk +snprintf +so +So +Sochiapam +Sodo +SOFT +software +Software +SOFTWARE +Soga +Sogdian +SOGDIAN +Solaris +SOLARIS +solely +solution +Somali +some +Some +Somebody +somefunc +somehow +Somehow +someone +something +sometime +sometimes +somewhat +SOMPENG +Songe +Soninke +soon +sop +SORA +Sorbian +sort +Sort +SORT +sorted +Sorted +SORTED +SortedArrayOf +sortedness +SortedUnsizedArrayOf +sorting +SORTING +Sotho +SOUND +sounds +source +Source +SOURCE +sourceware +South +SOUTH +Southeast +Southeastern +Southern +Southwestern +Soyombo +SOYOMBO +spac +space +Space +SPACE +spaced +spaces +Spaces +spacing +Spacing +SPACING +Spain +Spanish +spans +speaking +spec +Spec +special +Special +SPECIAL +Specialization +specializations +Specializations +Specialize +specially +Specials +specific +specifically +SPECIFICALLY +specification +specifications +specificed +specifics +specified +specifies +specify +specifying +specs +speculative +speed +Speed +speeds +split +Split +SplitCurrentRun +splitPoint +splitPosition +Spoon +SPOT +Spread +spreadsheets +Spring +spv +spy +sq +sqrt +Square +SQUARE +SQUARED +squeezing +sr +src +Sri +sro +srr +srs +ss +ssh +Ssmall +SSOT +ssuperior +ssxx +ssXX +st +stable +stack +Stack +STACK +Stacker +STACKER +stacking +stackoverflow +stage +stages +STAGES +stale +standalone +standard +Standard +StandardEncoding +standardheaderfiles +standards +stands +start +Start +START +startCharCode +startcode +startCode +startConnectorLength +startCoord +startCount +started +Started +starter +Starter +startGlyph +startGlyphID +startGlyphIndex +starting +Starting +StartOfText +starts +startSize +startUnicodeValue +stat +STAT +StatAxisRecord +state +State +STATE +stateArrayTable +stateHeader +statement +states +States +STATES +StateTable +StateTableDriver +stateTableOffset +static +Static +STATIC +status +stay +stays +stch +STCH +std +STD +stdarg +stddef +stderr +stdGlyph +StdHW +stdint +stdio +stdlib +STDMETHODCALLTYPE +STDMETHODIMP +StdVW +stem +StemSnapH +StemSnapV +step +STEP +stepping +steps +sterling +stHeader +still +Still +stmt +STMT +stop +Stop +STOP +stopped +stops +storage +Storage +store +Store +STORE +stored +Stored +storing +stq +str +STR +straight +Straight +straightforward +strategic +strategy +Strategy +strbuf +strchr +strcmp +strcpy +strdup +stream +streams +strerror +stretch +Stretch +STRETCH +stretchable +stretched +stretchGlyphAction +StretchGlyphAction +stretching +Stribley +Strict +STRICT +strictly +stride +strike +strikeout +STRIKEOUT +strikes +string +String +STRING +stringIndex +StringIndex +stringIndexInfo +stringOffset +strings +strlen +strncmp +strncpy +stroke +Strokes +StrokeWidth +strong +strongly +strstr +strtod +STRTOD +strtol +strtoul +struct +StructAfter +StructAtOffset +StructAtOffsetOrNull +StructAtOffsetUnaligned +structs +STRUCTS +structure +Structure +structures +Studio +stuff +stupid +stv +style +Style +STYLE +stylistic +Stylistic +STYLISTIC +stylisticSet +sTypoAscender +sTypoDescender +sTypoLineGap +su +sub +SUB +subarray +subclass +Subclass +subclasses +subdivided +subdivision +subfamily +SUBFAMILY +subfamilyID +subfamilyNameID +subFeatureFlags +subfonts +SubFormat +subject +subjoined +Subjoined +SUBJOINED +subjoining +sublookup +SUBLOOKUP +SubLookupOffsets +SubLookupOffsetsArray +submerged +subpixel +subr +subrecord +subroffset +subroutine +Subroutine +subroutines +subrs +Subrs +SUBRS +subrsOffset +subs +subscript +Subscript +SUBSCRIPT +subscripts +Subscripts +subsequence +subsequences +subsequent +subset +Subset +SUBSET +SubsetGlyph +Subsets +subsetted +subsetter +SUBSETTER +subsetting +subst +SUBST +substantially +substGlyph +substitued +substitute +Substitute +SUBSTITUTE +substituted +SUBSTITUTED +substitutes +substituteX +substitution +Substitution +SUBSTITUTION +substitutions +substitutionTables +SubstLookup +SubstLookupSubTable +substr +substring +substThreshold +subsystem +subtable +subTable +Subtable +SubTable +subtableCount +SubTableFlags +subtableGlyphCoverageArray +SubTableHeader +subtables +Subtables +SubTables +SUBTABLES +SubtableType +subtag +SUBTAG +subtags +subtending +subtract +subtracting +subtraction +succeed +succeeded +SUCCEEDED +Succeeding +SUCCEEDING +succeeds +success +successful +successfully +successive +such +SUCH +sucks +Sudanese +sudo +sufficient +SUFFICIENT +suggest +suggested +Suggested +suggests +suit +suitable +suite +Suite +suk +Sukuma +sukun +SUKUN +sum +Sum +summation +Summer +sun +Sundanese +SUNDANESE +SUNPRO +SUPER +superimposing +SUPERIORS +superscript +SUPERSCRIPT +superscripts +Superscripts +supp +suppData +suppEncData +SuppEncData +SuppEncoding +supplement +Supplement +Supplemental +supplied +supply +supplying +support +Support +SUPPORT +supported +Supported +SUPPORTED +supporting +supports +Supports +supposed +supposedly +suppress +supps +suq +sure +Suri +surprise +surprises +surrogate +SURROGATE +Surrogates +surrounding +survive +survived +survives +sutable +Sutu +sv +sva +Svan +svg +SVG +svgDoc +svgDocEntries +svgDocLength +SVGDocumentIndexEntry +SVR +sw +Swadaya +Swahili +Swampy +swap +Swap +SWAP +swaplp +swapped +swaps +SWASH +SWASHES +Swati +swb +swc +Sweden +Swedish +Sweep +swh +switch +Switch +switched +switches +Switzerland +swv +sxHeight +sxu +syc +syl +Sylheti +Syllabary +syllabic +Syllabic +SYLLABIC +Syllabics +SYLLABICS +syllable +Syllable +SYLLABLE +syllables +Syllables +Syloti +SYLOTI +SYM +symbol +Symbol +SYMBOL +symbolic +symbols +Symbols +SYMBOLS +symmetric +sync +synchronize +syntatically +syntax +Syntax +synthesize +synthesizes +synthesizing +SyntheticBase +syr +Syrc +syre +Syre +Syria +syriac +Syriac +SYRIAC +syrj +Syrj +syrn +Syrn +sys +SYS +sysconf +SYSCONF +system +System +SYSTEM +systems +sz +szl +t +T +ta +Ta +taa +tab +Tabasaran +Tabassaran +table +Table +TABLE +tableCount +tablelist +TableRecord +TableRecords +tables +Tables +TABLES +tableTag +TableType +Tachelhit +Tachoni +tag +Tag +TAG +Tagalog +TAGALOG +Tagbanwa +TAGBANWA +tagFeature +tagged +Tagin +Tagish +tagLangSys +tagRanges +tags +Tags +TAGS +tagScript +TAH +Tahaggart +Tahitian +Tahltan +tahoma +Tahoma +tahomabd +Tai +TAI +tail +Tail +tailored +Taiwan +Taiwanese +Tajik +Tajiki +Tajikistan +take +Take +taken +takes +taking +Takri +TAKRI +TALL +Tamahaq +Tamajaq +Tamajeq +Tamashek +Tamasheq +Tamazight +Tamil +TAMIL +TAML +Tanacross +Tanaina +Tanana +TANDEM +Tandroy +Tangshewi +TANGUT +Tanosy +Tanzania +taq +tarball +Tarball +target +TARGET +TargetConditionals +targs +Tarifit +tasks +Tatar +tator +tau +TAV +Tawallammat +Tawr +Tày +Tayart +Taylor +TB +TBase +TBASE +tbl +tbody +TBR +tcb +tce +TCHEH +TCHEHEH +TCodepoint +TCount +TCOUNT +tcp +tcy +tcz +tdd +tdx +te +tec +technetwork +Technical +technicalities +Technically +Tedim +TEH +TEHEH +telecom +tell +tells +TELU +Telugu +TELUGU +tem +Temne +temp +templ +template +Template +templates +temporarily +temporary +tempting +Temuan +TEN +Tena +Tenggarong +Tepetotutla +Tepinapa +Terik +term +terminal +Terminal +terminate +terminated +terminates +terminating +termination +Termination +TerminationWordCount +terminator +terminology +Terminology +terms +Tesaka +test +Test +TEST +tested +testing +Testing +tests +Tests +tet +TET +Tetum +text +Text +TEXT +TextAnalysis +textAnalyzer +textLength +textPosition +textProperties +TEXTRANGE +textString +textual +tfn +tg +tgj +tgroup +tgx +th +TH +tha +Thaana +THAANA +Thado +thai +Thai +THAI +Thailand +THAL +Tham +THAM +than +THAN +THANTHAKHAT +that +That +the +The +THE +thead +THEH +their +them +themed +themselves +then +Then +theory +thep +there +There +therefore +Therefore +these +These +they +They +thickness +THICKNESS +THIN +thing +things +Things +thingy +think +third +Third +THIRD +THIRTEEN +this +This +THIS +thiz +THO +thorn +Thorn +Thornsmall +those +though +thread +Thread +threading +threads +threadsafe +threadsafely +three +Three +THREE +threeeighths +threeinferior +threeoldstyle +threequarters +threequartersemdash +threesuperior +through +throughout +throw +tht +thus +thv +thz +ti +Tibetan +TIBETAN +Tidy +tiff +Tifinagh +TIFINAGH +tig +tight +Tigon +Tigre +Tigrinya +tilde +Tildesmall +tile +tiles +Tiles +time +timeouts +times +Times +timesbi +timesi +Timne +tindex +Tiny +TINY +Tirhuta +TIRHUTA +Tiriki +title +TITLECASE +TITLING +tiv +Tiv +tjmo +TJMO +tk +tkg +tl +TL +Tlacoatzintepec +tlen +tlist +TLookup +TLookupList +TLR +TM +tmh +tmp +tmw +tn +tnf +to +To +TO +Toba +Tobago +TObject +toCoord +tod +today +Todo +TODO +toe +together +ToGlyphs +toi +tok +Tok +tol +Tolowa +TOLOWER +Toma +tombstone +tombstones +tone +Tone +TONE +tones +Tonga +Tongan +too +took +toolkit +tools +tooltip +top +Top +TOP +topAccentAttachment +topAccentCoverage +topdict +topDict +TopDict +topDictIndex +TopDictIndex +topDictInfo +topDictModSIDs +topDictSize +topDictStr +toplevel +topographical +Topographical +topologically +topSide +topSzr +Torki +TORTIOUS +TORTOISE +Tosk +total +Total +totalDataSize +totally +touch +TOUCH +touches +TOUPPER +towards +tpi +tr +TR +trace +Trace +TRACE +tracing +track +Track +trackData +TrackData +tracking +Tracking +trackNameID +tracks +trackTable +trackTableEntry +TrackTableEntry +TRAD +trade +trademark +TRADEMARK +trademarks +Traditional +TRADITIONAL +trailed +trailing +trak +TRAK +trampoline +trans +TRANSCODING +transcription +transfer +Transfer +transform +Transform +transformation +transformed +transforming +transient +Transient +transition +transitioning +transitive +translatation +translate +translating +translation +TRANSLITERATION +transparent +traversal +treat +treated +treatment +treats +tree +trees +TRI +trick +trickiest +tricky +Tricky +tried +tries +Tries +trigger +triggered +triggers +trim +trimmable +trimmed +Trimming +Trinidad +trivial +Trivial +trivially +trouble +troubleshooting +tru +true +TRUE +TrueTag +TrueType +TRUETYPE +TrueTypeTag +truly +truncate +truncated +try +Try +TryGetFontTable +trying +Trying +ts +Ts +TSA +TSADI +tsb +tsere +Tsetsaut +Tshangla +Tsimihety +tsj +Tsmall +Tsonga +Tsotso +TSubTable +tsuperior +Tswana +tt +TTA +ttb +TTB +ttc +TTC +ttcf +ttcHeader +TTCHeader +TTCHeaderVersion +ttcTag +TTCTag +TTEH +TTEHEH +ttf +ttm +ttq +Tugen +Tulu +tum +Tumari +Tumbuka +Tundra +Tunisia +Tunisian +tuple +Tuple +tupleCount +tupleIndex +TupleIndexMask +tuples +tupleVarCount +TupleVarCount +TupleVarHeader +tupleVarHeaders +Tupple +TuppleIndex +Turkey +Turkic +TURKIC +Turkish +Turkmen +Turkmenistan +turn +Turn +Turner +turning +turns +Turns +Turoyo +Tusi +Tutchone +Tututni +tuu +Tuvalu +Tuvin +Tuvinian +tuy +tvalue +tvl +tw +tweaks +TWELVE +TWENTY +Twi +twice +twilight +two +Two +TWO +TwoByteNegInt +TwoBytePosInt +twodotenleader +twoinferior +twooldstyle +twosuperior +twothirds +tx +txc +txt +txy +ty +tying +Typ +type +Type +TYPE +typed +typedef +typedefs +typeface +typefaces +typeList +typename +TypeName +types +Types +TYPES +typesetter +typesetting +typical +typically +typo +TYPO +typographic +Typographic +TYPOGRAPHIC +typographical +typography +Typography +typos +tyv +tyz +tze +tzm +tzo +Tzotzil +u +U +uacute +Uacute +Uacutesmall +UARRAY +ub +uBidiLevel +ubl +Ubuntu +ubyte +ubytes +ucd +UCD +ucdn +UCDN +uchar +UChar +UCHAR +ucircumflex +Ucircumflex +Ucircumflexsmall +ucs +udieresis +Udieresis +Udieresissmall +udm +Udmurt +ue +UE +UEE +UErrorCode +ufuncs +ufunctions +UFWORD +ug +Ugaritic +UGARITIC +UGC +Ugh +ugly +Ugly +UGLY +ugrave +Ugrave +Ugravesmall +UHEADLESSARRAY +UI +UIDBase +Uighur +uiLabelNameId +uiNameID +uint +UINT +uintptr +UIPC +UISC +uk +Ukraine +Ukrainian +ULBAR +ulCodePageRange +ulink +ULL +ULLONG +ULong +ULONG +Ulrich +ultimately +ULTRA +ulUnicodeOS +ulUnicodeRange +umb +Umbundu +Umm +un +unassigned +UNASSIGNED +unbounded +UNBOUNDED +unchanged +UNCLASSIFIED +UnclassifiedGlyph +unclear +unconditionalAddGlyphAction +UnconditionalAddGlyphAction +unconditionally +UNCONNECTED +unconst +und +undef +UNDEF +undefined +UNDEFINED +under +Under +UNDERBAR +underflow +undergone +underline +Underline +UNDERLINE +underlinePosition +UnderlinePosition +underlineThickness +UnderlineThickness +underlining +underlying +underneath +underscore +UNDERSCORE +understand +understandable +understood +undertake +Undetermined +undo +undocumented +Undocumented +unequal +UNFITTED +unforced +unformed +unfortunate +unfortunately +Unfortunately +unhide +uni +unichar +UniChar +unicode +Unicode +UNICODE +UnicodeData +unicodes +UNICODES +unicodeValue +UnicodeValueRange +Unified +uniform +uninitialized +union +UNION +Unión +unions +unique +UNIQUE +UniqueID +uniscribe +Uniscribe +UNISCRIBE +unistd +UNISTD +unit +United +units +Units +unitSize +unitsPerEm +uniUUUU +Universal +unix +unknown +Unknown +UNKNOWN +unless +Unless +unlike +unlikely +unlimited +UnlimiteGap +unloaded +unlock +Unmake +unmap +UnmapViewOfFile +unmarked +unnecessary +unnormalize +unoffset +unorm +UNormalizer +unpack +unpadded +unpop +unprocessed +unr +unrecognized +unref +unreferenced +UnregisterFontFileLoader +unsafe +Unsafe +UNSAFE +UNSCALED +unset +unsigned +Unsized +UnsizedArrayOf +UnsizedByteStr +UnsizedOffsetArrayOf +UnsizedOffsetListOf +unsorted +UNSUCCESSFUL +unsupported +UNSUPPORTED +unsure +UNTAG +until +untouched +unused +Unused +UNUSED +unusual +unwanted +unwise +unzip +uoffset +up +UP +update +updated +UPDATES +upem +UPEM +upon +upper +Upper +UPPER +uppercase +UPPERCASE +upperLimit +upright +UPROPS +upward +ur +Urak +Urdu +urk +url +URL +Uruguay +us +USABLE +usage +usBreakChar +uscript +USCRIPT +UScriptCode +usDefaultChar +use +Use +USE +used +Used +useful +Useful +useless +UseMarkFilteringSet +user +User +USER +userfeatures +users +uses +Uses +usFirstCharIndex +USHRT +Usila +using +Using +USING +usLastCharIndex +usLowerOpticalPointSize +Usmall +usMaxContext +usp +USP +ustr +ustring +usually +Usually +usUpperOpticalPointSize +usWeightClass +usWidthClass +usWinAscent +usWinDescent +utf +UTF +Uthmanic +util +utilities +Utilities +utility +utilize +UTS +uu +UU +UUID +UuidCreate +uuidof +UVCRDOypOtijlMDLNNyyLk +uversion +uvs +UVS +UVSMapping +Uyghur +uz +Uzbek +Uzbeki +Uzbekistan +uzn +uzs +v +V +va +VA +VAbv +VAH +Vai +VAI +Vakhi +val +Val +VAL +ValCount +valFormat +valid +Valid +VALID +validate +validated +Validator +validity +Valle +valuable +value +Value +VALUE +valueArrayZ +valueCount +valueFormat +ValueFormat +valueFormats +valueIndex +valueNameID +ValueRecord +valueRecordCount +ValueRecords +valueRecordSize +values +Values +VALUES +ValuesAreLong +valueSize +valuesZ +valueTag +ValueType +var +Var +VAR +vararg +varation +VarData +varDataSize +variable +Variable +variablelist +variables +variant +Variant +VARIANT +variantGlyph +variants +Variants +variation +Variation +VARIATION +variationAxis +VariationAxisRecord +VariationDevice +variations +Variations +VARIATIONS +VariationSelectorRecord +variationsTag +VariationStore +VariationValueRecord +varidx +varIdx +varies +variety +varika +variour +various +Various +varlistentry +varname +varRecords +VarRegionAxis +VarRegionList +vars +varSelector +VarSizedBinSearchArrayOf +VarSizedBinSearchHeader +varStore +varStoreOffset +vary +vattu +vatu +Vatu +VATU +VAV +vAxis +VBAR +VBase +VBASE +VBlw +VCount +VCOUNT +vcpkg +VD +ve +VE +vec +vector +Vector +VECTOR +vectorization +vectorized +vedic +Vedic +VEH +ven +Venda +VENDOR +Venetian +Venezuela +VER +Verb +verbatim +verify +versa +version +Version +VERSION +versions +versionZ +vert +VERT +vertAdvance +vertBearingX +vertBearingY +vertData +vertGlyphCount +vertGlyphCoverage +vertical +Vertical +VERTICAL +vertically +VertOriginMetric +vertOriginY +vertYOrigins +very +vfprintf +vhcurveto +vhea +vi +VI +via +vice +Viet +VIET +Vietnam +Vietnamese +view +vindex +vINVALID +violation +virama +Virama +VIRAMA +viramas +virtual +Virtualizing +vis +Visarga +VISARGA +VISATTR +visibility +VISIBILITY +visible +visibly +visit +visited +visitLangSys +visitScript +vista +Vista +visual +Visual +VISUAL +vjmo +VJMO +vkk +vkt +Vlaams +Vlax +vlineto +vls +VM +VMAbv +VMBlw +vmoveto +VMPre +VMPst +vmtx +vmw +vo +Vo +VOICED +VOICING +void +Void +VOID +VOL +Volapük +volatile +volt +vorg +VORG +vorgMap +Võro +vowel +Vowel +VOWEL +vowels +Vowels +vp +VPre +VPst +VRBAR +vrinda +vro +Vs +VS +vsindex +vsindexcs +vsindexdict +Vsmall +vsnprintf +vstem +vstemhm +vstore +vstoreOffset +vtable +vv +vvar +VVAR +VVARTag +vvcurveto +w +W +wa +Wa +Wagdi +Wailaki +walk +Walk +walks +Wall +Walloon +Wanca +WANCHO +Wang +Wanga +want +wanted +wants +war +WARANG +Waray +warn +warning +Warning +WARNING +warnings +Warnings +WARRANTIES +was +Was +WASLA +wasn +waste +Watch +watchout +Watchout +WAVY +WAW +way +ways +Wayuu +wbm +wbr +Wbuiltin +Wc +Wcast +WCE +wchar +WCHAR +Wclass +Wconversion +wdcTable +Wdelete +Wdeprecated +Wdisabled +Wdouble +wdRecord +wdth +we +We +WE +weak +weight +Weight +WEIGHT +weights +weird +welcome +well +Welsh +Wembedded +went +were +Werner +West +Western +Weverything +Wextra +Wformat +wght +what +What +WHAT +whatever +Whatever +whatsoever +WHATSOEVER +when +When +whenever +Whenever +where +whereas +Whereas +WheresData +WheresFace +wherever +whether +Whether +WHETHER +which +Which +while +While +white +WHITE +Whitelist +whitespace +Whitespace +who +whole +whose +why +Why +wide +widely +width +Width +WIDTH +WidthDeltaCluster +WidthDeltaPair +widthMax +widths +widthsZ +Wignored +wiki +wikipedia +wild +will +Will +willing +willis +wilson +Wilson +Wimplicit +win +Win +WIN +WINAPI +windows +Windows +Winit +Winjected +WINNT +Winter +Wipe +wish +wishes +with +With +WITH +within +Within +without +Without +WJ +wlc +wle +wlk +Wlogical +Wmaybe +Wmissing +Wnested +wni +wo +Wolane +Wold +Wolof +won +Woods +word +Word +WORD +wording +wordOffsetToIndex +words +WORDS +work +Work +worked +working +Working +works +Works +world +worry +worrying +worth +would +Would +WOULD +wouldbn +wouldn +Wow +Wpacked +Wpointer +Wpragmas +wrap +wrapper +wrappers +wrapping +Wredundant +Wreorder +writable +Writable +WRITABLE +write +Write +WRITE +writer +writing +written +Written +wrong +wrote +wry +Ws +wsg +Wshadow +Wsign +Wsmall +Wstrict +Wstring +Wswitch +Wtautological +wtm +Wtype +Wu +Wundef +Wunknown +Wunneeded +Wunsafe +Wunused +wuu +Wvla +ww +Wwrite +WWS +www +x +X +xa +xA +xaa +xAA +xAAF +xAB +xabc +xABC +xABFFu +xAC +xAdvance +xAdvDevice +xAFF +xal +XALLOCATE +Xamtanga +xan +xAu +xAvgCharWidth +xb +xB +xBA +xBB +xBFF +xBytes +xc +xC +xCD +xCFF +Xconstructor +xCoordinate +xCULL +xD +xDBFFu +xDC +xDE +xDeviceTable +xDFDFDFDF +xDFDFDFDFu +xDFF +xDFFF +xDFFFu +xDFu +xe +xE +xEFF +xEFu +xF +xFAFF +xFB +xFBA +xFBAAu +xFBABu +xFBACu +xFBADu +xFBAEu +xFBAFu +xFBB +xFBD +xFBDAu +xFBDBu +xFBDCu +xFBDDu +xFBDEu +xFBDFu +xFBE +xFBFCu +xFBFDu +xFBFEu +xFBFFu +xFDFF +xfe +xFE +xFEA +xFEAAu +xFEABu +xFEACu +xFEADu +xFEAEu +xFEAFu +xFEB +xFEBAu +xFEBBu +xFEBCu +xFEBDu +xFEBEu +xFEBFu +xFEC +xFECAu +xFECBu +xFECCu +xFECDu +xFECEu +xFECFu +xFED +xFEDAu +xFEDBu +xFEDCu +xFEDDu +xFEDEu +xFEDFu +xFEE +xFEEAu +xFEEBu +xFEECu +xFEEDu +xFEEEu +xFEEFu +xFEF +xFEFAu +xFEFBu +xFEFCu +xFEFF +xFEFFu +xff +xFF +xFFEF +xFFF +xFFFC +xFFFD +xFFFDu +xFFFE +xFFFF +xFFFFD +xFFFFF +xFFFFFF +xFFFFFFFF +xFFFFFFFFFFFFFull +xFFFFFFFFu +xFFFFu +xFFu +xFu +Xgroup +xh +Xhb +Xhosa +xi +Xian +Xiang +Xiangxi +Xibe +XInclude +xjb +xkf +xlocale +XLOCALE +xMax +xMin +xml +XML +xmlns +xmm +xmv +xmw +xnr +xOffset +xog +xor +XP +xpe +xPlacement +xPlaDevice +xscale +xsl +Xsmall +xst +Xuan +XUID +xwo +xx +XXX +XY +y +Y +Ya +yacute +Yacute +Yacutesmall +yAdvance +yAdvDevice +Yakut +Yanahuanca +Yang +Yangbye +yao +Yao +yap +Yapese +Yarowilca +Yauyos +Yay +yb +ybd +yBytes +yCoordinate +ydd +yDeviceTable +ydieresis +Ydieresis +Ydieresissmall +YEH +Yemen +yen +yes +Yes +YES +yet +Ygroup +yi +Yi +YI +Yiddish +YIDDISH +yield +YIELD +yields +yih +Yijing +YING +yMax +yMin +yml +yo +YO +YOD +yOffset +Yongbei +Yongnan +Yoruba +yos +Yos +Yosemite +you +You +Youjiang +your +yourinputtext +yourself +yPlacement +yPlaDevice +yrk +yscale +Ysmall +yStrikeoutPosition +yStrikeoutSize +ySubscriptXOffset +ySubscriptXSize +ySubscriptYOffset +ySubscriptYSize +ySuperscriptXOffset +ySuperscriptXSize +ySuperscriptYOffset +ySuperscriptYSize +YU +yue +Yue +Yugoslav +yum +Yupik +z +Z +za +ZAH +ZAIN +Zambia +Zamboanga +Zanabazar +ZANABAZAR +Zande +Zarma +zawgyi +Zawgyi +ZAWGYI +ZAYIN +Zazaki +zcaron +Zcaron +Zcaronsmall +zch +zdj +zea +Zealand +Zealandic +Zeeuws +zeh +zero +Zero +ZERO +zeroed +zeroinferior +zeroing +zeroint +zerooldstyle +zeros +zerosuperior +zgb +zgh +zgm +zgn +zh +zhd +zhe +zhn +Zhong +Zhuang +Zimbabwe +zip +zipped +zk +Zl +zlj +zlm +zln +zlq +zmi +zne +zo +zom +zone +Zotung +Zou +Zp +zqe +Zs +zsm +Zsmall +zu +Zulu +zum +Zuojiang +zwj +ZWJ +zwnj +ZWNJ +zyb +zyg +zyj +zyn +Zyrian +zza +zzj diff --git a/perf/texts/fa-monologue.txt b/perf/texts/fa-monologue.txt new file mode 100644 index 0000000000000000000000000000000000000000..c41257c14795fb58d591b1f8c8221de170913875 --- /dev/null +++ b/perf/texts/fa-monologue.txt @@ -0,0 +1 @@ +من اسمم کاظمه. ما توی یه کوچه بن بست خونه داریم. کوچه‌مون خاکیه. اونوقت خیلی پایئن تر از خونه ما - زیاد پایین نه - اینور می‌پیچی یه نونواس. از اونجا صاف می‌ریم اینجا. یه خیابونه اینجا. اونوقت خیلی پایین‌ترش یه حمومه. بعداً یه بقالی هم دم خونمونه. یه خرده انور خرابه، یه قصابیه. قصابه با بابام رفیقه. پشت خونمون یه دباغیه. اینقده بچه گوسفند توشه! خونه‌مون ساس داره. ساس کوچیک و سیاس. هر جا بزنه جاش باد می‌کنه. وقتی داره از دیوار اتاق می‌ره بالا، نمی‌تونه خودشو نگه داره، می‌افته رو تن ما، می‌گیره خونمونو می‌مکه. یه دفعه همه اثاث مثاثامونو ریختیم بیرون، یه عالمه دوا خریدیم زدیم همه جا: به رختخوابا،‌ زیر زیلو، سوراخ سنبه‌ها. ولی ساسها بیشتر شدن، کمتر نشدن. بابام توی حموم کار می‌کنه. دوتا برادر داریم، یه خواهر: من و مصطفی و زهرا کوچولو. بابا وقتی داره شب می‌شه برمی‌گرده خونه. همیشه استخوناش درد می‌کنه. سر هیچی به هیچی می‌گیره می‌زنه‌مون، بازهم طلبکاره. مثلاً وسط سال، صبح ساعت شیش می‌آد می‌گه، «پاشو برو سیگار بفروش، پول دربیار لباس بخر!» من هم می‌گم: «لباس می‌خوام چی‌ کار؟» اون هم می‌گیره با کمربند حالمونو جا می‌آره. باز خوبه سه ماه تعطیلی خودمون می‌ریم کار می‌کنیم. یه کارخونه هست. می‌ریم اونجا قابلمه درست می‌کنیم، کاسه درست می‌کنیم، عصر که شونصد تا کاسه درست کردیم، دستگارو تمیز می‌کنیم برمی‌گردیم خونه. پارسال هفته‌ای پنجاه تومن مزد می‌دادن. امسال دیگه خدا می‌دونه. با همه این حرفا، بمیریم بهتره آقا! هر روز هر روز کتک. بابام دیشب بیخودی مصطفی رو گرفت زد. گرفت زدش گفت: «چرا وقتی می‌ری دست به آب، سر پا می‌شاشی؟ بشی بشاش!» مصطفی‌مون هیچی حالیش نمی‌شه. قد زهرامون بوده که از بالا پشت بوم افتاده، رگ کله‌اش تکون خرده. حالا سیزده سالشه. نه چارده،‌ چارده سالشه. داداش بزرگ‌ مونه. الان مدرسه عقب افتاده‌ها درس می‌خونه. آب، بابا، بار میخونه یاد بگیره، بیاد جلو. دو سه کلمه بلده حرف بزنه ولی چیزه... نمیتونه قشنگ حرف بزنه. بابام می‌خواد از مدرسه ورش داره، بذاره یه جا که کار یاد بگیره. بابا زهرا را از همه بیشتر می‌خواد. اون هم هر کاری دلش بخواد می‌کنه. هرچی می‌گیم گوش نمی‌کنه، می‌ره تو جوب محل کثافت‌کاری می‌کنه. اون روزی حواسم نبود، رفت یه مشت دیگ مونده سر کوچه بود ورداشت خورد. شب دلش درد گرفت نزدیک بود بمیره. اونوقت بابام اومد گرفت منو با شیلنگ کشت. آقا مگه شهر هرته؟ خر کتک می‌خوره. دیگه چرا ما رو می‌زنن؟ برن به خر بزنن! آخه من که نمی‌تونم همه‌ش مواظب زهرا باشم. راستی یه صاحب حیاط داریم، خیلی بد اخلاقه آقا! اسمش عباس آقاس. صبح می‌ره ظهر می‌آد. سپور شهرداریه. بیست و چار ساعت می‌آد بند میکنه به ما، میگه: «آب زیاد مصرف نکنین، چاه پر میشه.» زهرامون که گاهی گریه می‌کنه، دادش بلند می‌شه می‌گه: «صدای این تخم‌سگو خفه کنین!» اونوقت که مادرمون زنده بود، یه دفعه می‌خواست از دست عباس آقا نفت بریزه سرش، خودشو آتیش بزنه. عباس آقا اصلاً رحم حالیش نمی‌شه؛ پسر سیزده ساله‌شو گرفته از خونه انداخته بیرون. اون هم رفته توی کوچه‌ پس ‌کوچه‌‌ها ول شده. حالا خدا می‌دونه کجاس، چه کار می‌کنه،‌ از کجا می‌آره می‌خوره. بچه‌ها می‌گن: «شب‌ها می‌ره توی پارک‌ها پیش سگها می‌خوابه.» که رفته دهات خونهٔ باباش، می‌گه دیگه نمی‌آم تهران. آقا، ما هم دلمون می‌خواد میرفتیم دهمون با گوسفندها بازی می‌کردیم؛ با بابا بزرگ‌مون می‌رفتیم دشت بز می‌چروندیم،‌ بادوم پاک می‌کردیم، انگور می‌چیدیم. دهمون ولی خیلی دوره آخه! زن عباس آقا حق داره، آقا! محله‌مون خیلی بده. هر روز اونجا دعواس، دعوا، چاقو کشی. توی خرابه هم پر معتاده، بگی دوهزار تا هم بیشتر. می‌رن اونجا قمار می‌کنن، شیره می‌کشن، آمپول می‌زنن تو رگشون. ماهم از ترس معتادها جرأت نمی‌کنیم از خونه بریم کوچه، یه ذره بازی کنیم. از کمیته‌م نمی‌ترسن، میگیرن بچه‌های مردمو می‌دزدن، میبرن توی کوره‌ها،‌ توی دلاشون چیز قایم می‌کنن؛ هروئین قایم میکنن. یه امیر ریزه هست تریاکیه، اون روزی اومد خرم کنه، گفت: «بیا سوار ماشین بشیم، بریم یه جائی.» من هم از ترسم خر نشدم. یه چیز خنده دار بگم بخندی، آقا: اینورمون یه همسایه داریم، اسمش ربابه. انوقت توپ،‌ لنگه کفش، تنکه، هرچی بیفته خونشون،‌ شوهرش ور می‌داره می‌اندازه توی آب انبارشون. هروقت هم کوچه شلوغ بشه، شوهر رباب می‌آد بیرون می‌گه: «واق، عو!» اون هم مث مصطفی‌ ما لقوه‌ایه‌؛ دستش می‌لزره، همه جاش می‌لرزه. اون روز اومد دم دکون، رفت اونور جوب نشت. این یکی همسایه‌مون رفت یه کتاب دربارهٔ خدا و فرشته‌ها آورد براش خوند. رباب خانم خودش خونه یه اعیونه کار می‌کنه؛ چیزاشونو می‌شوره، باغ‌شونو آب می‌ده؛ کلفتی می‌کنه. بعد همه‌ش می‌آد پز اربابشو می‌ده. الان دیگه همه اهل محل می‌دونن باغ خونهٔ ارباب رباب خانوم اندازه پارک شهره. استخرش از مال پارک شهر هم گنده‌تره. هروقت هم که ارباب می‌خواد‌ آبتنی کنه،‌ اول یه قطره دوای مخصوص هست، می‌ریزه توی استخر که آب‌شو می‌کنه مث اشک چشم. بعد می‌ره زیر دوش، با عطر و گلاب خودشو می‌شوره. بعد می‌پره توی استخر، می‌گیره شوخی شوخی آب می‌پاشه به رباب خانوم. زن اربابش هم خارجیه. مال همون کشوریه که شیش ماه شبه، شیش ماه روز. رباب یه چاخان‌هایی می‌کنه که کلهٔ آدم سوت می‌کشه! می‌گه ارباب یه سگ پشمالو داره،‌ اسمش مونیکاس. قسم می‌خوره می‌گه مونیکا غذاشو با کارد و چنگال می‌خوره. اللَه اکبر به این دروغ. یه پیرزنه هم هست سر کوچمونه. با خودش تنهایی زندگی می‌کنه. اسمش ننه غلامه. هشتاد نود سالشه ولی خجالت نمی‌کشه،‌ از امریکا خوشش می‌آد. همه ازش می‌ترسن؛ هر وفت بیاد بیرون، فحش می‌ده، جیغ و ویغ می‌زنه. مثلا من اذیتش کردم، می‌آد سر فحش‌رو می‌کشه به تو. وقتی بچه‌ها بخوان لج‌شو در‌بیارن، می‌گن: «مرگ بر امریکا!» اونوقت اون هم حرصش می‌گیره، هزار تا فحش بی‌ناموسی و خوار و مادر می‌کشه به جون همه. ننه غلام دیونه‌س. بعضی وقتا هم با‌ آدم خوبه. یه روز من و زهرا رو گرفت به زور برد خونه‌ش، کله پاچه داد، گفت «بخورین!» ما هم خوردیم. ته کاسه یه لقمه موند که روش یه عالمه مو بود. گفت: «اگه نخورین با همین چاقو سرتونو می‌برم.» ما هم از ترس جونمون خوردیم. ننه غلام وقتی سر حاله، چیز می‌آره می‌ده آدم. مثلا یکی زخمه،‌ دوا می‌آره بهش می‌ده. مثلا کسی چیزی نداره، چیز می‌آره بهش می‌ده، وسط کوچه‌مون یه خونه‌س که دخترهاش خرابن، آقا. اونوقت شیره‌ای‌ها و چاقوکش‌ها می‌رن خونه‌شون، کار بد می‌کنن. بعضی وقتا هم دختر‌هاش لباس سرخ و زرد تن می‌کنن و کفش پاشنه بلند تق‌تقی می‌پوشن، می‌رن واسه بالاشهری‌ها قر می‌دن. یه دفعه هم داشتم می‌رفتم پیش بچه‌ها «لیس پس لیس» بازی کنم که دختر کوچیکه‌ش امیر ریزه رو صدا کرد و بهش گفت: «تو چقدر پاهات لاغره!» بعد امیر ریزه هم نامردی نکرد. گفت:«خودت چرا لمبه‌هات چاقه؟» بعد دوتایی کرکر خندیدن. خودم با همین دو تا چشمام دیدم، آقا! اونوقت ما هم که می‌بینیم محله‌مون پر از بی‌تربیتی‌یه، زدیم با هفت‌تا از بچه محلامون قهر کردیم. با اون هفت‌تا هم بمیرم آشتی نمی‌کنم، آقا. با یکی‌شون یه ساله قهریم، اسمش محمده. یه روز سر کوچه‌مون عروسی بود، ما هم داشتیم بازی می‌کردیم. من دراومدم به محمد گفتم: «محمد امشب چه خبره؟ آبجی‌ت می‌ره حجله؟» ناراحت شد، گفت: «باهات قهرم.» من هم گفتم: «چه بهتر! می‌رم درسامو می‌خونم.» به خدا ما چه می‌دونستیم، به خیالمون عروسی آبجیشه، آقا! فقط با دو نفر دوستیم: مهدی ملخ و حسن گامبو. مهدی از بس مردنیه، همه ملخ صداش می‌کنن. باباش قوری بست می‌زنه. وسط بازی یهو پیداش می‌شه، می‌آد می‌گه: «اگه منو بازی ندین، بازی‌تونو بهم می‌زنم.» اونوقت تا که دس بهش می‌خوره، جیغش می‌ره هوا، میگه: «گه خوردم، گه خوردم.» اونوقت می‌ره از حرصش با میخ یه شکل‌هایی می‌کشه روی دیوار، می‌گه: «این عکس کاظمه.» فسقلی فوتش کنی، قل می‌خوره، ها. آقا، ما دوچرخه خیلی دوست داریم، بعضی وقتا می‌ریم یه تومن می‌دیم چرخ کرایه می‌کنیم. حسن گامبو زورش می‌آد، با سنگ می‌زنه، می‌گه: «منو باید سوار کنی.» من هم می‌بینم داره دلش می‌شکنه، می‌گم: «بیا تو هم سوار شو!» داداش حسن گامبو پنج ماهه رفته لب مرز با خارجیا بجنگه. حسن می‌گه: «رفته امریکا رو نابود کنه، برگرده.» بابای حسن آهنکاره؛ یعنی قالب می‌سازه، پشقاب می‌سازه، همه‌چی می‌سازه. نه که حسن خیکیه، بچه‌ها صداش می‌کنن: «حسن گامبو، سرت تو شامپو!» می‌خواییم با این دو نفر هم قهر کنیم بره. هی می‌آن در خونمون داد می‌زنن: «کاظم، بیا بازی، بیا بازی!» بازی چیه، آقا؟ بده بچه بازی کنه. رفوزه بشیم چه کار؟ دلم می‌خواد دکتر، مهندس، بازنشست، نیرو هوایی، هرچی شد بشیم، بریم پی کارمون بره. ولی تو خونه ما نمی‌شه درس خوند. تا می‌آم بشینم، باید پاشم برم نون بخرم، جارو کنم، خشتک زهرامونو بشورم. پارسال که رفوزه شدم، همه‌ش نیم نمره می‌خواستم قبول بشم. مدرسه‌مونم خیلی هردمبیه، آقا! بچه‌هاش دزدن، می‌آن دفترامونو می‌دزدن. سر کلاس یکی گچ پرت می‌کنه، یکی رو نیمکت ضرب می‌گیره، یکی پا می‌شه می‌رقصه. ما هم که می‌بینیم خر تو خره، حوصله‌مون سر می‌ره، از مدرسه جیم می‌شیم، می‌ریم فروشگاه بزرگ. اونجا پله‌برقی داره. می‌ریم می‌ایستیم خودمونو می‌زینم به اون راه. الکی نگاه می‌کنیم به جنس منس‌ها؛ یعنی مثلا ما هم اومدیم چیز بخریم. بعد می‌ریم سوار پله‌برقی می‌شیم، می‌ریم سواری می‌خوریم، عشق می‌کنیم. آقا، اجازه؟ سه تا دایی هم دارم، آقا! یکی‌شون دایی ضامن، یکی‌شونم دایی مرتضی. اونی که وضعش خوبه اسمش دایی رضوانه. یه وانت داره با یه اتوشویی. تا پامونو می‌ذاریم در دکونش، نامرد یه لگد می‌زنه در اونجامون، می‌گه: «بزن به چاک! باز اومدی از دخل کف ببری» به خدا تهمت می‌زنه، آقا! آقا، به خدا هیچکی به اندازه ما از دزدی بدش نمی‌آد. آقا، دایی مرتضی‌مون اولها کارگر بلورسازی بود، ولی وقتی من هنوز تو دل مادرم بودم، افتاد زندان. یه شب هفت نفر ریختن سرش، اون هم چاقو کشید، زد یکی‌شونو کشت. بعد دادگاه هم اومد بیخودی تقصیر رو گذاشت گردن دایی ما. قبل انقلاب از زندان اومد بیرون، رفت معتاد شد. حالا هم همیشه با زنش دعوا مرافعه داره. گاهی می‌ذاره از خونه‌ش می‌ره، می‌ره می‌ره پیداش نمی‌شه. بعد که برمی‌گرده، الکی به زنش می‌گه، رفته بودم بیمارستان ترک کنم. دایی مرتضی یه بچه کوچولو داره، هروقت می‌آد خونمون، می‌خواد از پله‌هامون بره بالا، بیاد پایین. ما هم می‌ریم دنبالش که نیفته سرش بشکنه. می‌ریم بغلش می‌کنیم. اونوقت می‌ترسه، سفت آدمو می‌گیره. دایی ضامن‌مون توی دولت آباد نفتیه، بعضی روزها که می‌ره نفت پخش کنه منو هم با خودش می‌بره. اون تا می‌ره نفت بده به خونه‌ها، بچه‌ها می‌گیرن مسخره‌م می‌کنن، می‌گن: «ای عرب پا نفتی، کی اومدی، کی رفتی؟» سنگ می‌زنن تو کله‌ام. من هم که زورم نمی‌رسه، گریه‌م می‌گیره. یه روز رفتیم در یه خونه نفت بدیم، اونوقت یه پسره بود - لال بود - دنبالمون کرد تا سر کوچه‌شون. فحش مادر داد، گفت: «دیگه در خونه ما نیا!» لال بود، آقا! نمی‌دونیم چی می‌گفت... آقا، هر وقت از مادرمون حرف می‌زنیم، بغض می‌آد گلومونو می‌گیره، ول‌مون نمی‌کنه... مادرمون سر بچه مرد، آقا! شب درد بچه گرفتش. رفتیم نبات خانومو آوردیم. نبات خانوم مامای محله‌س، شله، یه چشمش هم چپه. صبح که بچه اومد دنیا، مادرمون گذاشت از دنیا رفت. بچه‌ هم پشت سرش مرد، آقا!... مادرمون اون وقت که زنده بود، توی کارخونهٔ استارلایت کار می‌کرد. جوراب شلواری می‌بافت. وقتی شکمش اومد بالا، از اونجا بیرونش کردن. مادرمون اینقده سختی کشیده که خدا بگه، بس! همیشه مریض بود، بعضی وقتا هم غش می‌کرد. پاهاش قد یه متکا باد کرده بود، آقا!... آقا، باور کن، آقا... وقتی مادرمون مرد ما صد برابر الان بغض کردیم. من و زهرا و مصطفی شب تا صبح خوابمون نبرد. بابام اون شب هزار تا سیگار کشید،‌ ولی صبحش مادرمون مرد. وقتی رفتیم خاکش کنیم، ننه غلام نمی‌خواست بذاره ما بریم تماشا، می‌گفت، ما بچه‌ایم، گناه داریم. ولی من دزدکی توی مرده‌شور خونه هم رفتم. بوی بدی می‌ده مرده‌شور خونه، بوی گربهٔ مرده. آدم می‌خواد دل و روده‌شو بالا بیاره. وقتی مادرمونو اوردن گذاشتن توی سالن مرده‌شور خونه، هفت تا مرده زودتر مرده بودن. مادرمون نفر هشتم بود. مرده‌ها منتظر بودن دوش خالی بشه، سر نوبت برن تو، غسل کنن. جنازه یه دختر مدرسه هم بود. نمی‌دونی فک و فامیل دختره چی‌کار می‌کردن؛ یکی سرشو می‌زد به دیوار، یکی کفش‌شو دراورده بود می‌زد تو سر خودش. مادرمونو که اوردن بذارن توی قبر، سروکله‌ٔ مصطفی هم پیداش شد. مادرمون با مصطفی خوب بود. خدا بیامرز که رفت توی قبر، نمی‌دونم از کجا یه مگس اومد نشست روی کفنش. تا مصطفی کیش‌اش کرد، مگسه گذاشت در رفت. بعد شروع کردن با بیل خاک ریختن روی سر مادرمون. رباب خانم با ناخن صورتشو می‌کند. بابام داشت توی دل خودش گریه می‌کرد. اگه مصطفی نمی‌زد زیر گریه و توی خاک و خل غلت نمی‌خورد، من هم گریه نمی‌کردم... مادرمونو که خاک کردیم، دم قبرستان حلوای نذری پخش می‌کردن. واسه اینکه بوی گربهٔ مرده از دماغم بره، یه قاشق حلوا گذاشتم دهنم. ولی صاحب عذا که روشو برگردوند، تفش کردم. آقا، هیچی نمی‌تونستیم بخوریم. آقا، ما دلمون خیلی تنگه، هیشکی نیست ما را زفت کنه. دل‌مون می‌خواد از این دنیا می‌رفتیم. آقا، باورتون نمی‌شه، توی محله ما ملت تند تند می‌میرن، آقا! زهرامون یه همبازی داره، همقد خودشه. اسمش الهامه، پنج سالشه. ده بیست روز پیش باباش از داربست افتاد زمین عکس برگردون شد، مرد. دیروز الهام اومده بود خونه‌مون، یه عکس از باباش هم اورده بود، می‌گفت، هر شب خواب باباشو می‌بینه که اون دنیا آتیش درست کرده، می‌خواد بیاد بگیره اونو کباب کنه بخوره. یه حرفهایی می‌زد که مو به تن آدم سیخ می‌شد. اونوقت شب که خوابم برد، خوابیدم، خواب دیدم عزرائیل و شمر با آتیش اومدن بالای سرم، هی می‌چرخن و چه‌چه می‌خندن. عزرائیل نصفه‌س، آقا! یعنی پا نداره. من هم اومدم از دست‌شون در برم که دیدم یه خرگوشه داره با مامانش قایم موشک بازی می‌کنه. رفتم بگم، من هم بازی که گذاشتن در رفتن. من هم دنبالشون کردم. خسته که شدم دیدم سوار یه قایقم، یه سگ هم داشتم. داشتم با سگ بازی می‌کردم که یهو امیر ریزه پشت پا انداخت، افتادم توی آب. من هم رفتم سوار دوچرخه شدم، زدم به چاک. سگ هم از توی قایق پرید، اومد دنبالم. بعدش دیدم یه هلی‌کوپتر بالای سرمه، می‌خواد باید بستنی لیوانی‌مو قاپ بزنه. من هم با سنگ زدم شیشه‌شو شکوندم. اون هم ترسید در رفت، توی کوچه دباغ‌ها غیب شد. بعدش دیدم عباس آقا گرگ شده، می‌خواد بیاد زهرامونو بگیره لقمه‌ٔ چپش کنه. از ترسم دویدم توی پارک و رفتم سوار تاب شدم. اینقده تاب بازی کردم تا حسابی سرم گیج رفت. اومدم از تاب بپرم پایین، دیدیم زیر پام یه چاهه، یه چاه به این گندگی. داشتم ول می‌شدم ته چاه که از خواب پریدم. نشستم گریه کردم. اونوقت بابام بیدار شد، پرسید: «باز چی شده؟ شاشیدی؟» گفتم: «می‌ترسم.» گفت: «بگیر بخواب بابا تو هم دلت خوشه!» من هم لحافو که کشیدم روی سرم، همه‌ش خدا خدا می‌کردم ایم دفعه که خوابم برد، شانسم بگه، بزنه خواب خوشبختی ببینم، دلم خوش بشه. ولی اگه ما شانس داشتیم، آقا، اسم‌مونو می‌ذاشتن شانسعلی. diff --git a/perf/texts/fa-thelittleprince.txt b/perf/texts/fa-thelittleprince.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c56869a56b7557ec98a91b87fd35a9dfcb67c82 --- /dev/null +++ b/perf/texts/fa-thelittleprince.txt @@ -0,0 +1,923 @@ +شازده کوچولو +اثر آنتوان دو سن‌تگزوپه‌ری +برگردان احمد شاملو + + +اهدانام‌چه +به لئون ورث Leon Werth +از بچه‌ها عذر می‌خواهم که این کتاب را به یکی از بزرگ‌ترها هدیه کرده‌ام. برای این کار یک دلیل حسابی دارم: این «بزرگ‌تر» به‌ترین دوست من تو همه دنیا است. یک دلیل دیگرم هم آن که این «بزرگ‌تر» همه چیز را می‌تواند بفهمد حتا کتاب‌هایی را که برای بچه‌ها نوشته باشند. عذر سومم این است که این «بزرگ‌تر» تو فرانسه زندگی می‌کند و آن‌جا گشنگی و تشنگی می‌کشد و سخت محتاج دلجویی است. اگر همه‌ی این عذرها کافی نباشد اجازه می‌خواهم این کتاب را تقدیم آن بچه‌ای کنم که این آدم‌بزرگ یک روزی بوده. آخر هر آدم بزرگی هم روزی روزگاری بچه‌ای بوده (گیرم کم‌تر کسی از آن‌ها این را به یاد می‌آورد). پس من هم اهدانام‌چه‌ام را به این شکل تصحیح می‌کنم: + +به لئون ورث +موقعی که پسربچه بود +آنتوان دو سن‌تگزوپه‌ری + +من هم برگردان فارسی این شعر بزرگ را به دو بچه‌ی دوست‌داشتنی دیگر تقدیم می‌کنم: دکتر جهانگیر کازرونی و دکتر محمدجواد گلبن + +احمد شاملو + +۱ +یک بار شش سالم که بود تو کتابی به اسم قصه‌های واقعی -که درباره‌ی جنگل بِکر نوشته شده بود- تصویر محشری دیدم از یک مار بوآ که داشت حیوانی را می‌بلعید. آن تصویر یک چنین چیزی بود: + +یک مار بوآ که دارد حیوانی را می‌بلعد +تو کتاب آمده بود که: «مارهای بوآ شکارشان را همین جور درسته قورت می‌دهند. بی این که بجوندش. بعد دیگر نمی‌توانند از جا بجنبند و تمام شش ماهی را که هضمش طول می‌کشد می‌گیرند می‌خوابند». + +این را که خواندم، راجع به چیزهایی که تو جنگل اتفاق می‌افتد کلی فکر کردم و دست آخر توانستم با یک مداد رنگی اولین نقاشیم را از کار درآرم. یعنی نقاشی شماره‌ی یکم را که این جوری بود: + +نقاشی شماره‌ی یکم — مار شبیه به کلاه +شاهکارم را نشان بزرگ‌تر ها دادم و پرسیدم از دیدنش ترس‌تان بر می‌دارد؟ +جوابم دادند: -چرا کلاه باید آدم را بترساند؟ + +نقاشی من کلاه نبود، یک مار بوآ بود که داشت یک فیل را هضم می‌کرد. آن وقت برای فهم بزرگ‌ترها برداشتم توی شکم بوآ را کشیدم. آخر همیشه باید به آن‌ها توضیحات داد. نقاشی دومم این جوری بود: + +نقاشی دوم — مار و فیل درونش +بزرگ‌ترها بم گفتند کشیدن مار بوآی باز یا بسته را بگذارم کنار و عوضش حواسم را بیش‌تر جمع جغرافی و تاریخ و حساب و دستور زبان کنم. و این جوری شد که تو شش سالگی دور کار ظریف نقاشی را قلم گرفتم. از این که نقاشی شماره‌ی یک و نقاشی شماره‌ی دو ام یخ‌شان نگرفت دلسرد شده بودم. بزرگ‌ترها اگر به خودشان باشد هیچ وقت نمی‌توانند از چیزی سر درآرند. برای بچه‌ها هم خسته کننده است که همین جور مدام هر چیزی را به آن‌ها توضیح بدهند. + +ناچار شدم برای خودم کار دیگری پیدا کنم و این بود که رفتم خلبانی یاد گرفتم. بگویی نگویی تا حالا به همه جای دنیا پرواز کرده ام و راستی راستی جغرافی خیلی بم خدمت کرده. می‌توانم به یک نظر چین و آریزونا را از هم تمیز بدهم. اگر آدم تو دل شب سرگردان شده باشد جغرافی خیلی به دادش می‌رسد. + +از این راه است که من تو زندگیم با گروه گروه آدم‌های حسابی برخورد داشته‌ام. پیش خیلی از بزرگ‌ترها زندگی کرده‌ام و آن‌ها را از خیلی نزدیک دیده‌ام گیرم این موضوع باعث نشده در باره‌ی آن‌ها عقیده‌ی بهتری پیدا کنم. + +هر وقت یکی‌شان را گیر آورده‌ام که یک خرده روشن بین به نظرم آمده با نقاشی شماره‌ی یکم که هنوز هم دارمش محکش زده‌ام ببینم راستی راستی چیزی بارش هست یا نه. اما او هم طبق معمول در جوابم در آمده که: «این یک کلاه است». آن وقت دیگر من هم نه از مارهای بوآ باش اختلاط کرده‌ام نه از جنگل‌های بکر دست نخورده نه از ستاره‌ها. خودم را تا حد او آورده‌ام پایین و باش از بریج و گلف و سیاست و انواع کرات حرف زده‌ام. او هم از این که با یک چنین شخص معقولی آشنایی به هم رسانده سخت خوش‌وقت شده. + +۲ +این جوری بود که روزگارم تو تنهایی می‌گذشت بی این که راستی راستی یکی را داشته باشم که باش دو کلمه حرف بزنم، تااین که زد و شش سال پیش در کویر صحرا حادثه‌یی برایم اتفاق افتاد؛ یک چیز موتور هواپیمایم شکسته بود و چون نه تعمیرکاری همراهم بود نه مسافری یکه و تنها دست به کار شدم تا از پس چنان تعمیر مشکلی برآیم. مساله‌ی مرگ و زندگی بود. آبی که داشتم زورکی هشت روز را کفاف می‌داد. + +شب اول را هزار میل دورتر از هر آبادی مسکونی رو ماسه‌ها به روز آوردم پرت افتاده‌تر از هر کشتی شکسته‌یی که وسط اقیانوس به تخته پاره‌یی چسبیده باشد. پس لابد می‌توانید حدس بزنید چه جور هاج و واج ماندم وقتی کله‌ی آفتاب به شنیدن صدای ظریف عجیبی که گفت: «بی زحمت یک برّه برام بکش!» از خواب پریدم. +-ها؟ +-یک برّه برام بکش... + +چنان از جا جستم که انگار صاعقه بم زده. خوب که چشم‌هام را مالیدم و نگاه کردم آدم کوچولوی بسیار عجیبی را دیدم که با وقار تمام تو نخ من بود. این به‌ترین شکلی است که بعد ها توانستم از او در آرم، گیرم البته آن‌چه من کشیده‌ام کجا و خود او کجا! تقصیر من چیست؟ بزرگ‌تر ها تو شش سالگی از نقاشی دل‌سردم کردند و جز بوآی باز و بسته یاد نگرفتم چیزی بکشم. + +با چشم‌هایی که از تعجب گرد شده بود به این حضور ناگهانی خیره شدم. یادتان نرود که من از نزدیک‌ترین آبادی مسکونی هزار میل فاصله داشتم و این آدمی‌زاد کوچولوی من هم اصلا به نظر نمی‌آمد که راه گم کرده باشد یا از خستگی دم مرگ باشد یا از گشنگی دم مرگ باشد یا از تشنگی دم مرگ باشد یا از وحشت دم مرگ باشد. هیچ چیزش به بچه‌یی نمی‌بُرد که هزار میل دور از هر آبادی مسکونی تو دل صحرا گم شده باشد. + +این بهترین شکلی است که بعدها از او در آوردم. +وقتی بالاخره صدام در آمد، گفتم: +-آخه... تو این جا چه می‌کنی؟ +و آن وقت او خیلی آرام، مثل یک چیز خیلی جدی، دوباره در آمد که: +-بی زحمت واسه‌ی من یک برّه بکش. +آدم وقتی تحت تاثیر شدید رازی قرار گرفت جرات نافرمانی نمی‌کند. گرچه تو آن نقطه‌ی هزار میل دورتر از هر آبادی مسکونی و با قرار داشتن در معرض خطر مرگ این نکته در نظرم بی معنی جلوه کرد باز کاغذ و خودنویسی از جیبم در آوردم اما تازه یادم آمد که آن‌چه من یاد گرفته‌ام بیش‌تر جغرافیا و تاریخ و حساب و دستور زبان است، و با کج خلقی مختصری به آن موجود کوچولو گفتم نقاشی بلد نیستم. +بم جواب داد: -عیب ندارد، یک بَرّه برام بکش. + +از آن‌جایی که هیچ وقت تو عمرم بَرّه نکشیده بودم یکی از آن دو تا نقاشی‌ای را که بلد بودم برایش کشیدم. آن بوآی بسته را. ولی چه یکه‌ای خوردم وقتی آن موجود کوچولو در آمد که: -نه! نه! فیلِ تو شکم یک بوآ نمی‌خواهم. بوآ خیلی خطرناک است فیل جا تنگ کن. خانه‌ی من خیلی کوچولوست، من یک بره لازم دارم. برام یک بره بکش.بره‌ی مریض +-خب، کشیدم. +با دقت نگاهش کرد و گفت: +-نه! این که همین حالاش هم حسابی مریض است. یکی دیگر بکش.قوچ +-کشیدم. +لبخند با نمکی زد و در نهایت گذشت گفت: +-خودت که می‌بینی... این بره نیست، قوچ است. شاخ دارد نه...بره‌ی پیر +باز نقاشی را عوض کردم. +آن را هم مثل قبلی ها رد کرد: +-این یکی خیلی پیر است... من یک بره می‌خواهم که مدت ها عمر کند... + +باری چون عجله داشتم که موتورم را پیاده کنم رو بی حوصلگی جعبه‌ای کشیدم که دیواره‌اش سه تا سوراخ داشت، و از دهنم پرید که:جعبه +-این یک جعبه است. بره‌ای که می‌خواهی این تو است. + +و چه قدر تعجب کردم از این که دیدم داور کوچولوی من قیافه‌اش از هم باز شد و گفت: +-آها... این درست همان چیزی است که می‌خواستم! فکر می‌کنی این بره خیلی علف بخواهد؟ +-چطور مگر؟ +-آخر جای من خیلی تنگ است... +-هر چه باشد حتماً بسش است. بره‌یی که بت داده‌ام خیلی کوچولوست. +-آن قدرهاهم کوچولو نیست... اِه! گرفته خوابیده... + +و این جوری بود که من با شهریار کوچولو آشنا شدم. + +۳ +خیلی طول کشید تا توانستم بفهمم از کجا آمده. شهریار کوچولو که مدام مرا سوال پیچ می‌کرد خودش انگار هیچ وقت سوال‌های مرا نمی‌شنید. فقط چیزهایی که جسته گریخته از دهنش می‌پرید کم کم همه چیز را به من آشکار کرد. مثلا اول بار که هواپیمای مرا دید (راستی من هواپیما نقاشی نمی‌کنم، سختم است.) ازم پرسید: +-این چیز چیه؟ +-این «چیز» نیست: این پرواز می‌کند. هواپیماست. هواپیمای من است. + +و از این که به‌اش می‌فهماندم من کسی‌ام که پرواز می‌کنم به خود می‌بالیدم. +حیرت زده گفت: -چی؟ تو از آسمان افتاده‌ای؟ +با فروتنی گفتم: -آره. +گفت: -اوه، این دیگر خیلی عجیب است! +و چنان قهقهه‌ی ملوسی سر داد که مرا حسابی از جا در برد. راستش من دلم می‌خواهد دیگران گرفتاری‌هایم را جدی بگیرند. +خنده‌هایش را که کرد گفت: -خب، پس تو هم از آسمان می‌آیی! اهل کدام سیاره‌ای؟... + +بفهمی نفهمی نور مبهمی به معمای حضورش تابید. یکهو پرسیدم: +-پس تو از یک سیاره‌ی دیگر آمده‌ای؟ +آرام سرش را تکان داد بی این که چشم از هواپیما بردارد. + +اما جوابم را نداد، تو نخ هواپیما رفته بود و آرام آرام سر تکان می‌داد. +گفت: -هر چه باشد با این نباید از جای خیلی دوری آمده باشی... + +مدت درازی تو خیال فرو رفت، بعد بره‌اش را از جیب در آورد و محو تماشای آن گنج گرانبها شد.تصویری از شهریار کوچولو بر روی زمین +فکر می‌کنید از این نیمچه اعتراف «سیاره‌ی دیگر»ِ او چه هیجانی به من دست داد؟ زیر پاش نشستم که حرف بیشتری از زبانش بکشم: +-تو از کجا می‌آیی آقا کوچولوی من؟ خانه‌ات کجاست؟ بره‌ی مرا می‌خواهی کجا ببری؟ +مدتی در سکوت به فکر فرورفت و بعد در جوابم گفت: +-حسن جعبه‌ای که بم داده‌ای این است که شب‌ها می‌تواند خانه‌اش بشود. +-معلوم است... اما اگر بچه‌ی خوبی باشی یک ریسمان هم بِت می‌دهم که روزها ببندیش. یک ریسمان با یک میخ طویله... +انگار از پیش‌نهادم جا خورد، چون که گفت: +-ببندمش؟ چه فکر ها! +-آخر اگر نبندیش راه می‌افتد می‌رود گم می‌شود. + +دوست کوچولوی من دوباره غش غش خنده را سر داد: +-مگر کجا می‌تواند برود؟ +-خدا می‌داند. راستِ شکمش را می‌گیرد و می‌رود... +-بگذار برود...اوه، خانه‌ی من آن‌قدر کوچک است! +و شاید با یک خرده اندوه در آمد که: +-یک‌راست هم که بگیرد برود جای دوری نمی‌رود... + +۴ +به این ترتیب از یک موضوع خیلی مهم دیگر هم سر در آوردم: این که سیاره‌ی او کمی از یک خانه‌ی معمولی بزرگ‌تر بود.این نکته آن‌قدرها به حیرتم نینداخت. می‌دانستم گذشته از سیاره‌های بزرگی مثل زمین و کیوان و تیر و ناهید که هرکدام برای خودشان اسمی دارند، صدها سیاره‌ی دیگر هم هست که بعضی‌شان از بس کوچکند با دوربین نجومی هم به هزار زحمت دیده می‌شوند و هرگاه اخترشناسی یکی‌شان را کشف کند به جای اسم شماره‌ای به‌اش می‌دهد. مثلا اسمش را می‌گذارد «اخترک ۳۲۵۱». + +دلایل قاطعی دارم که ثابت می‌کند شهریار کوچولو از اخترک ب۶۱۲ آمده‌بود. + +شهریار کوچولو بر اخترکِ ب۶۱۲ +این اخترک را فقط یک بار به سال ۱۹۰۹ یک اخترشناس ترک توانسته بود ببیند اخترشناسِ ترک در حالِ دیدنِ اخترکِ ب۶۱۲که تو یک کنگره‌ی بین‌المللی نجوم هم با کشفش هیاهوی زیادی به راه انداخت اما واسه خاطر لباسی که تنش بود هیچ کس حرفش را باور نکرد. اخترشناسِ ترک در کنگره‌ی بین‌المللیِ نجوم، با لباس قدیمیآدم بزرگ‌ها این جوری‌اند! + +بختِ اخترک ب۶۱۲ زد و، ترک مستبدی ملتش را به ضرب دگنک وادار به پوشیدن لباس اروپایی‌ها کرد. اخترشناس به سال ۱۹۲۰ دوباره، و این بار با سر و وضع آراسته برای کشفش ارائه‌ی دلیل کرد و این بار همه جانب او را گرفتند.اخترشناسِ ترک در کنگره‌ی بین‌المللیِ نجوم، با لباس جدید +به خاطر آدم بزرگ‌هاست که من این جزئیات را در باب اخترکِ ب۶۱۲ برای‌تان نقل می‌کنم یا شماره‌اش را می‌گویم چون که آن‌ها عاشق عدد و رقم‌اند. وقتی با آن‌ها از یک دوست تازه‌تان حرف بزنید هیچ وقت ازتان درباره‌ی چیزهای اساسی‌اش سوال نمی‌کنند که هیج وقت نمی‌پرسند «آهنگ صداش چه‌طور است؟ چه بازی‌هایی را بیشتر دوست دارد؟ پروانه جمع می‌کند یا نه؟» -می‌پرسند: «چند سالش است؟ چند تا برادر دارد؟ وزنش چه‌قدر است؟ پدرش چه‌قدر حقوق می‌گیرد؟» و تازه بعد از این سوال‌ها است که خیال می‌کنند طرف را شناخته‌اند. + +اگر به آدم بزرگ‌ها بگویید یک خانه‌ی قشنگ دیدم از آجر قرمز که جلو پنجره‌هاش غرقِ شمعدانی و بامش پر از کبوتر بود محال است بتوانند مجسمش کنند. باید حتماً به‌شان گفت یک خانه‌ی صد میلیون تومنی دیدم تا صداشان بلند بشود که: -وای چه قشنگ! + +یا مثلا اگر به‌شان بگویید «دلیل وجودِ شهریارِ کوچولو این که تودل‌برو بود و می‌خندید و دلش یک بره می‌خواست و بره خواستن، خودش بهترین دلیل وجود داشتن هر کسی است» شانه بالا می‌اندازند و باتان مثل بچ‌ه‌ها رفتار می‌کنند! اما اگر به‌شان بگویید «سیاره‌ای که ازش آمده‌بود اخترک ب۶۱۲ است» بی‌معطلی قبول می‌کنند و دیگر هزار جور چیز ازتان نمی‌پرسند. این جوری‌اند دیگر. نباید ازشان دل‌خور شد. بچه‌ها باید نسبت به آدم بزرگ‌ها گذشت داشته باشند. + +اما البته ماها که مفهوم حقیقی زندگی را درک می‌کنیم می‌خندیم به ریش هرچه عدد و رقم است! چیزی که من دلم می‌خواست این بود که این ماجرا را مثل قصه‌ی پریا نقل کنم. دلم می‌خواست بگویم: «یکی بود یکی نبود. روزی روزگاری یه شهریار کوچولو بود که تو اخترکی زندگی می‌کرد همه‌اش یه خورده از خودش بزرگ‌تر و واسه خودش پیِ دوستِ هم‌زبونی می‌گشت...»، آن هایی که مفهوم حقیقی زندگی را درک کرده‌اند واقعیت قضیه را با این لحن بیشتر حس می‌کنند. آخر من دوست ندارم کسی کتابم را سرسری بخواند. خدا می‌داند با نقل این خاطرات چه بار غمی روی دلم می‌نشیند. شش سالی می‌شود که دوستم با بَرّه‌اش رفته. این که این جا می‌کوشم او را وصف کنم برای آن است که از خاطرم نرود. فراموش کردن یک دوست خیلی غم‌انگیز است. همه کس که دوستی ندارد. من هم می‌توانم مثل آدم بزرگ‌ها بشوم که فقط اعداد و ارقام چشم‌شان را می‌گیرد. و باز به همین دلیل است که رفته‌ام یک جعبه رنگ و چند تا مداد خریده‌ام. تو سن و سال من واسه کسی که جز کشیدنِ یک بوآی باز یا یک بوآی بسته هیچ کار دیگری نکرده -و تازه آن هم در شش سالگی- دوباره به نقاشی رو کردن از آن حرف‌هاست! البته تا آن‌جا که بتوانم سعی می‌کنم چیزهایی که می‌کشم تا حد ممکن شبیه باشد. گیرم به موفقیت خودم اطمینان چندانی ندارم. یکیش شبیه از آب در می‌آید یکیش نه. سرِ قدّ و قواره‌اش هم حرف است. یک جا زیادی بلند درش آورده‌ام یک جا زیادی کوتاه. از رنگ لباسش هم مطمئن نیستم. خب، رو حدس و گمان پیش رفته‌ام؛ کاچی به زِ هیچی. و دست آخر گفته باشم که تو بعضِ جزئیات مهم‌ترش هم دچار اشتباه شده‌ام. اما در این مورد دیگر باید ببخشید: دوستم زیر بار هیچ جور شرح و توصیفی نمی‌رفت. شاید مرا هم مثل خودش می‌پنداشت. اما از بختِ بد، دیدن بره‌ها از پشتِ جعبه از من بر نمی‌آید. نکند من هم یک خرده به آدم بزرگ‌ها رفته‌ام؟ «باید پیر شده باشم». + +۵ +هر روزی که می‌گذشت از اخترک و از فکرِ عزیمت و از سفر و این حرف‌ها چیزهای تازه‌ای دست‌گیرم می‌شد که همه‌اش معلولِ بازتاب‌هایِ اتفاقی بود. و از همین راه بود که روز سوم از ماجرایِ تلخِ بائوباب ها سردرآوردم. + +این بار هم بَرّه باعثش شد، چون شهریار کوچولو که انگار سخت دودل مانده‌بود ناگهان ازم پرسید: +-بَرّه‌ها بته‌ها را هم می‌خورند دیگر، مگر نه؟ +-آره. همین جور است. +-آخ! چه خوشحال شدم! + +نتوانستم بفهمم این موضوع که بَرّه‌ها بوته‌ها را هم می‌خورند اهمیتش کجاست اما شهریار کوچولو درآمد که: +-پس لابد بائوباب ها را هم می‌خورند دیگر؟ + +یک گله فیل که در اخترکِ ب۶۱۲ روی هم چیده شده‌اندمن برایش توضیح دادم که بائوباب بُتّه نیست. درخت است و از ساختمان یک معبد هم گنده‌تر، و اگر یک گَلّه فیل هم با خودش ببرد حتا یک درخت بائوباب را هم نمی‌توانند بخورند. +از فکر یک گَلّه فیل به خنده افتاد و گفت: -باید چیدشان روی هم. +اما با فرزانگی تمام متذکر شد که: -بائوباب هم از بُتِّگی شروع می‌کند به بزرگ شدن. +-درست است. اما نگفتی چرا دلت می‌خواهد بره‌هایت نهال‌های بائوباب را بخورند؟ +گفت: -دِ! معلوم است! + +و این را چنان گفت که انگار موضوع از آفتاب هم روشن‌تر است؛ منتها من برای این که به تنهایی از این راز سر در آرم ناچار شدم حسابی کَلّه را به کار بیندازم. + +راستش این که تو اخترکِ شهریار کوچولو هم مثل سیارات دیگر هم گیاهِ خوب به هم می‌رسید هم گیاهِ بد. یعنی هم تخمِ خوب گیاه‌های خوب به هم می‌رسید، هم تخمِ بدِ گیاه‌هایِ بد. اما تخم گیاه‌ها نامریی‌اند. آن‌ها تو حرمِ تاریک خاک به خواب می‌روند تا یکی‌شان هوس بیدار شدن به سرش بزند. آن وقت کش و قوسی می‌آید و اول با کم رویی شاخکِ باریکِ خوشگل و بی‌آزاری به طرف خورشید می‌دواند. اگر این شاخک شاخکِ تربچه‌ای گلِ سرخی چیزی باشد می‌شود گذاشت برای خودش رشد کند اما اگر گیاهِ بدی باشد آدم باید به مجردی که دستش را خواند ریشه‌کنش کند. + +باری، تو سیاره‌ی شهریار کوچولو گیاه تخمه‌های وحشتناکی به هم می‌رسید. یعنی تخم درختِ بائوباب که خاکِ سیاره حسابی ازشان لطمه خورده بود. بائوباب هم اگر دیر به‌اش برسند دیگر هیچ جور نمی‌شود حریفش شد: تمام سیاره را می‌گیرد و با ریشه‌هایش سوراخ سوراخش می‌کند و اگر سیاره خیلی کوچولو باشد و بائوباب‌ها خیلی زیاد باشند پاک از هم متلاشیش می‌کنند. + +شهریار کوچولو در حال نظافت ِ اخترکششهریار کوچولو بعدها یک روز به من گفت: «این، یک امر انضباطی است. صبح به صبح بعد از نظافتِ خود باید با دفت تمام به نظافتِ اخترک پرداخت. آدم باید خودش را مجبور کند که به مجردِ تشخیص دادن بائوباب‌ها از بته‌های گلِ سرخ که تا کوچولواَند عین هم‌اَند با دقت ریشه‌کن‌شان بکند. کار کسل‌کننده‌ای هست اما هیچ مشکل نیست.» + +یک روز هم بم توصیه کرد سعی کنم هر جور شده یک نقاشی حسابی از کار درآرم که بتواند قضیه را به بچه‌های سیاره‌ی من هم حالی کند. گفت اگر یک روز بروند سفر ممکن است به دردشان بخورد. پاره‌ای وقت‌ها پشت گوش انداختن کار ایرادی ندارد اما اگر پای بائوباب در میان باشد گاوِ آدم می‌زاید. اخترکی را سراغ دارم که یک تنبل‌باشی ساکنش بود و برای کندن سه تا نهال بائوباب امروز و فردا کرد...». + +آن وقت من با استفاده از چیزهایی که گفت شکل آن اخترک را کشیدم. + +اخترکِ تنبل‌باشی با سه درختِ بائوباب +هیچ دوست ندارم اندرزگویی کنم. اما خطر بائوباب‌ها آن‌قدر کم شناخته شده و سر راهِ کسی که تو چنان اخترکی سرگیدان بشود آن قدر خطر به کمین نشسته که این مرتبه را از رویه‌ی همیشگی خودم دست بر می‌دارم و می‌گویم: «بچه‌ها! هوای بائوباب‌ها را داشته باشید!» + +اگر من سرِ این نقاشی این همه به خودم فشار آورده‌ام فقط برای آن بوده که دوستانم را متوجه خطری کنم که از مدت‌ها پیش بیخ گوش‌شان بوده و مثلِ خودِ من ازش غافل بوده‌اند. درسی که با این نقاشی داده‌ام به زحمتش می‌ارزد. حالا ممکن است شما از خودتان بپرسید: «پس چرا هیچ کدام از بقیه‌ی نقاشی‌های این کتاب هیبتِ تصویرِ بائوباب‌ها را ندارد؟» -خب، جوابش خیلی ساده است: من زور خودم را زده‌ام اما نتوانسته‌ام از کار درشان بیاورم. اما عکس بائوباب‌ها را که می‌کشیدم احساس می‌کردم قضیه خیلی فوریت دارد و به این دلیل شور بَرَم داشته بود. + +۶ +آخ، شهریار کوچولو! این جوری بود که من کَم کَمَک از زندگیِ محدود و دل‌گیر تو سر درآوردم. تا مدت‌ها تنها سرگرمیِ تو تماشای زیباییِ غروب آفتاب بوده. به این نکته‌ی تازه صبح روز چهارم بود که پی بردم؛ یعنی وقتی که به من گفتی: +-غروب آفتاب را خیلی دوست دارم. برویم فرورفتن آفتاب را تماشا کنیم...شهریار کوچولو در اخترکش مشغولِ تماشای غروبِ آفتاب +-هوم، حالاها باید صبر کنی... +-واسه چی صبر کنم؟ +-صبر کنی که آفتاب غروب کند. + +اول سخت حیرت کردی بعد از خودت خنده‌ات گرفت و برگشتی به من گفتی: +-همه‌اش خیال می‌کنم تو اخترکِ خودمم! +-راستش موقعی که تو آمریکا ظهر باشد همه می‌دانند تو فرانسه تازه آفتاب دارد غروب می‌کند. کافی است آدم بتواند در یک دقیقه خودش را برساند به فرانسه تا بتواند غروب آفتاب را تماشا کند. متاسفانه فرانسه کجا این‌جا کجا! اما رو اخترک تو که به آن کوچکی است همین‌قدر که چند قدمی صندلیت را جلو بکشی می‌توانی هرقدر دلت خواست غروب تماشا کنی. +-یک روز چهل و سه بار غروب آفتاب را تماشا کردم! +و کمی بعد گفت: +-خودت که می‌دانی... وقتی آدم خیلی دلش گرفته باشد از تماشای غروب لذت می‌برد. +-پس خدا می‌داند آن روز چهل و سه غروبه چه‌قدر دلت گرفته بوده. + +اما مسافر کوچولو جوابم را نداد. + +۷ +روز پنجم باز سرِ گوسفند از یک راز دیگر زندگی شهریار کوچولو سر در آوردم. مثل چیزی که مدت‌ه‌ا تو دلش به‌اش فکر کرده باشد یک‌هو بی مقدمه از من پرسید: +-گوسفندی که بُتّه ها را بخورد گل ها را هم می‌خورد؟ +-گوسفند هرچه گیرش بیاید می‌خورد. +-حتا گل‌هایی را هم که خار دارند؟ +-آره، حتا گل‌هایی را هم که خار دارند. +-پس خارها فایده‌شان چیست؟ + +من چه می‌دانستم؟ یکی از آن: سخت گرفتار باز کردن یک مهره‌ی سفتِ موتور بودم. از این که یواش یواش بو می‌بردم خرابیِ کار به آن سادگی‌ها هم که خیال می‌کردم نیست برج زهرمار شده‌بودم و ذخیره‌ی آبم هم که داشت ته می‌کشید بیش‌تر به وحشتم می‌انداخت. +-پس خارها فایده‌شان چسیت؟ + +شهریار کوچولو وقتی سوالی را می‌کشید وسط دیگر به این مفتی‌ها دست بر نمی‌داشت. مهره پاک کلافه‌ام کرده بود. همین جور سرسری پراندم که: +-خارها به درد هیچ کوفتی نمی‌خورند. آن‌ها فقط نشانه‌ی بدجنسی گل‌ها هستند. +-دِ! +و پس از لحظه‌یی سکوت با یک جور کینه درآمد که: +-حرفت را باور نمی‌کنم! گل‌ها ضعیفند. بی شیله‌پیله‌اند. سعی می‌کنند یک جوری تهِ دل خودشان را قرص کنند. این است که خیال می‌کنند با آن خارها چیزِ ترسناکِ وحشت‌آوری می‌شوند... + +لام تا کام به‌اش جواب ندادم. در آن لحظه داشتم تو دلم می‌گفتم: «اگر این مهره‌ی لعنتی همین جور بخواهد لج کند با یک ضربه‌ی چکش حسابش را می‌رسم.» اما شهریار کوچولو دوباره افکارم را به هم ریخت: +-تو فکر می‌کنی گل‌ها... +من باز همان جور بی‌توجه گفتم: +-ای داد بیداد! ای داد بیداد! نه، من هیچ کوفتی فکر نمی‌کنم! آخر من گرفتار هزار مساله‌ی مهم‌تر از آنم! +هاج و واج نگاهم کرد و گفت: +-مساله‌ی مهم! + +مرا می‌دید که چکش به دست با دست و بالِ سیاه روی چیزی که خیلی هم به نظرش زشت می‌آمد خم شده‌ام. +-مثل آدم بزرگ‌ها حرف می‌زنی! +از شنیدنِ این حرف خجل شدم اما او همین جور بی‌رحمانه می‌گفت: +-تو همه چیز را به هم می‌ریزی... همه چیز را قاتی می‌کنی! +حسابی از کوره در رفته‌بود. + +موهای طلایی طلائیش تو باد می‌جنبید. +-اخترکی را سراغ دارم که یک آقا سرخ روئه توش زندگی می‌کند. او هیچ وقت یک گل را بو نکرده، هیچ وقت یک ستاره‌را تماشا نکرده هیچ وقت کسی را دوست نداشته هیچ وقت جز جمع زدن عددها کاری نکرده. او هم مثل تو صبح تا شب کارش همین است که بگوید: «من یک آدم مهمم! یک آدم مهمم!» این را بگوید و از غرور به خودش باد کند. اما خیال کرده: او آدم نیست، یک قارچ است! +-یک چی؟ +-یک قارچ!گلِ سرخ +حالا دیگر رنگش از فرط خشم مثل گچ سفید شده‌بود: +-کرورها سال است که گل‌ها خار می‌سازند و با وجود این کرورها سال است که برّه‌ها گل‌ها را می‌خورند. آن وقت هیچ مهم نیست آدم بداند پس چرا گل‌ها واسه ساختنِ خارهایی که هیچ وقتِ خدا به هیچ دردی نمی‌خورند این قدر به خودشان زحمت می‌دهند؟ جنگ میان برّه‌ها و گل‌ها هیچ مهم نیست؟ این موضوع از آن جمع زدن‌های آقا سرخ‌روئه‌یِ شکم‌گنده مهم‌تر و جدی‌تر نیست؟ اگر من گلی را بشناسم که تو همه‌ی دنیا تک است و جز رو اخترک خودم هیچ جای دیگر پیدا نمیشه و ممکن است یک روز صبح یک برّه کوچولو، مفت و مسلم، بی این که بفهمد چه‌کار دارد می‌کند به یک ضرب پاک از میان ببردش چی؟ یعنی این هم هیچ اهمیتی ندارد؟ اگر کسی گلی را دوست داشته باشد که تو کرورها و کرورها ستاره فقط یک دانه ازش هست واسه احساس وشبختی همین قدر بس است که نگاهی به آن همه ستاره بیندازد و با خودش بگوید: «گل من یک جایی میان آن ستاره‌هاست»، اما اگر برّه گل را بخورد برایش مثل این است که یکهو تمام آن ستاره‌ها پِتّی کنند و خاموش بشوند. یعنی این هم هیچ اهمیتی ندارد؟ +دیگر نتوانست چیزی بگوید و ناگهان هِق هِق کنان زد زیر گریه. + +حالا دیگر شب شده‌بود. اسباب و ابزارم را کنار انداخته‌بودم. دیگر چکش و مهره و تشنگی و مرگ به نظرم مضحک می‌آمد. رو ستاره‌ای، رو سیاره‌ای، رو سیاره‌ی من، زمین، شهریارِ کوچولویی بود که احتیاج به دلداری داشت! به آغوشش گرفتم مثل گهواره تابش دادم به‌اش گفتم: «گلی که تو دوست داری تو خطر نیست. خودم واسه گوسفندت یک پوزه‌بند می‌کشم... خودم واسه گفت یک تجیر می‌کشم... خودم...» بیش از این نمی‌دانستم چه بگویم. خودم را سخت چُلمَن و بی دست و پا حس می‌کردم. نمی‌دانستم چه‌طور باید خودم را به‌اش برسانم یا به‌اش بپیوندم...p چه دیار اسرارآمیزی است دیار اشک! + +۸ +راه شناختن آن گل را خیلی زود پیدا کردم: +تو اخترکِ شهریار کوچولو همیشه یک مشت گل‌های خیلی ساده در می‌آمده. گل‌هایی با یک ردیف گلبرگ که جای چندانی نمی‌گرفته، دست و پاگیرِ کسی نمی‌شده. صبحی سر و کله‌شان میان علف‌ها پیدا می‌شده شب از میان می‌رفته‌اند. اما این یکی یک روز از دانه‌ای جوانه زده بود که خدا می‌دانست از کجا آمده رود و شهریار کوچولو با جان و دل از این شاخکِ نازکی که به هیچ کدام از شاخک‌های دیگر نمی‌رفت مواظبت کرده‌بود. بعید بنود که این هم نوعِ تازه‌ای از بائوباب باشد اما بته خیلی زود از رشد بازماند و دست‌به‌کارِ آوردن گل شد. شهریار کوچولو که موقعِ نیش زدن آن غنچه‌ی بزرگ حاضر و ناظر بود به دلش افتاد که باید چیز معجزه‌آسایی از آن بیرون بیاید. اما گل تو پناهِ خوابگاهِ سبزش سر فرصت دست اندکار خودآرایی بود تا هرچه زیباتر جلوه‌کند. رنگ‌هایش را با وسواس تمام انتخاب می‌کرد سر صبر لباس می‌پوشید و گلبرگ‌ها را یکی یکی به خودش می‌بست. دلش نمی‌خواست مثل شقایق‌ها با جامه‌ی مچاله و پر چروک بیرون بیاید. + +شهریار کوچولو و گلِ سرخنمی‌خواست جز در اوج درخشندگی زیبائیش رو نشان بدهد!... + +هوه، بله عشوه‌گری تمام عیار بود! آرایشِ پر راز و رمزش روزها و روزها طول کشید تا آن که سرانجام یک روز صبح درست با بر آمدن آفتاب نقاب از چهره برداشت و با این که با آن همه دقت و ظرافت روی آرایش و پیرایش خودش کار کرده بود خمیازه‌کشان گفت: +-اوه، تازه همین حالا از خواب پا شده‌ام... عذر می‌خواهم که موهام این جور آشفته‌است... + +شهریار کوچولو نتوانست جلو خودش را بگیرد و از ستایش او خودداری کند: +-وای چه‌قدر زیبائید! +گل به نرمی گفت: +-چرا که نه؟ من و آفتاب تو یک لحظه به دنیا آمدیم... +شهریار کوچولو شستش خبردار شد که طرف آن‌قدرها هم اهل شکسته‌نفسی نیست اما راستی که چه‌قدر هیجان انگیز بود! +-به نظرم وقت خوردن ناشتایی است. بی زحمت برایم فکری بکنید. +و شهریار کوچولوی مشوش و در هم یک آبپاش آب خنک آورده به گل داده‌بود.شهریار کوچولو در حالِ تماشای گلِ سرخ +با این حساب، هنوزهیچی نشده با آن خودپسندیش که بفهمی‌نفهمی از ضعفش آب می‌خورد دل او را شکسته بود. مثلا یک روز که داشت راجع به چهارتا خارش حرف می‌زد یک‌هو در آمده بود که:ببر و گلِ سرخ +-نکند ببرها با آن چنگال‌های تیزشان بیایند سراغم! +شهریار کوچولو ازش ایراد گرفته‌بود که: +-تو اخترک من ببر به هم نمی‌رسد. تازه ببرها که علف‌خوار نیستند. +گل به گلایه جواب داده بود: +-من که علف نیستم. +و شهریار کوچولو گفته بود: +-عذر می‌خواهم... +-من از ببرها هیچ ترسی ندارم اما از جریان هوا وحشت می‌کنم. تو دستگاه‌تان تجیر به هم نمی‌رسد؟شهریار کوچولو در حالِ پوشاندنِ گلِ سرخ +شهریار کوچولو تو دلش گفت: «وحشت از جریان هوا... این که واسه یک گیاه تعریفی ندارد... چه مرموز است این گل!» +-شب مرا بگذارید زیر یک سرپوش. این جا هواش خیلی سرد است. چه جای بدی افتادم! جایی که پیش از این بودم...شهریار کوچولو در حالِ گذاشتنِ سرپوش روی گلِ سرخ +اما حرفش را خورده بود. آخر، آمدنا هنوز به شکل دانه بود. امکان نداشت توانسته‌باشد دنیاهای دیگری را بشناسد. شرم‌سار از این که گذاشته بود سر به هم بافتن دروغی به این آشکاری مچش گیربیفتد دو سه بار سرفه کرده بود تا اهمالِ شهریار کوچولو را به‌اش یادآور شود: +-تجیر کو پس؟ +-داشتم می‌رفتم اما شما داشتید صحبت می‌کردید! +و با وجود این زورکی بنا کرده‌بود به سرفه کردن تا او احساس پشیمانی کند. + +به این ترتیب شهریار کوچولو با همه‌ی حسن نیّتی که از عشقش آب می‌خورد همان اول کار به او بد گمان شده‌بود. حرف‌های بی سر و تهش را جدی گرفته‌بود و سخت احساس شوربختی می‌کرد. + +یک روز دردِدل کنان به من گفت: -حقش بود به حرف‌هاش گوش نمی‌دادم. هیچ وقت نباید به حرف گل‌ها گوش داد. گل را فقط باید بوئید و تماشا کرد. گلِ من تمامِ اخترکم را معطر می‌کرد گیرم من بلد نبودم چه‌جوری از آن لذت ببرم. قضیه‌ی چنگال‌های ببر که آن جور دَمَغم کرده‌بود می‌بایست دلم را نرم کرده باشد...» + +یک روز دیگر هم به من گفت: «آن روزها نتوانستم چیزی بفهمم. من بایست روی کرد و کارِ او در باره‌اش قضاوت می‌کردم نه روی گفتارش... عطرآگینم می‌کرد. دلم را روشن می‌کرد. نمی‌بایست ازش بگریزم. می‌بایست به مهر و محبتی که پشتِ آن کلک‌های معصومانه‌اش پنهان بود پی می‌بردم. گل‌ها پُرَند از این جور تضادها. اما خب دیگر، من خام‌تر از آن بودم که راهِ دوست داشتنش را بدانم!». + +۹ +گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرنده‌های وحشی استفاده کرد. + +گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرنده‌های وحشی استفاده کرد. +صبح روز حرکت، اخترکش را آن جور که باید مرتب کرد، آتش‌فشان‌های فعالش را با دقت پاک و دوده‌گیری کرد: شهریار کوچولو در حالِ پاک کردنِ آتش‌فشان.دو تا آتش‌فشان فعال داشت که برای گرم کردن ناشتایی خیلی خوب بود. یک آتش‌فشان خاموش هم داشت. منتها به قول خودش «آدم کف دستش را که بو نکرده!» این بود که آتش‌فشان خاموش را هم پاک کرد. آتش‌فشان که پاک باشد مرتب و یک هوا می‌سوزد و یک‌هو گُر نمی‌زند. آتش‌فشان هم عین‌هو بخاری یک‌هو اَلُو می‌زند. البته ما رو سیاره‌مان زمین کوچک‌تر از آن هستیم که آتش‌فشان‌هامان را پاک و دوده‌گیری کنیم و برای همین است که گاهی آن جور اسباب زحمت‌مان می‌شوند. + +شهریار کوچولو با دل‌ِگرفته آخرین نهال‌های بائوباب را هم ریشه‌کن کرد. فکر می‌کرد دیگر هیچ وقت نباید برگردد. اما آن روز صبح گرچه از این کارهای معمولیِ هر روزه کُلّی لذت برد موقعی که آخرین آب را پای گل داد و خواست بگذاردش زیرِ سرپوش چیزی نمانده‌بود که اشکش سرازیر شود. +به گل گفت: -خدا نگهدار! +اما او جوابش را نداد. +دوباره گفت: -خدا نگهدار! +گل سرفه‌کرد، گیرم این سرفه اثر چائیدن نبود. بالاخره به زبان آمد و گفت: +-من سبک مغز بودم. ازت عذر می‌خواهم. سعی کن خوشبخت باشی. +از این که به سرکوفت و سرزنش‌های همیشگی برنخورد حیرت کرد و سرپوش به دست هاج‌وواج ماند. از این محبتِ آرام سر در نمی‌آورد. +گل به‌اش گفت: -خب دیگر، دوستت دارم. اگر تو روحت هم از این موضوع خبردار نشد تقصیر من است. باشد، زیاد مهم نیست. اما تو هم مثل من بی‌عقل بودی... سعی کن خوشبخت بشوی... این سرپوش را هم بگذار کنار، دیگر به دردم نمی‌خورد. +-آخر، باد... +-آن قدرهاهم سَرمائو نیستم... هوای خنک شب برای سلامتیم خوب است. خدانکرده گُلم آخر. +-آخر حیوانات... +-اگر خواسته‌باشم با شب‌پره‌ها آشنا بشوم جز این که دو سه تا کرمِ حشره را تحمل کنم چاره‌ای ندارم. شب‌پره باید خیلی قشنگ باشد. جز آن کی به دیدنم می‌آید؟ تو که می‌روی به آن دور دورها. از بابتِ درنده‌ها هم هیچ کَکَم نمی‌گزد: «من هم برای خودم چنگ و پنجه‌ای دارم». +و با سادگی تمام چهارتا خارش را نشان داد. بعد گفت: +-دست‌دست نکن دیگر! این کارت خلق آدم را تنگ می‌کند. حالا که تصمیم گرفته‌ای بروی برو! + +و این را گفت، چون که نمی‌خواست شهریار کوچولو گریه‌اش را ببیند. گلی بود تا این حد خودپسند... + +۱۰ +خودش را در منطقه‌ی اخترک‌های ۳۲۵، ۳۲۶، ۳۲۷، ۳۲۸، ۳۲۹ و ۳۳۰ دید. این بود که هم برای سرگرمی و هم برای چیزیادگرفتن بنا کرد یکی‌یکی‌شان را سیاحت کردن. + +اخترکِ اول مسکن پادشاهی بود که با شنلی از مخمل ارغوانی قاقم بر اورنگی بسیار ساده و در عین حال پرشکوه نشسته بود و همین که چشمش به شهریار کوچولو افتاد داد زد: +-خب، این هم رعیت! +شهریار کوچولو از خودش پرسید: -او که تا حالا هیچ وقت مرا ندیده چه جوری می‌تواند بشناسدم؟ +دیگر اینش را نخوانده‌بود که دنیابرای پادشاهان به نحو عجیبی ساده شده و تمام مردم فقط یک مشت رعیت به حساب می‌آیند. + +پادشاه در سیاره‌اش +پادشاه که می‌دید بالاخره شاهِ کسی شده و از این بابت کبکش خروس می‌خواند گفت: -بیا جلو بهتر ببینیمت. شهریار کوچولو با چشم پیِ جایی گشت که بنشیند اما شنلِ قاقمِ حضرتِ پادشاهی تمام اخترک را دربرگرفته‌بود. ناچار همان طور سر پا ماند و چون سخت خسته بود به دهن‌دره افتاد. +شاه به‌اش گفت: -خمیازه کشیدن در حضرتِ سلطان از نزاکت به دور است. این کار را برایت قدغن می‌کنم. شهریار کوچولو که سخت خجل شده‌بود در آمد که: +-نمی‌توانم جلوِ خودم را بگیرم. راه درازی طی‌کرده‌ام و هیچ هم نخوابیده‌ام... +پادشاه گفت: -خب خب، پس بِت امر می‌کنم خمیازه بکشی. سال‌هاست خمیازه‌کشیدن کسی را ندیده‌ام برایم تازگی دارد. یاالله باز هم خمیازه بکش. این یک امر است. +شهریار کوچولو گفت: -آخر این جوری من دست و پایم را گم می‌کنم... دیگر نمی‌توانم. +شاه گفت: -هوم! هوم! خب، پس من به‌ات امر می‌کنم که گاهی خمیازه بکشی گاهی نه. +تند و نامفهوم حرف می‌زد و انگار خلقش حسابی تنگ بود. + +پادشاه فقط دربند این بود که مطیع فرمانش باشند. در مورد نافرمانی‌ها هم هیچ نرمشی از خودش نشان نمی‌داد. یک پادشاهِ تمام عیار بود گیرم چون زیادی خوب بود اوامری که صادر می‌کرد اوامری بود منطقی. مثلا خیلی راحت در آمد که: «اگر من به یکی از سردارانم امر کنم تبدیل به یکی از این مرغ‌های دریایی بشود و یارو اطاعت نکند تقسیر او نیست که، تقصیر خودم است». +شهریار کوچولو در نهایت ادب پرسید: -اجازه می‌فرمایید بنشینم؟ +پادشاه که در نهایتِ شکوه و جلال چینی از شنل قاقمش را جمع می‌کرد گفت: -به‌ات امر می‌کنیم بنشینی. + +منتها شهریار کوچولو مانده‌بود حیران: آخر آن اخترک کوچک‌تر از آن بود که تصورش را بشود کرد. واقعا این پادشاه به چی سلطنت می‌کرد؟ گفت: -قربان عفو می‌فرمایید که ازتان سوال می‌کنم... +پادشاه با عجله گفت: -به‌ات امر می‌کنیم از ما سوال کنی. +-شما قربان به چی سلطنت می‌فرمایید؟ +پادشاه خیلی ساده گفت: -به همه چی. +-به همه‌چی؟ +پادشاه با حرکتی قاطع به اخترک خودش و اخترک‌های دیگر و باقی ستاره‌ها اشاره کرد. +شهریار کوچولو پرسید: -یعنی به همه‌ی این ها؟ +شاه جواب داد: -به همه‌ی این ها. +آخر او فقط یک پادشاه معمولی نبود که، یک پادشاهِ جهانی بود. +-آن وقت ستاره‌ها هم سربه‌فرمان‌تانند؟ +پادشاه گفت: -البته که هستند. همه‌شان بی‌درنگ هر فرمانی را اطاعت می‌کنند. ما نافرمانی را مطلقا تحمل نمی‌کنیم. + +یک چنین قدرتی شهریار کوچولو را به شدت متعجب کرد. اگر خودش چنین قدرتی می‌داشت بی این که حتا صندلیش را یک ذره تکان بدهد روزی چهل و چهار بار که هیچ روزی هفتاد بار و حتا صدبار و دویست‌بار غروب آفتاب را تماشا می‌کرد! و چون بفهمی نفهمی از یادآوریِ اخترکش که به امان خدا ول‌کرده‌بود غصه‌اش شد جراتی به خودش داد که از پادشاه درخواست محبتی بکند: +-دلم می‌خواست یک غروب آفتاب تماشا کنم... در حقم التفات بفرمایید امر کنید خورشید غروب کند. +-اگر ما به یک سردار امر کنیم مثل شب‌پره از این گل به آن گل بپرد یا قصه‌ی سوزناکی بنویسد یا به شکل مرغ دریایی در آید و او امریه را اجرا نکند کدام یکی‌مان مقصریم، ما یا او؟ +شهریار کوچولو نه گذاشت، نه برداشت، گفت: -شما. +پادشاه گفت: -حرف ندارد. باید از هر کسی چیزی را توقع داشت که ازش ساخته باشد. قدرت باید پیش از هر چیز به عقل متکی باشد. اگر تو به ملتت فرمان بدهی که بروند خودشان را بیندازند تو دریا انقلاب می‌کنند. حق داریم توقع اطاعت داشته باشیم چون اوامرمان عاقلانه است. +شهریار کوچولو که هیچ وقت چیزی را که پرسیده بود فراموش نمی‌کرد گفت: -غروب آفتاب من چی؟ +-تو هم به غروب آفتابت می‌رسی. امریه‌اش را صادر می‌کنیم. منتها با شَمِّ حکمرانی‌مان منتظریم زمینه‌اش فراهم بشود. +شهریار کوچولو پرسید: -کِی فراهم می‌شود؟ +پادشاه بعد از آن که تقویم کَت و کلفتی را نگاه کرد جواب داد: +-هوم! هوم! حدودِ... حدودِ... غروب. حدودِ ساعت هفت و چهل دقیقه... و آن وقت تو با چشم‌های خودت می‌بینی که چه‌طور فرمان ما اجرا می‌شود! + +شهریار کوچولو خمیازه کشید. از این که تماشای آفتاب غروب از کیسه‌اش رفته‌بود تاسف می‌خورد. از آن گذشته دلش هم کمی گرفته‌بود. این بود که به پادشاه گفت: +-من دیگر این‌جا کاری ندارم. می‌خواهم بروم. +شاه که دلش برای داشتن یک رعیت غنج می‌زد گفت: +-نرو! نرو! وزیرت می‌کنیم. +-وزیرِ چی؟ +-وزیرِ دادگستری! +-آخر این جا کسی نیست که محاکمه بشود. +پادشاه گفت: -معلوم نیست. ما که هنوز گشتی دور قلمرومان نزده‌ایم. خیلی پیر شده‌ایم، برای کالسکه جا نداریم. پیاده‌روی هم خسته‌مان می‌کند. +شهریار کوچولو که خم شده‌بود تا نگاهی هم به آن طرف اخترک بیندازد گفت: -بَه! من نگاه کرده‌ام، آن طرف هم دیارالبشری نیست. +پادشاه به‌اش جواب داد: -خب، پس خودت را محاکمه کن. این کار مشکل‌تر هم هست. محاکمه کردن خود از محاکمه‌کردن دیگران خیلی مشکل تر است. اگر توانستی در مورد خودت قضاوت درستی بکنی معلوم می‌شود یک فرزانه‌ی تمام عیاری. +شهریار کوچولو گفت: -من هر جا باشم می‌توانم خودم را محاکمه کنم، چه احتیاجی است این جا بمانم؟ پادشاه گفت: -هوم! هوم! فکر می‌کنیم یک جایی تو اخترک ما یک موش پیر هست. صدایش را شب ها می‌شنویم. می‌توانی او را به محاکمه بکشی و گاه‌گاهی هم به اعدام محکومش کنی. در این صورت زندگی او به عدالت تو بستگی پیدا می‌کند. گیرم تو هر دفعه عفوش می‌کنی تا همیشه زیر چاق داشته باشیش. آخر یکی بیش‌تر نیست که. +شهریار کوچولو جواب داد: -من از حکم اعدام خوشم نمی‌آید. فکر می‌کنم دیگر باید بروم. +پادشاه گفت: -نه! + +اما شهریار کوچولو که آماده‌ی حرکت شده بود و ضمنا هم هیچ دلش نمی‌خواست اسباب ناراحتی سلطان پیر بشود گفت: +-اگر اعلی‌حضرت مایلند اوامرشان دقیقا اجرا بشود می‌توانند فرمان خردمندانه‌ای در مورد بنده صادر بفرمایند. مثلا می‌توانند به بنده امر کنند ظرف یک دقیقه راه بیفتم. تصور می‌کنم زمینه‌اش هم آماده باشد... +چون پادشاه جوابی نداد شهریار کوچولو اول دو دل ماند اما بعد آهی کشید و به راه افتاد. +آن‌وقت پادشاه با شتاب فریاد زد: -سفیر خودمان فرمودیمت! +حالت بسیار شکوهمندی داشت. + +شهریار کوچولو همان طور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند! + +۱۱ +اخترک دوم مسکن آدم خود پسندی بود. +خود پسند چشمش که به شهریار کوچولو افتاد از همان دور داد زد: -به‌به! این هم یک ستایشگر که دارد می‌آید مرا ببیند! + +خودپسند در سیاره‌اش +آخر برای خودپسندها دیگران فقط یک مشت ستایش‌گرند. +شهریار کوچولو گفت: -سلام! چه کلاه عجیب غریبی سرتان گذاشته‌اید! +خود پسند جواب داد: -مال اظهار تشکر است. منظورم موقعی است که هلهله‌ی ستایشگرهایم بلند می‌شود. گیرم متاسفانه تنابنده‌ای گذارش به این طرف‌ها نمی‌افتد. +شهریار کوچولو که چیزی حالیش نشده بود گفت: +-چی؟ +خودپسند گفت: -دست‌هایت را بزن به هم دیگر. +شهریار کوچولو دست زد و خودپسند کلاهش را برداشت و متواضعانه از او تشکر کرد. +شهریار کوچولو با خودش گفت: «دیدنِ این تفریحش خیلی بیش‌تر از دیدنِ پادشاه‌است». و دوباره بنا کرد دست‌زدن و خودپسند با برداشتن کلاه بنا کرد تشکر کردن. + +پس از پنج دقیقه‌ای شهریار کوچولو که از این بازی یک‌نواخت خسته شده بود پرسید: -چه کار باید کرد که کلاه از سرت بیفتد؟ +اما خودپسند حرفش را نشنید. آخر آن‌ها جز ستایش خودشان چیزی را نمی‌شنوند. +از شهریار کوچولو پرسید: -تو راستی راستی به من با چشم ستایش و تحسین نگاه می‌کنی؟ +-ستایش و تحسین یعنی چه؟ +-یعنی قبول این که من خوش‌قیافه‌ترین و خوش‌پوش‌ترین و ثروت‌مندترین و باهوش‌ترین مرد این اخترکم. +-آخر روی این اخترک که فقط خودتی و کلاهت. +-با وجود این ستایشم کن. این لطف را در حق من بکن. +شهریار کوچولو نیم‌چه شانه‌ای بالا انداخت و گفت: -خب، ستایشت کردم. اما آخر واقعا چیِ این برایت جالب است؟ + +شهریار کوچولو به راه افتاد و همان طور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند! + +۱۲ +تو اخترک بعدی می‌خواره‌ای می‌نشست. دیدار کوتاه بود اما شهریار کوچولو را به غم بزرگی فرو برد. + +می‌خواره در سیاره‌اش + +به می‌خواره که صُم‌بُکم پشت یک مشت بطری خالی و یک مشت بطری پر نشسته بود گفت: -چه کار داری می‌کنی؟ +می‌خواره با لحن غم‌زده‌ای جواب داد: -مِی می‌زنم. +شهریار کوچولو پرسید: -مِی می‌زنی که چی؟ +می‌خواره جواب داد: -که فراموش کنم. +شهریار کوچولو که حالا دیگر دلش برای او می‌سوخت پرسید: -چی را فراموش کنی؟ +می‌خواره همان طور که سرش را می‌انداخت پایین گفت: -سر شکستگیم را. +شهریار کوچولو که دلش می‌خواست دردی از او دوا کند پرسید: -سرشکستگی از چی؟ +می‌خواره جواب داد: -سرشکستگیِ می‌خواره بودنم را. +این را گفت و قال را کند و به کلی خاموش شد. و شهریار کوچولو مات و مبهوت راهش را گرفت و رفت و همان جور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی‌راستی چه‌قدر عجیبند! + +۱۳ +اخترک چهارم اخترک مرد تجارت‌پیشه بود. این بابا چنان مشغول و گرفتار بود که با ورود شهریار کوچولو حتا سرش را هم بلند نکرد. + +مردِ تجارت‌پیشه در سیاره‌اش +شهریار کوچولو گفت: -سلام. آتش‌سیگارتان خاموش شده. +-سه و دو می‌کند پنج. پنج و هفت دوازده و سه پانزده. سلام. پانزده و هفت بیست و دو. بیست و دو و شش بیست و هشت. وقت ندارم روشنش کنم. بیست و شش و پنج سی و یک. اوف! پس جمعش می‌کند پانصدویک میلیون و ششصد و بیست و دو هزار هفتصد و سی و یک. +-پانصد میلیون چی؟ +-ها؟ هنوز این جایی تو؟ پانصد و یک میلیون چیز. چه می‌دانم، آن قدر کار سرم ریخته که!... من یک مرد جدی هستم و با حرف‌های هشت‌من‌نه‌شاهی سر و کار ندارم!... دو و پنج هفت... +شهریار کوچولو که وقتی چیزی می‌پرسید دیگر تا جوابش را نمی‌گرفت دست بردار نبود دوباره پرسید: +-پانصد و یک میلیون چی؟ +تاجر پیشه سرش را بلند کرد: +-تو این پنجاه و چهار سالی که ساکن این اخترکم همه‌اش سه بار گرفتار مودماغ شده‌ام. اولیش بیست و دو سال پیش یک سوسک بود که خدا می‌داند از کدام جهنم پیدایش شد. صدای وحشت‌ناکی از خودش در می‌آورد که باعث شد تو یک جمع چهار جا اشتباه کنم. دفعه‌ی دوم یازده سال پیش بود که استخوان درد بی‌چاره‌ام کرد. من ورزش نمی‌کنم. وقت یللی‌تللی هم ندارم. آدمی هستم جدی... این هم بار سومش!... کجا بودم؟ پانصد و یک میلیون و... +-این همه میلیون چی؟ +تاجرپیشه فهمید که نباید امید خلاصی داشته باشد. گفت: -میلیون‌ها از این چیزهای کوچولویی که پاره‌ای وقت‌ها تو هوا دیده می‌شود. +-مگس؟ +-نه بابا. این چیزهای کوچولوی براق. +-زنبور عسل؟ +-نه بابا! همین چیزهای کوچولوی طلایی که وِلِنگارها را به عالم هپروت می‌برد. گیرم من شخصا آدمی هستم جدی که وقتم را صرف خیال‌بافی نمی‌کنم. +-آها، ستاره؟ +-خودش است: ستاره. +-خب پانصد میلیون ستاره به چه دردت می‌خورد؟ +-پانصد و یک میلیون و ششصد و بیست و دو هزار و هفتصد و سی و یکی. من جدیّم و دقیق. +-خب، به چه دردت می‌خورند؟ +-به چه دردم می‌خورند؟ +-ها. +-هیچی تصاحب‌شان می‌کنم. +-ستاره‌ها را؟ +-آره خب. +-آخر من به یک پادشاهی برخوردم که... +-پادشاه‌ها تصاحب نمی‌کنند بل‌که به‌اش «سلطنت» می‌کنند. این دو تا با هم خیلی فرق دارد. +-خب، حالا تو آن‌ها را تصاحب می‌کنی که چی بشود؟ +-که دارا بشوم. +-خب دارا شدن به چه کارت می‌خورد؟ +-به این کار که، اگر کسی ستاره‌ای پیدا کرد من ازش بخرم. +شهریار کوچولو با خودش گفت: «این بابا هم منطقش یک خرده به منطق آن دائم‌الخمره می‌بَرَد.» با وجود این باز ازش پرسید: +-چه جوری می‌شود یک ستاره را صاحب شد؟ +تاجرپیشه بی درنگ با اَخم و تَخم پرسید: -این ستاره‌ها مال کی‌اند؟ +-چه می‌دانم؟ مال هیچ کس. +-پس مال منند، چون من اول به این فکر افتادم. +-همین کافی است؟ +-البته که کافی است. اگر تو یک جواهر پیدا کنی که مال هیچ کس نباشد می‌شود مال تو. اگر جزیره‌ای کشف کنی که مال هیچ کس نباشد می‌شود مال تو. اگر فکری به کله‌ات بزند که تا آن موقع به سر کسی نزده به اسم خودت ثبتش می‌کنی و می‌شود مال تو. من هم ستاره‌ها را برای این صاحب شده‌ام که پیش از من هیچ کس به فکر نیفتاده بود آن‌ها را مالک بشود. +شهریار کوچولو گفت: -این ها همه‌اش درست. منتها چه کارشان می‌کنی؟ +تاجر پیشه گفت: -اداره‌شان می‌کنم، همین جور می‌شمارم‌شان و می‌شمارم‌شان. البته کار مشکلی است ولی خب دیگر، من آدمی هستم بسیار جدی. +شهریار کوچولو که هنوز این حرف تو کَتَش نرفته‌بود گفت: +-اگر من یک شال گردن ابریشمی داشته باشم می‌توانم بپیچم دور گردنم با خودم ببرمش. اگر یک گل داشته باشم می‌توانم بچینم با خودم ببرمش. اما تو که نمی‌توانی ستاره‌ها را بچینی! +-نه. اما می‌توانم بگذارم‌شان تو بانک. +-اینی که گفتی یعنی چه؟ +-یعنی این که تعداد ستاره‌هایم را رو یک تکه کاغذ می‌نویسم می‌گذارم تو کشو درش را قفل می‌کنم. +-همه‌اش همین؟ +-آره همین کافی است. + +شهریار کوچولو فکر کرد «جالب است. یک خرده هم شاعرانه است. اما کاری نیست که آن قدرها جدیش بشود گرفت». آخر تعبیر او از چیزهای جدی با تعبیر آدم‌های بزرگ فرق می‌کرد. +باز گفت: -من یک گل دارم که هر روز آبش می‌دهم. سه تا هم آتش‌فشان دارم که هفته‌ای یک بار پاک و دوده‌گیری‌شان می‌کنم. آخر آتش‌فشان خاموشه را هم پاک می‌کنم. آدم کفِ دستش را که بو نکرده! رو این حساب، هم برای آتش‌فشان‌ها و هم برای گل این که من صاحب‌شان باشم فایده دارد. تو چه فایده‌ای به حال ستاره‌ها داری؟ + +تاجرپیشه دهن باز کرد که جوابی بدهد اما چیزی پیدا نکرد. و شهریار کوچولو راهش را گرفت و رفت و همان جور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند! + +۱۴ +اخترکِ پنجم چیز غریبی بود. از همه‌ی اخترک‌های دیگر کوچک‌تر بود، یعنی فقط به اندازه‌ی یک فانوس پایه‌دار و یک فانوس‌بان جا داشت. + +فانوس‌بان در حالِ روشن کردنِ فانوس در سیاره‌اش +شهریار کوچولو از این راز سر در نیاورد که یک جا میان آسمان خدا تو اخترکی که نه خانه‌ای روش هست نه آدمی، حکمت وجودی یک فانوس و یک فانوس‌بان چه می‌تواند باشد. با وجود این تو دلش گفت: +-خیلی احتمال دارد که این بابا عقلش پاره‌سنگ ببرد. اما به هر حال از پادشاه و خودپسند و تاجرپیشه و مسته کم عقل‌تر نیست. دست کم کاری که می‌کند یک معنایی دارد. فانوسش را که روشن می‌کند عین‌هو مثل این است که یک ستاره‌ی دیگر یا یک گل به دنیا می‌آورد و خاموشش که می‌کند پنداری گل یا ستاره‌ای را می‌خواباند. سرگرمی زیبایی است و چیزی که زیبا باشد بی گفت‌وگو مفید هم هست. + +وقتی رو اخترک پایین آمد با ادب فراوان به فانوس‌بان سلام کرد: +-سلام. واسه چی فانوس را خاموش کردی؟ +-دستور است. صبح به خیر! +-دستور چیه؟ +-این است که فانوسم را خاموش کنم. شب خوش! +و دوباره فانوس را روشن کرد. +-پس چرا روشنش کردی باز؟ +فانوس‌بان جواب داد: -خب دستور است دیگر. +شهریار کوچولو گفت: -اصلا سر در نمیارم. +فانوس‌بان گفت: -چیز سر در آوردنی‌یی توش نیست که. دستور دستور است. روز بخیر! +و باز فانوس را خاموش کرد. +بعد با دستمال شطرنجی قرمزی عرق پیشانیش را خشکاند و گفت: +-کار جان‌فرسایی دارم. پیش‌تر ها معقول بود: صبح خاموشش می‌کردم و شب که می‌شد روشنش می‌کردم. باقی روز را فرصت داشتم که استراحت کنم و باقی شب را هم می‌توانستم بگیرم بخوابم... +-بعدش دستور عوض شد؟ +فانوس‌بان گفت: -دستور عوض نشد و بدبختی من هم از همین جاست: سیاره سال به سال گردشش تندتر و تندتر شده اما دستور همان جور به قوت خودش باقی مانده است. +-خب؟ +-حالا که سیاره دقیقه‌ای یک بار دور خودش می‌گردد دیگر من یک ثانیه هم فرصت استراحت ندارم: دقیقه‌ای یک بار فانوس را روشن می‌کنم یک بار خاموش. +-چه عجیب است! تو اخترک تو شبانه روز همه‌اش یک دقیقه طول می‌کشد! +فانوس‌بان گفت: -هیچ هم عجیب نیست. الان یک ماه تمام است که ما داریم با هم اختلاط می‌کنیم. +-یک ماه؟ +-آره. سی دقیقه. سی روز! شب خوش! +و دوباره فانوس را روشن کرد. + +شهریار کوچولو به فانوس‌بان نگاه کرد و حس کرد این مرد را که تا این حد به دستور وفادار است دوست می‌دارد. یادِ آفتاب‌غروب‌هایی افتاد که آن وقت‌ها خودش با جابه‌جا کردن صندلیش دنبال می‌کرد. برای این که دستی زیر بال دوستش کرده باشد گفت: +-می‌دانی؟ یک راهی بلدم که می‌توانی هر وقت دلت بخواهد استراحت کنی. +فانوس‌بان گفت: -آرزوش را دارم. +آخر آدم می‌تواند هم به دستور وفادار بماند هم تنبلی کند. +شهریار کوچولو دنبال حرفش را گرفت و گفت: +-تو، اخترکت آن‌قدر کوچولوست که با سه تا شلنگ برداشتن می‌توانی یک بار دور بزنیش. اگر آن اندازه که لازم است یواش راه بروی می‌توانی کاری کنی که مدام تو آفتاب بمانی. پس هر وقت خواستی استراحت کنی شروع می‌کنی به راه‌رفتن... به این ترتیب روز هرقدر که بخواهی برایت کِش می‌آید. +فانوس‌بان گفت: -این کار گرهی از بدبختی من وا نمی‌کند. تنها چیزی که تو زندگی آرزویش را دارم یک چرت خواب است. +شهریار کوچولو گفت: -این یکی را دیگر باید بگذاری در کوزه. +فانوس‌بان گفت: -آره. باید بگذارمش در کوزه... صبح بخیر! +و فانوس را خاموش کرد. + +شهریار کوچولو میان راه با خودش گفت: گرچه آن‌های دیگر، یعنی خودپسنده و تاجره اگر این را می‌دیدند دستش می‌انداختند و تحقیرش می‌کردند، هر چه نباشد کار این یکی به نظر من کم‌تر از کار آن‌ها بی‌معنی و مضحک است. شاید به خاطر این که دست کم این یکی به چیزی جز خودش مشغول است. + +از حسرت آهی کشید و همان طور با خودش گفت: +-این تنها کسی بود که من می‌توانستم باش دوست بشوم. گیرم اخترکش راستی راستی خیلی کوچولو است و دو نفر روش جا نمی‌گیرند. + +چیزی که جرات اعترافش را نداشت حسرت او بود به این اخترک کوچولویی که، بخصوص، به هزار و چهارصد و چهل بار غروب آفتاب در هر بیست و چهار ساعت برکت پیدا کرده بود. + +۱۵ +اخترک ششم اخترکی بود ده بار فراخ‌تر، و آقاپیره‌ای توش بود که کتاب‌های کَت‌وکلفت می‌نوشت. + +جغرافی‌دان در سیاره‌اش +همین که چشمش به شهریار کوچولو افتاد با خودش گفت: +-خب، این هم یک کاشف! +شهریار کوچولو لب میز نشست و نفس نفس زد. نه این که راه زیادی طی کرده بود؟ +آقا پیره به‌اش گفت: -از کجا می‌آیی؟ +شهریار کوچولو گفت: -این کتاب به این کلفتی چی است؟ شما این‌جا چه‌کار می‌کنید؟ +آقا پیره گفت: -من جغرافی‌دانم. +-جغرافی‌دان چه باشد؟ +-جغرافی‌دان به دانشمندی می‌گویند که جای دریاها و رودخانه‌ها و شهرها و کوه‌ها و بیابان‌ها را می‌داند. +شهریار کوچولو گفت: -محشر است. یک کار درست و حسابی است. +و به اخترک جغرافی‌دان، این سو و آن‌سو نگاهی انداخت. تا آن وقت اخترکی به این عظمت ندیده‌بود. +-اخترک‌تان خیلی قشنگ است. اقیانوس هم دارد؟ +جغرافی‌دان گفت: -از کجا بدانم؟ +شهریار کوچولو گفت: -عجب! (بد جوری جا خورده بود) کوه چه‌طور؟ +جغرافی‌دان گفت: -از کجا بدانم؟ +-شهر، رودخانه، بیابان؟ +جغرافی‌دان گفت: از این‌ها هم خبری ندارم. +-آخر شما جغرافی‌دانید؟ +جغرافی‌دان گفت: -درست است ولی کاشف که نیستم. من حتا یک نفر کاشف هم ندارم. کار جغرافی‌دان نیست که دوره‌بیفتد برود شهرها و رودخانه‌ها و کوه‌ها و دریاها و اقیانوس‌ها و بیابان‌ها را بشمرد. مقام جغرافی‌دان برتر از آن است که دوره بیفتد و ول‌بگردد. اصلا از اتاق کارش پا بیرون نمی‌گذارد بلکه کاشف‌ها را آن تو می‌پذیرد ازشان سوالات می‌کند و از خاطرات‌شان یادداشت بر می‌دارد و اگر خاطرات یکی از آن‌ها به نظرش جالب آمد دستور می‌دهد روی خُلقیات آن کاشف تحقیقاتی صورت بگیرد. +-برای چه؟ +-برای این که اگر کاشفی گنده‌گو باشد کار کتاب‌های جغرافیا را به فاجعه می‌کشاند. هکذا کاشفی که اهل پیاله باشد. +-آن دیگر چرا؟ +b-چون آدم‌های دائم‌الخمر همه چیز را دوتا می‌بینند. آن وقت جغرافی‌دان برمی‌دارد جایی که یک کوه +بیشتر نیست می‌نویسد دو کوه. +شهریار کوچولو گفت: -پس من یک بابایی را می‌شناسم که کاشف هجوی از آب در می‌آید. +-بعید نیست. بنابراین، بعد از آن که کاملا ثابت شد پالان کاشف کج نیست تحقیقاتی هم روی کشفی که کرده انجام می‌گیرد. +-یعنی می‌روند می‌بینند؟ +-نه، این کار گرفتاریش زیاد است. از خود کاشف می‌خواهند دلیل بیاورد. مثلا اگر پای کشف یک کوه بزرگ در میان بود ازش می‌خواهند سنگ‌های گنده‌ای از آن کوه رو کند. +جغرافی‌دان ناگهان به هیجان در آمد و گفت: -راستی تو داری از راه دوری می‌آیی! تو کاشفی! باید چند و چون اخترکت را برای من بگویی. +و با این حرف دفتر و دستکش را باز کرد و مدادش را تراشید. معمولا خاطرات کاشف‌ها را اول بامداد یادداشت می‌کنند و دست نگه می‌دارند تا دلیل اقامه کند، آن وقت با جوهر می‌نویسند. +گفت: -خب؟ +شهریار کوچولو گفت: -اخترک من چیز چندان جالبی ندارد. آخر خیلی کوچک است. سه تا آتش‌فشان دارم که دوتاش فعال است یکیش خاموش. اما، خب دیگر، آدم کف دستش را که بو نکرده. +جغرافی‌دان هم گفت: -آدم چه می‌داند چه پیش می‌آید. +-یک گل هم دارم. +-نه، نه، ما دیگر گل ها را یادداشت نمی‌کنیم. +-چرا؟ گل که زیباتر است. +-برای این که گل‌ها فانی‌اند. +-فانی یعنی چی؟ +جغرافی‌دان گفت: -کتاب‌های جغرافیا از کتاب‌های دیگر گران‌بهاترست و هیچ وقت هم از اعتبار نمی‌افتد. بسیار به ندرت ممکن است یک کوه جا عوض کند. بسیار به ندرت ممکن است آب یک اقیانوس خالی شود. ما فقط چیزهای پایدار را می‌نویسیم. +شهریار کوچولو تو حرف او دوید و گفت: -اما آتش‌فشان‌های خاموش می‌توانند از نو بیدار بشوند. فانی را نگفتید یعنی چه؟ +جغرافی‌دان گفت: -آتش‌فشان چه روشن باشد چه خاموش برای ما فرقی نمی‌کند. آن‌چه به حساب می‌آید خود کوه است که تغییر پیدا نمی‌کند. +شهریار کوچولو که تو تمام عمرش وقتی چیزی از کسی می‌پرسید دیگر دست بردار نبود دوباره سوال کرد: -فانی یعنی چه؟ +-یعنی چیزی که در آینده تهدید به نابودی شود. +-گل من هم در آینده نابود می‌شود؟ +-البته که می‌شود. +شهریار کوچولو در دل گفت: «گل من فانی است و جلو دنیا برای دفاع از خودش جز چهارتا خار هیچی ندارد، و آن وقت مرا بگو که او را توی اخترکم تک و تنها رها کرده‌ام!» +این اولین باری بود که دچار پریشانی و اندوه می‌شد اما توانست به خودش مسلط بشود. پرسید: -شما به من دیدن کجا را توصیه می‌کنید؟ +جغرافی‌دان به‌اش جواب داد: -سیاره‌ی زمین. شهرت خوبی دارد... + +و شهریار کوچولو هم چنان که به گلش فکر می‌کرد به راه افتاد. + +۱۶ +لاجرم، زمین، سیاره‌ی هفتم شد. + +زمین، فلان و بهمان سیاره نیست. رو پهنه‌ی زمین یک‌صد و یازده پادشاه (البته بامحاسبه‌ی پادشاهان سیاه‌پوست)، هفت هزار جغرافی‌دان، نه‌صد هزار تاجرپیشه، پانزده کرور می‌خواره و شش‌صد و بیست و دو کرور خودپسند و به عبارت دیگر حدود دو میلیارد آدم بزرگ زندگی می‌کند. برای آن‌که از حجم زمین مقیاسی به دست‌تان بدهم بگذارید به‌تان بگویم که پیش از اختراع برق مجبور بودند در مجموع شش قاره‌ی زمین وسایل زندگیِ لشکری جانانه شامل یکصد و شصت و دو هزار و پانصد و یازده نفر فانوس‌بان را تامین کنند. + +روشن شدن فانوس‌ها از دور خیلی باشکوه بود. حرکات این لشکر مثل حرکات یک باله‌ی تو اپرا مرتب و منظم بود. اول از همه نوبت فانوس‌بان‌های زلاندنو و استرالیا بود. این‌ها که فانوس‌هاشان را روشن می‌کردند، می‌رفتند می‌گرفتند می‌خوابیدند آن وقت نوبت فانوس‌بان‌های چین و سیبری می‌رسید که به رقص درآیند. بعد، این‌ها با تردستی تمام به پشت صحنه می‌خزیدند و جا را برای فانوس‌بان‌های ترکیه و هفت پَرکَنِه‌ی هند خالی می کردند. بعد نوبت به فانوس‌بان‌های آمریکای‌جنوبی می‌شد. و آخر سر هم نوبت فانوس‌بان‌های افریقا و اروپا می‌رسد و بعد نوبت فانوس‌بان‌های آمریکای شمالی بود. و هیچ وقتِ خدا هم هیچ‌کدام این‌ها در ترتیب ورودشان به صحنه دچار اشتباه نمی‌شدند. چه شکوهی داشت! میان این جمع عظیم فقط نگه‌بانِ تنها فانوسِ قطب شمال و همکارش نگه‌بانِ تنها فانوسِ قطب جنوب بودند که عمری به بطالت و بی‌هودگی می‌گذراندند: آخر آن‌ها سالی به سالی همه‌اش دو بار کار می‌کردند. + +۱۷ +آدمی که اهل اظهار لحیه باشد بفهمی نفهمی می‌افتد به چاخان کردن. من هم تو تعریف قضیه‌ی فانوس‌بان‌ها برای شما آن‌قدرهاروراست نبودم. می‌ترسم به آن‌هایی که زمین ما را نمی‌سناسند تصور نادرستی داده باشم. انسان‌ها رو پهنه‌ی زمین جای خیلی کمی را اشغال می‌کنند. اگر همه‌ی دو میلیارد نفری که رو کره‌ی زمین زندگی می‌کنند بلند بشوند و مثل موقعی که به تظاهرات می‌روند یک خورده جمع و جور بایستند راحت و بی‌درپسر تو میدانی به مساحت بیست میل در بیست میل جا می‌گیرند. همه‌ی جامعه‌ی بشری را می‌شود یک‌جا روی کوچک‌ترین جزیره‌ی اقیانوس آرام کُپه کرد. + +البته گفت‌وگو ندارد که آدم بزرگ‌ها حرف‌تان را باور نمی‌کنند. آخر تصور آن‌ها این است که کلی جا اشغال کرده‌اند، نه این‌که مثل بائوباب‌ها خودشان را خیلی مهم می‌بینند؟ بنابراین به‌شان پیش‌نهاد می‌کنید که بنشینند حساب کنند. آن‌ها هم که عاشق اعداد و ارقامند، پس این پیش‌نهاد حسابی کیفورشان می‌کند. اما شما را به خدا بی‌خودی وقت خودتان را سر این جریمه‌ی مدرسه به هدر ندهید. این کار دو قاز هم نمی‌ارزد. به من که اطمینان دارید. شهریار کوچولو پاش که به زمین رسید از این که دیارالبشری دیده نمی‌شد سخت هاج و واج ماند. + +شهریار کوچولو وسطِ کویر +تازه داشت از این فکر که شاید سیاره را عوضی گرفته ترسش بر می‌داشت که چنبره‌ی مهتابی رنگی رو ماسه‌ها جابه‌جا شد.شهریار کوچولو و مار +شهریار کوچولو همین‌جوری سلام کرد. +مار گفت: -سلام. +شهریار کوچولو پرسید: -رو چه سیاره‌ای پایین آمده‌ام؟ +مار جواب داد: -رو زمین تو قاره‌ی آفریقا. +-عجب! پس رو زمین انسان به هم نمی‌رسد؟ +مار گفت: -این‌جا کویر است. تو کویر کسی زندگی نمی‌کند. زمین بسیار وسیع است. +شهریار کوچولو رو سنگی نشست و به آسمان نگاه کرد. گفت: -به خودم می‌گویم ستاره‌ها واسه این روشنند که هرکسی بتواند یک روز مال خودش را پیدا کند!... اخترک مرا نگاه! درست بالا سرمان است... اما چه‌قدر دور است! +مار گفت: -قشنگ است. این‌جا آمده‌ای چه کار؟ +شهریار کوچولو گفت: -با یک گل بگومگویم شده. +مار گفت: -عجب! +و هر دوشان خاموش ماندند. +دست آخر شهریار کوچولو درآمد که: -آدم‌ها کجاند؟ آدم تو کویر یک خرده احساس تنهایی می‌کند. +مار گفت: -پیش آدم‌ها هم احساس تنهایی می‌کنی. +شهریار کوچولو مدت درازی تو نخ او رفت و آخر سر به‌اش گفت: -تو چه جانور بامزه‌ای هستی! مثل یک انگشت، باریکی. +مار گفت: -عوضش از انگشت هر پادشاهی مقتدرترم. +شهریار کوچولو لب‌خندی زد و گفت: -نه چندان... پا هم که نداری. حتا راه هم نمی‌تونی بری... +-من می‌تونم تو را به چنان جای دوری ببرم که با هیچ کشتی‌یی هم نتونی بری. +مار این را گفت و دور قوزک پای شهریار کوچولو پیچید. عین یک خلخال طلا. و باز درآمد که: -هر کسی را لمس کنم به خاکی که ازش درآمده بر می‌گردانم اما تو پاکی و از یک سیّاره‌ی دیگر آمده‌ای... +شهریار کوچولو جوابی بش نداد. +-تو رو این زمین خارایی آن‌قدر ضعیفی که به حالت رحمم می‌آید. روزی‌روزگاری اگر دلت خیلی هوای اخترکت را کرد بیا من کمکت کنم... من می‌توانم... +شهریار کوچولو گفت: -آره تا تهش را خواندم. اما راستی تو چرا همه‌ی حرف‌هایت را به صورت معما درمی‌آری؟ + +مار گفت: -حلّال همه‌ی معماهام من. +و هر دوشان خاموش شدند. + +۱۸ +شهریار کوچولو کویر را از پاشنه درکرد و جز یک گل به هیچی برنخورد: یک گل سه گل‌برگه. یک گلِ ناچیز. + +یک گُل وسطِ کویر + +شهریار کوچولو گفت: -سلام. +گل گفت: -سلام. +شهریار کوچولو با ادب پرسید: -آدم‌ها کجاند؟ +گل روزی روزگاری عبور کاروانی را دیده‌بود. این بود که گفت: -آدم‌ها؟ گمان کنم ازشان شش هفت تایی باشد. سال‌ها پیش دیدم‌شان. منتها خدا می‌داند کجا می‌شود پیداشان کرد. باد این‌ور و آن‌ور می‌بَرَدشان؛ نه این که ریشه ندارند؟ بی‌ریشگی هم حسابی اسباب دردسرشان شده. +شهریار کوچولو گفت: -خداحافظ. +گل گفت: -خداحافظ. + +۱۹ +از کوه بلندی بالا رفت. + +شهریار کوچولو بر قله‌ی کوهِ بلند +تنها کوه‌هایی که به عمرش دیده بود سه تا آتش‌فشان‌های اخترک خودش بود که تا سر زانویش می‌رسید و از آن یکی که خاموش بود جای چارپایه استفاده می‌کرد. این بود که با خودش گفت: «از سر یک کوه به این بلندی می‌توانم به یک نظر همه‌ی سیاره و همه‌ی آدم‌ها را ببینم...» اما جز نوکِ تیزِ صخره‌های نوک‌تیز چیزی ندید. +همین جوری گفت: -سلام. +طنین به‌اش جواب داد: -سلام... سلام... سلام... +شهریار کوچولو گفت: -کی هستید شما؟ +طنین به‌اش جواب داد: -کی هستید شما... کی هستید شما... کی هستید شما... +گفت: -با من دوست بشوید. من تک و تنهام. +طنین به‌اش جواب داد: -من تک و تنهام... من تک و تنهام... من تک و تنهام... +آن‌وقت با خودش فکر کرد: «چه سیاره‌ی عجیبی! خشک‌ِخشک و تیزِتیز و شورِشور. این آدم‌هاش که یک ذره قوه‌ی تخیل ندارند و هر چه را بشنوند عینا تکرار می‌کنند... تو اخترک خودم گلی داشتم که همیشه اول او حرف می‌زد...» + +۲۰ +اما سرانجام، بعد از مدت‌ها راه رفتن از میان ریگ‌ها و صخره‌ها و برف‌ها به جاده‌ای برخورد. و هر جاده‌ای یک‌راست می‌رود سراغ آدم‌ها. +گفت: -سلام. +و مخاطبش گلستان پرگلی بود. + +شهریار کوچولو در گلستانِ پرگل + +گل‌ها گفتند: -سلام. +شهریار کوچولو رفت تو بحرشان. همه‌شان عین گل خودش بودند. حیرت‌زده ازشان پرسید: -شماها کی هستید؟ +گفتند: -ما گل سرخیم. + +آهی کشید و سخت احساس شوربختی کرد. گلش به او گفته بود که از نوع او تو تمام عالم فقط همان یکی هست و حالا پنج‌هزارتا گل، همه مثل هم، فقط تو یک گلستان! فکر کرد: «اگر گل من این را می‌دید بدجور از رو می‌رفت. پشت سر هم بنا می‌کرد سرفه‌کردن و، برای این‌که از هُوشدن نجات پیدا کند خودش را به مردن می‌زد و من هم مجبور می‌شدم وانمود کنم به پرستاریش، وگرنه برای سرشکسته کردنِ من هم شده بود راستی راستی می‌مرد...» و باز تو دلش گفت: «مرا باش که فقط بایک دانه گل خودم را دولت‌مندِ عالم خیال می‌کردم در صورتی‌که آن‌چه دارم فقط یک گل معمولی است. با آن گل و آن سه تا آتش‌فشان که تا سرِ زانومَند و شاید هم یکی‌شان تا ابد خاموش بماند شهریارِ چندان پُرشوکتی به حساب نمی‌آیم.» + +شهریار کوچولو در حالِ احساسِ شوربختی +رو سبزه‌ها دراز شد و حالا گریه نکن کی گریه‌کن. + +۲۱ +آن وقت بود که سر و کله‌ی روباه پیدا شد. + +شهریار کوچولو و روباه + +روباه گفت: -سلام. +شهریار کوچولو برگشت اما کسی را ندید. با وجود این با ادب تمام گفت: -سلام. +صداگفت: -من این‌جام، زیر درخت سیب... +شهریار کوچولو گفت: -کی هستی تو؟ عجب خوشگلی! +روباه گفت: -یک روباهم من. +شهریار کوچولو گفت: -بیا با من بازی کن. نمی‌دانی چه قدر دلم گرفته... +روباه گفت: -نمی‌توانم بات بازی کنم. هنوز اهلیم نکرده‌اند آخر. +شهریار کوچولو آهی کشید و گفت: -معذرت می‌خواهم. +اما فکری کرد و پرسید: -اهلی کردن یعنی چه؟ +روباه گفت: -تو اهل این‌جا نیستی. پی چی می‌گردی؟ +شهریار کوچولو گفت: -پی آدم‌ها می‌گردم. نگفتی اهلی کردن یعنی چه؟ +روباه گفت: -آدم‌ها تفنگ دارند و شکار می‌کنند. اینش اسباب دلخوری است! اما مرغ و ماکیان هم پرورش می‌دهند و خیرشان فقط همین است. تو پی مرغ می‌کردی؟ +شهریار کوچولو گفت: -نَه، پیِ دوست می‌گردم. اهلی کردن یعنی چی؟ +روباه گفت: -یک چیزی است که پاک فراموش شده. معنیش ایجاد علاقه کردن است. +-ایجاد علاقه کردن؟ +روباه گفت: -معلوم است. تو الان واسه من یک پسر بچه‌ای مثل صد هزار پسر بچه‌ی دیگر. نه من هیچ احتیاجی به تو دارم نه تو هیچ احتیاجی به من. من هم واسه تو یک روباهم مثل صد هزار روباه دیگر. اما اگر منو اهلی کردی هر دوتامان به هم احتیاج پیدا می‌کنیم. تو واسه من میان همه‌ی عالم موجود یگانه‌ای می‌شوی من واسه تو. +شهریار کوچولو گفت: -کم‌کم دارد دستگیرم می‌شود. یک گلی هست که گمانم مرا اهلی کرده باشد. +روباه گفت: -بعید نیست. رو این کره‌ی زمین هزار جور چیز می‌شود دید. +شهریار کوچولو گفت: -اوه نه! آن رو کره‌ی زمین نیست. +روباه که انگار حسابی حیرت کرده بود گفت: -رو یک سیاره‌ی دیگر است؟ +-آره. +شکارچی-تو آن سیاره شکارچی هم هست؟ +-نه. +-محشر است! مرغ و ماکیان چه‌طور؟ +-نه. +روباه آه‌کشان گفت: -همیشه‌ی خدا یک پای بساط لنگ است! +اما پی حرفش را گرفت و گفت: -زندگی یک‌نواختی دارم. من مرغ‌ها را شکار می‌کنم آدم‌ها مرا. همه‌ی مرغ‌ها عین همند همه‌ی آدم‌ها هم عین همند. این وضع یک خرده خلقم را تنگ می‌کند. اما اگر تو منو اهلی کنی انگار که زندگیم را چراغان کرده باشی. آن وقت صدای پایی را می‌شناسم که باهر صدای پای دیگر فرق می‌کند: صدای پای دیگران مرا وادار می‌کند تو هفت تا سوراخ قایم بشوم اما صدای پای تو مثل نغمه‌ای مرا از سوراخم می‌کشد بیرون. تازه، نگاه کن آن‌جا آن گندم‌زار را می‌بینی؟ برای من که نان بخور نیستم گندم چیز بی‌فایده‌ای است. پس گندم‌زار هم مرا به یاد چیزی نمی‌اندازد. اسباب تاسف است. اما تو موهات رنگ طلا است. پس وقتی اهلیم کردی محشر می‌شود! گندم که طلایی رنگ است مرا به یاد تو می‌اندازد و صدای باد را هم که تو گندم‌زار می‌پیچد دوست خواهم داشت... +خاموش شد و مدت درازی شهریار کوچولو را نگاه کرد. آن وقت گفت: -اگر دلت می‌خواهد منو اهلی کن! +شهریار کوچولو جواب داد: -دلم که خیلی می‌خواهد، اما وقتِ چندانی ندارم. باید بروم دوستانی پیدا کنم و از کلی چیزها سر در آرم. +روباه گفت: -آدم فقط از چیزهایی که اهلی کند می‌تواند سر در آرد. انسان‌ها دیگر برای سر در آوردن از چیزها وقت ندارند. همه چیز را همین جور حاضر آماده از دکان‌ها می‌خرند. اما چون دکانی نیست که دوست معامله کند آدم‌ها مانده‌اند بی‌دوست... تو اگر دوست می‌خواهی خب منو اهلی کن! +شهریار کوچولو پرسید: -راهش چیست؟ +روباه جواب داد: -باید خیلی خیلی حوصله کنی. اولش یک خرده دورتر از من می‌گیری این جوری میان علف‌ها می‌نشینی. من زیر چشمی نگاهت می‌کنم و تو لام‌تاکام هیچی نمی‌گویی، چون تقصیر همه‌ی سؤِتفاهم‌ها زیر سر زبان است. عوضش می‌توانی هر روز یک خرده نزدیک‌تر بنشینی. + +روباه در حالِ انتظارفردای آن روز دوباره شهریار کوچولو آمد. +روباه گفت: -کاش سر همان ساعت دیروز آمده بودی. اگر مثلا سر ساعت چهار بعد از ظهر بیایی من از ساعت سه تو دلم قند آب می‌شود و هر چه ساعت جلوتر برود بیش‌تر احساس شادی و خوشبختی می‌کنم. ساعت چهار که شد دلم بنا می‌کند شور زدن و نگران شدن. آن وقت است که قدرِ خوشبختی را می‌فهمم! اما اگر تو وقت و بی وقت بیایی من از کجا بدانم چه ساعتی باید دلم را برای دیدارت آماده کنم؟... هر چیزی برای خودش قاعده‌ای دارد. +شهریار کوچولو گفت: -قاعده یعنی چه؟ +روباه گفت: -این هم از آن چیزهایی است که پاک از خاطرها رفته. این همان چیزی است که باعث می‌شود فلان روز با باقی روزها و فلان ساعت با باقی ساعت‌ها فرق کند. مثلا شکارچی‌های ما میان خودشان رسمی دارند و آن این است که پنج‌شنبه‌ها را با دخترهای ده می‌روند رقص. پس پنج‌شنبه‌ها بَرّه‌کشانِ من است: برای خودم گردش‌کنان می‌روم تا دم مُوِستان. حالا اگر شکارچی‌ها وقت و بی وقت می‌رقصیدند همه‌ی روزها شبیه هم می‌شد و منِ بیچاره دیگر فرصت و فراغتی نداشتم. + +به این ترتیب شهریار کوچولو روباه را اهلی کرد. +لحظه‌ی جدایی که نزدیک شد روباه گفت: -آخ! نمی‌توانم جلو اشکم را بگیرم. +شهریار کوچولو گفت: -تقصیر خودت است. من که بدت را نمی‌خواستم، خودت خواستی اهلیت کنم. +روباه گفت: -همین طور است. +شهریار کوچولو گفت: -آخر اشکت دارد سرازیر می‌شود! +روباه گفت: -همین طور است. +-پس این ماجرا فایده‌ای به حال تو نداشته. +روباه گفت: -چرا، واسه خاطرِ رنگ گندم. +بعد گفت: -برو یک بار دیگر گل‌ها را ببین تا بفهمی که گلِ خودت تو عالم تک است. برگشتنا با هم وداع می‌کنیم و من به عنوان هدیه رازی را به‌ات می‌گویم. +شهریار کوچولو بار دیگر به تماشای گل‌ها رفت و به آن‌ها گفت: -شما سرِ سوزنی به گل من نمی‌مانید و هنوز هیچی نیستید. نه کسی شما را اهلی کرده نه شما کسی را. درست همان جوری هستید که روباه من بود: روباهی بود مثل صدهزار روباه دیگر. او را دوست خودم کردم و حالا تو همه‌ی عالم تک است. +گل‌ها حسابی از رو رفتند. +شهریار کوچولو دوباره درآمد که: -خوشگلید اما خالی هستید. برای‌تان نمی‌شود مُرد. گفت‌وگو ندارد که گلِ مرا هم فلان ره‌گذر می‌بیند مثل شما. اما او به تنهایی از همه‌ی شما سر است چون فقط اوست که آبش داده‌ام، چون فقط اوست که زیر حبابش گذاشته‌ام، چون فقط اوست که با تجیر برایش حفاظ درست کرده‌ام، چون فقط اوست که حشراتش را کشته‌ام (جز دو سه‌تایی که می‌بایست شب‌پره بشوند)، چون فقط اوست که پای گِلِه‌گزاری‌ها یا خودنمایی‌ها و حتا گاهی پای بُغ کردن و هیچی نگفتن‌هاش نشسته‌ام، چون او گلِ من است. +و برگشت پیش روباه. +گفت: -خدانگه‌دار! +روباه گفت: -خدانگه‌دار!... و اما رازی که گفتم خیلی ساده است: +جز با دل هیچی را چنان که باید نمی‌شود دید. نهاد و گوهر را چشمِ سَر نمی‌بیند. +شهریار کوچولو برای آن که یادش بماند تکرار کرد: -نهاد و گوهر را چشمِ سَر نمی‌بیند. +-ارزش گل تو به قدرِ عمری است که به پاش صرف کرده‌ای. +شهریار کوچولو برای آن که یادش بماند تکرار کرد: -به قدر عمری است که به پاش صرف کرده‌ام. +روباه گفت: -انسان‌ها این حقیقت را فراموش کرده‌اند اما تو نباید فراموشش کنی. تو تا زنده‌ای نسبت به چیزی که اهلی کرده‌ای مسئولی. تو مسئول گُلِتی... + +شهریار کوچولو برای آن که یادش بماند تکرار کرد: -من مسئول گُلمَم. + +۲۲ +شهریار کوچولو گفت: -سلام. +سوزن‌بان گفت: -سلام. +شهریار کوچولو گفت: -تو چه کار می‌کنی این‌جا؟ +سوزن‌بان گفت: -مسافرها را به دسته‌های هزارتایی تقسیم می‌کنم و قطارهایی را که می‌بَرَدشان گاهی به سمت راست می‌فرستم گاهی به سمت چپ. و همان دم سریع‌السیری با چراغ‌های روشن و غرّشی رعدوار اتاقک سوزن‌بانی را به لرزه انداخت. +-عجب عجله‌ای دارند! پیِ چی می‌روند؟ +سوزن‌بان گفت: -از خودِ آتش‌کارِ لکوموتیف هم بپرسی نمی‌داند! +سریع‌السیر دیگری با چراغ‌های روشن غرّید و در جهت مخالف گذشت . +شهریار کوچولو پرسید: -برگشتند که؟ +سوزن‌بان گفت: -این‌ها اولی‌ها نیستند. آن‌ها رفتند این‌ها برمی‌گردند. +-جایی را که بودند خوش نداشتند؟ +سوزن‌بان گفت: -آدمی‌زاد هیچ وقت جایی را که هست خوش ندارد. +و رعدِ سریع‌السیرِ نورانیِ ثالثی غرّید. +شهریار کوچولو پرسید: -این‌ها دارند مسافرهای اولی را دنبال می‌کنند؟ +سوزن‌بان گفت: -این‌ها هیچ چیزی را دنبال نمی‌کنند. آن تو یا خواب‌شان می‌بَرَد یا دهن‌دره می‌کنند. فقط بچه‌هاند که دماغ‌شان را فشار می‌دهند به شیشه‌ها. +شهریار کوچولو گفت: -فقط بچه‌هاند که می‌دانند پیِ چی می‌گردند. بچه‌هاند که کُلّی وقت صرف یک عروسک پارچه‌ای می‌کنند و عروسک برای‌شان آن قدر اهمیت به هم می‌رساند که اگر یکی آن را ازشان کِش برود می‌زنند زیر گریه... +سوزن‌بان گفت: -بخت، یارِ بچه‌هاست. + +۲۳ +شهریار کوچولو گفت: -سلام! +پیله‌ور گفت: -سلام. +این بابا فروشنده‌ی حَب‌های ضد تشنگی بود. خریدار هفته‌ای یک حب می‌انداخت بالا و دیگر تشنگی بی تشنگی. +شهریار کوچولو پرسید: -این‌ها را می‌فروشی که چی؟ +پیله‌ور گفت: -باعث صرفه‌جویی کُلّی وقت است. کارشناس‌های خبره نشسته‌اند دقیقا حساب کرده‌اند که با خوردن این حب‌ها هفته‌ای پنجاه و سه دقیقه وقت صرفه‌جویی می‌شود. +-خب، آن وقت آن پنجاه و سه دقیقه را چه کار می‌کنند؟ +ـ هر چی دل‌شان خواست... + +چشمه +شهریار کوچولو تو دلش گفت: «من اگر پنجاه و سه دقیقه وقتِ زیادی داشته باشم خوش‌خوشک به طرفِ یک چشمه می‌روم...» + +۲۴ +هشتمین روزِ خرابی هواپیمام تو کویر بود که، در حال نوشیدنِ آخرین چک‌ّه‌ی ذخیره‌ی آبم به قضیه‌ی پیله‌وره گوش داده بودم. به شهریار کوچولو گفتم: +-خاطرات تو راستی راستی زیباند اما من هنوز از پسِ تعمیر هواپیما برنیامده‌ام، یک چکه آب هم ندارم. و راستی که من هم اگر می‌توانستم خوش‌خوشک به طرف چشمه‌ای بروم سعادتی احساس می‌کردم که نگو! +درآمد که: -دوستم روباه... +گفتم: -آقا کوچولو، دورِ روباه را قلم بگیر! +-واسه چی؟ +-واسه این که تشنگی کارمان را می سازد. واسه این! +از استدلال من چیزی حالیش نشد و در جوابم گفت: +-حتا اگر آدم دَمِ مرگ باشد هم داشتن یک دوست عالی است. من که از داشتن یک دوستِ روباه خیلی خوشحالم... +به خودم گفتم نمی‌تواند میزان خطر را تخمین بزند: آخر او هیچ وقت نه تشنه‌اش می‌شود نه گشنه‌اش. یه ذره آفتاب بسش است... +اما او به من نگاه کرد و در جواب فکرم گفت: -من هم تشنه‌م است... بگردیم یک چاه پیدا کنیم... +از سرِ خستگی حرکتی کردم: -این جوری تو کویرِ برهوت رو هوا پیِ چاه گشتن احمقانه است. +و با وجود این به راه افتادیم. + +پس از ساعت‌ها که در سکوت راه رفتیم شب شد و ستاره‌ها یکی یکی درآمدند. من که از زور تشنگی تب کرده بودم انگار آن‌ها را خواب می‌دیدم. حرف‌های شهریار کوچولو تو ذهنم می‌رقصید. +ازش پرسیدم: -پس تو هم تشنه‌ات هست، ها؟ +اما او به سوآلِ من جواب نداد فقط در نهایت سادگی گفت: -آب ممکن است برای دلِ من هم خوب باشد... +از حرفش چیزی دستگیرم نشد اما ساکت ماندم. می‌دانستم از او نباید حرف کشید. +خسته شده بود. گرفت نشست. من هم کنارش نشستم. پس از مدتی سکوت گفت: +-قشنگیِ ستاره‌ها واسه خاطرِ گلی است که ما نمی‌بینیمش... +گفتم: -همین طور است +و بدون حرف در مهتاب غرق تماشای چین و شکن‌های شن شدم. +باز گفت: -کویر زیباست. + +و حق با او بود. من همیشه عاشق کویر بوده‌ام. آدم بالای توده‌ای شن لغزان می‌نشیند، هیچی نمی‌بیند و هیچی نمی‌شنود اما با وجود این چیزی توی سکوت برق‌برق می‌زند. +شهریار کوچولو گفت: -چیزی که کویر را زیبا می‌کند این است که یک جایی یک چاه قایم کرده... +از این‌که ناگهان به راز آن درخشش اسرارآمیزِ شن پی بردم حیرت‌زده شدم. بچگی‌هام تو خانه‌ی کهنه‌سازی می‌نشستیم که معروف بود تو آن گنجی چال کرده‌اند. البته نگفته پیداست که هیچ وقت کسی آن را پیدا نکرد و شاید حتا اصلا کسی دنبالش نگشت اما فکرش همه‌ی اهل خانه را تردماغ می‌کرد: «خانه‌ی ما تهِ دلش رازی پنهان کرده بود...» +گفتم: -آره. چه خانه باشد چه ستاره، چه کویر، چیزی که اسباب زیبایی‌اش می‌شود نامریی است! +گفت: -خوشحالم که با روباه من توافق داری. + +چون خوابش برده بود بغلش کردم و راه افتادم. دست و دلم می‌لرزید.انگار چیز شکستنیِ بسیار گران‌بهایی را روی دست می‌بردم. حتا به نظرم می‌آمد که تو تمام عالم چیزی شکستنی‌تر از آن هم به نظر نمی‌رسد. تو روشنی مهتاب به آن پیشانی رنگ‌پریده و آن چشم‌های بسته و آن طُرّه‌های مو که باد می‌جنباند نگاه کردم و تو دلم گفتم: «آن چه می‌بینم صورت ظاهری بیش‌تر نیست. مهم‌ترش را با چشم نمی‌شود دید...» +باز، چون دهان نیمه‌بازش طرح کم‌رنگِ نیمه‌لبخندی را داشت به خود گفتم: «چیزی که تو شهریار کوچولوی خوابیده مرا به این شدت متاثر می‌کند وفاداری اوست به یک گل: او تصویرِ گل سرخی است که مثل شعله‌ی چراغی حتا در خوابِ ناز هم که هست تو وجودش می‌درخشد...» و آن وقت او را باز هم شکننده‌تر دیدم. حس کردم باید خیلی مواظبش باشم: به شعله‌ی چراغی می‌مانست که یک وزش باد هم می‌توانست خاموشش کند. +و همان طور در حال راه رفتن بود که دمدمه‌ی سحر چاه را پیداکردم. + +۲۵ +شهریار کوچولو درآمد که: -آدم‌ها!... می‌چپند تو قطارهای تندرو اما نمی‌دانند دنبال چی می‌گردند. این است که بنامی‌کنند دور خودشان چرخک‌زدن. +و بعد گفت: -این هم کار نشد... +چاهی که به‌اش رسیده‌بودیم اصلا به چاه‌های کویری نمی‌مانست. چاه کویری یک چاله‌ی ساده است وسط شن‌ها. این یکی به چاه‌های واحه‌ای می‌مانست اما آن دوروبر واحه‌ای نبود و من فکر کردم دارم خواب می‌بینم. +گفتم: -عجیب است! قرقره و سطل و تناب، همه‌چیز روبه‌راه است. +خندید تناب را گرفت و قرقره را به کار انداخت + +شهریار کوچولو در حالِ کشیدنِ آب از چاه +و قرقره مثل بادنمای کهنه‌ای که تا مدت‌ها پس از خوابیدنِ باد می‌نالد به ناله‌درآمد. +گفت: -می‌شنوی؟ ما داریم این چاه را از خواب بیدار می‌کنیم و او دارد برای‌مان آواز می‌خواند... +دلم نمی‌خواست او تلاش و تقلا کند. بش گفتم: -بدهش به من. برای تو زیادی سنگین است. +سطل را آرام تا طوقه‌ی چاه آوردم بالا و آن‌جا کاملا در تعادل نگهش داشتم. از حاصل کار شاد بودم. خسته و شاد. آواز قرقره را همان‌طور تو گوشم داشتم و تو آب که هنوز می‌لرزید لرزش خورشید را می‌دیدم. +گفت: -بده من، که تشنه‌ی این آبم. +ومن تازه توانستم بفهمم پی چه چیز می‌گشته! + +سطل را تا لب‌هایش بالا بردم. با چشم‌های بسته نوشید. آبی بود به شیرینیِ عیدی. این آب به کُلّی چیزی بود سوایِ هرگونه خوردنی. زاییده‌ی راه رفتنِ زیر ستاره‌ها و سرود قرقره و تقلای بازوهای من بود. مثل یک چشم روشنی برای دل خوب بود. پسر بچه که بودم هم، چراغ درخت عید و موسیقیِ نماز نیمه‌شب عید کریسمس و لطف لب‌خنده‌ها عیدیی را که بم می‌دادند درست به همین شکل آن همه جلا و جلوه می‌بخشید. +گفت: -مردم سیاره‌ی تو ور می‌دارند پنج هزار تا گل را تو یک گلستان می‌کارند، و آن یک دانه‌ای را که پِیَش می‌گردند آن وسط پیدا نمی‌کنند... +گفتم: -پیدایش نمی‌کنند. +-با وجود این، چیزی که پیَش می‌گردند ممکن است فقط تو یک گل یا تو یک جرعه آب پیدا بشود... +جواب دادم: -گفت‌وگو ندارد. +باز گفت: -گیرم چشمِ سَر کور است، باید با چشم دل پی‌اش گشت. +من هم سیراب شده بودم. راحت نفس می‌کشیدم. وقتی آفتاب درمی‌آید شن به رنگ عسل است. من هم از این رنگ عسلی لذت می‌بردم. چرا می‌بایست در زحمت باشم... +شهریار کوچولو که باز گرفته بود کنار من نشسته بود با لطف بم گفت: -هِی! قولت قول باشد ها! +-کدام قول؟ +-یادت است؟ یک پوزه‌بند برای بَرّه‌ام... آخر من مسئول گلمَم! +طرح‌های اولیه‌ام را از جیب درآوردم. نگاه‌شان کرد و خندان‌خندان گفت: -بائوباب‌هات یک خرده شبیه کلم شده. +ای وای! مرا بگو که آن‌قدر به بائوباب‌هام می‌نازیدم. +-روباهت... گوش‌هاش بیش‌تر به شاخ می‌ماند... زیادی درازند! +و باز زد زیر خنده. +-آقا کوچولو داری بی‌انصافی می‌کنی. من جز بوآهای بسته و بوآهای باز چیزی بلد نبودم بکشم که. +گفت: -خب، مهم نیست. عوضش بچه‌ها سرشان تو حساب است. +با مداد یک پوزه‌بند کشیدم دادم دستش و با دلِ فشرده گفتم: +-تو خیالاتی به سر داری که من ازشان بی‌خبرم... +اما جواب مرا نداد. بم گفت: -می‌دانی؟ فردا سالِ به زمین آمدنِ من است. +بعد پس از لحظه‌ای سکوت دوباره گفت: -همین نزدیکی‌ها پایین آمدم. +و سرخ شد. + +و من از نو بی این که بدانم چرا غم عجیبی احساس کردم. با وجود این سوآلی به ذهنم رسید: -پس هشت روز پیش، آن روز صبح که تو تک و تنها هزار میل دورتر از هر آبادی وسطِ کویر به من برخوردی اتفاقی نبود: داشتی برمی‌گشتی به همان جایی که پایین‌آمدی... +دوباره سرخ شد +و من با دودلی به دنبال حرفم گفتم: +-شاید به مناسبت همین سال‌گرد؟... +باز سرخ شد. او هیچ وقت به سوآل‌هایی که ازش می‌شد جواب نمی‌داد اما وقتی کسی سرخ می‌شود معنیش این است که «بله»، مگر نه؟ +به‌اش گفتم: -آخر، من ترسم برداشته... +اما او حرفم را برید: +-دیگر تو باید بروی به کارت برسی. باید بروی سراغ موتورت. من همین‌جا منتظرت می‌مانم. فردا عصر برگرد... + +منتها من خاطر جمع نبودم. به یاد روباه افتادم: اگر آدم گذاشت اهلیش کنند بفهمی‌نفهمی خودش را به این خطر انداخته که کارش به گریه‌کردن بکشد. + +۲۶ +کنار چاه دیوارِ سنگی مخروبه‌ای بود. فردا عصر که از سرِ کار برگشتم از دور دیدم که آن بالا نشسته پاها را آویزان کرده، + +شهریار کوچولو نشسته بر دیوارِ سنگی و مار در پایینِ آن +و شنیدم که می‌گوید: +-پس یادت نمی‌آید؟ درست این نقطه نبود ها! +لابد صدای دیگری به‌اش جوابی داد، چون شهریار کوچولو در رَدِّ حرفش گفت: +-چرا چرا! روزش که درست همین امروز است گیرم محلش این جا نیست... +راهم را به طرف دیوار ادامه دادم. هنوز نه کسی به چشم خورده بود نه صدای کسی را شنیده بودم اما شهریار کوچولو باز در جواب درآمد که: +-... آره، معلوم است. خودت می‌توانی ببینی رَدِّ پاهایم روی شن از کجا شروع می‌شود. +همان جا منتظرم باش، تاریک که شد می‌آیم. +بیست متری دیوار بودم و هنوز چیزی نمی‌دیدم. پس از مختصر مکثی دوباره گفت: +-زهرت خوب هست؟ مطمئنی درد و زجرم را کِش نمی‌دهد؟ +با دل فشرده از راه ماندم اما هنوز از موضوع سر در نیاورده بودم. +گفت: -خب، حالا دیگر برو. دِ برو. می‌خواهم بیایم پایین! + +آن وقت من نگاهم را به پایین به پای دیوار انداختم و از جا جستم! یکی از آن مارهای زردی که تو سی ثانیه کَلَکِ آدم را می‌کنند، به طرف شهریار کوچولو قد راست کرده بود. من همان طور که به دنبال تپانچه دست به جیبم می‌بردم پا گذاشتم به دو، اما ماره از سر و صدای من مثل فواره‌ای که بنشیند آرام روی شن جاری شد و بی آن که چندان عجله‌ای از خودش نشان دهد باصدای خفیف فلزی لای سنگ‌ها خزید. +من درست به موقع به دیوار رسیدم و طفلکی شهریار کوچولو را که رنگش مثل برف پریده بود تو هوا بغل کردم. +-این دیگر چه حکایتی است! حالا دیگر با مارها حرف می‌زنی؟ +شال زردش را که مدام به گردن داشت باز کردم به شقیقه‌هایش آب زدم و جرعه‌ای به‌اش نوشاندم. اما حالا دیگر اصلا جرات نمی کردم ازش چیزی بپرسم. با وقار به من نگاه کرد و دستش را دور گردنم انداخت. حس کردم قلبش مثل قلب پرنده‌ای می‌زند که تیر خورده‌است و دارد می‌میرد. +گفت: -از این که کم و کسرِ لوازم ماشینت را پیدا کردی خوش‌حالم. حالا می‌توانی برگردی خانه‌ات... +-تو از کجا فهمیدی؟ +درست همان دم لب‌واکرده‌بودم بش خبر بدهم که علی‌رغم همه‌ی نومیدی‌ها تو کارم موفق شده‌ام! +به سوآل‌های من هیچ جوابی نداد اما گفت: -آخر من هم امروز بر می‌گردم خانه‌ام... +و بعد غم‌زده درآمد که: -گیرم راه من خیلی دورتر است... خیلی سخت‌تر است... + +حس می‌کردم اتفاق فوق‌العاده‌ای دارد می‌افتد. گرفتمش تو بغلم. عین یک بچه‌ی کوچولو. با وجود این به نظرم می‌آمد که او دارد به گردابی فرو می‌رود و برای نگه داشتنش از من کاری ساخته نیست... نگاه متینش به دوردست‌های دور راه کشیده بود. +گفت: بَرِّه‌ات را دارم. جعبه‌هه را هم واسه بره‌هه دارم. پوزه‌بنده را هم دارم. +و با دلِ گرفته لبخندی زد. +مدت درازی صبر کردم. حس کردم کم‌کمَک تنش دوباره دارد گرم می‌شود. +-عزیز کوچولوی من، وحشت کردی... +-امشب وحشت خیلی بیش‌تری چشم به‌راهم است. + +دوباره از احساسِ واقعه‌ای جبران ناپذیر یخ زدم. این فکر که دیگر هیچ وقت غش‌غش خنده‌ی او را نخواهم شنید برایم سخت تحمل‌ناپذیر بود. خنده‌ی او برای من به چشمه‌ای در دلِ کویر می‌مانست. +-کوچولوئَکِ من، دلم می‌خواهد باز هم غش‌غشِ خنده‌ات را بشنوم. +اما به‌ام گفت: -امشب درست می‌شود یک سال و اخترَکَم درست بالای همان نقطه‌ای می‌رسد که پارسال به زمین آمدم. +-کوچولوئک، این قضیه‌ی مار و میعاد و ستاره یک خواب آشفته بیش‌تر نیست. مگر نه؟ +به سوال من جوابی نداد اما گفت: -چیزی که مهم است با چشمِ سَر دیده نمی‌شود. +-مسلم است. +-در مورد گل هم همین‌طور است: اگر گلی را دوست داشته باشی که تو یک ستاره‌ی دیگر است، شب تماشای آسمان چه لطفی پیدا می‌کند: همه‌ی ستاره‌ها غرق گل می‌شوند! +-مسلم است... +-در مورد آب هم همین‌طور است. آبی که تو به من دادی به خاطر قرقره و ریسمان درست به یک موسیقی می‌مانست... یادت که هست... چه خوب بود. +-مسلم است... +-شب‌به‌شب ستاره‌ها را نگاه می‌کنی. اخترک من کوچولوتر از آن است که بتوانم جایش را نشانت بدهم. اما چه بهتر! آن هم برای تو می‌شود یکی از ستاره‌ها؛ و آن وقت تو دوست داری همه‌ی ستاره‌ها را تماشا کنی... همه‌شان می‌شوند دوست‌های تو... راستی می‌خواهم هدیه‌ای بت بدهم... +و غش غش خندید. +-آخ، کوچولوئک، کوچولوئک! من عاشقِ شنیدنِ این خنده‌ام! +-هدیه‌ی من هم درست همین است... درست مثل مورد آب. +-چی می‌خواهی بگویی؟ +-همه‌ی مردم ستاره دارند اما همه‌ی ستاره‌ها یک‌جور نیست: واسه آن‌هایی که به سفر می‌روند حکم راهنما را دارند واسه بعضی دیگر فقط یک مشت روشناییِ سوسوزن‌اند. برای بعضی که اهل دانشند هر ستاره یک معما است واسه آن بابای تاجر طلا بود. اما این ستاره‌ها همه‌شان زبان به کام کشیده و خاموشند. فقط تو یکی ستاره‌هایی خواهی داشت که تنابنده‌ای مِثلش را ندارد. +-چی می‌خواهی بگویی؟ +-نه این که من تو یکی از ستاره‌هام؟ نه این که من تو یکی از آن‌ها می‌خندم؟... خب، پس هر شب که به آسمان نگاه می‌کنی برایت مثل این خواهد بود که همه‌ی ستاره‌ها می‌خندند. پس تو ستاره‌هایی خواهی داشت که بلدند بخندند! +و باز خندید. +-و خاطرت که تسلا پیدا کرد (خب بالاخره آدمی‌زاد یک جوری تسلا پیدا می‌کند دیگر) از آشنایی با من خوش‌حال می‌شوی. دوست همیشگی من باقی می‌مانی و دلت می‌خواهد با من بخندی و پاره‌ای وقت‌هام واسه تفریح پنجره‌ی اتاقت را وا می‌کنی... دوستانت از این‌که می‌بینند تو به آسمان نگاه می‌کنی و می‌خندی حسابی تعجب می‌کنند آن وقت تو به‌شان می‌گویی: «آره، ستاره‌ها همیشه مرا خنده می‌اندازند!» و آن‌وقت آن‌ها یقین‌شان می‌شود که تو پاک عقلت را از دست داده‌ای. جان! می‌بینی چه کَلَکی به‌ات زده‌ام... +و باز زد زیر خنده. +-به آن می‌ماند که عوضِ ستاره یک مشت زنگوله بت داده باشم که بلدند بخندند... +دوباره خندید و بعد حالتی جدی به خودش گرفت: +-نه، من تنهات نمی‌گذارم. + +شهریار کوچولو تنها + +-ظاهر آدمی را پیدا می‌کنم که دارد درد می‌کشد... یک خرده هم مثل آدمی می‌شوم که دارد جان می‌کند. رو هم رفته این جوری‌ها است. نیا که این را نبینی. چه زحمتی است بی‌خود؟ +-تنهات نمی‌گذارم. +اندوه‌زده بود. +-این را بیش‌تر از بابت ماره می‌گویم که، نکند یک‌هو تو را هم بگزد. مارها خیلی خبیثند. حتا واسه خنده هم ممکن است آدم را نیش بزنند. +-تنهات نمی‌گذارم. +منتها یک چیز باعث خاطر جمعیش شد: +-گر چه، بار دوم که بخواهند بگزند دیگر زهر ندارند. +شب متوجه راه افتادنش نشدم. بی سر و صدا گریخت. +وقتی خودم را به‌اش رساندم با قیافه‌ی مصمم و قدم‌های محکم پیش می‌رفت. همین قدر گفت: -اِ! این‌جایی؟ +و دستم را گرفت. +اما باز بی‌قرار شد وگفت: -اشتباه کردی آمدی. رنج می‌بری. گرچه حقیقت این نیست، اما ظاهرِ یک مرده را پیدا می‌کنم. +من ساکت ماندم. +-خودت درک می‌کنی. راه خیلی دور است. نمی‌توانم این جسم را با خودم ببرم. خیلی سنگین است. +من ساکت ماندم. +-گیرم عینِ پوستِ کهنه‌ای می‌شود که دورش انداخته باشند؛ پوست کهنه که غصه ندارد، ها؟ +من ساکت ماندم. +کمی دل‌سرد شد اما باز هم سعی کرد: +-خیلی با مزه می‌شود، نه؟ من هم به ستاره‌ها نگاه می‌کنم. هم‌شان به صورت چاه‌هایی در می‌آیند با قرقره‌های زنگ زده. همه‌ی ستاره‌ها بم آب می‌دهند بخورم... +من ساکت ماندم. +-خیلی با مزه می‌شود. نه؟ تو صاحب هزار کرور زنگوله می‌شوی من صاحب هزار کرور فواره... +او هم ساکت شد، چرا که داشت گریه می‌کرد... +-خب، همین جاست. بگذار چند قدم خودم تنهایی بروم. +و گرفت نشست، چرا که می‌ترسید. + +شهریار کوچولو نشسته + +می‌دانی؟... گلم را می‌گویم... آخر من مسئولشم. تازه چه قدر هم لطیف است و چه قدر هم ساده و بی‌شیله‌پیله. برای آن که جلو همه‌ی عالم از خودش دفاع کند همه‌اش چی دارد مگر؟ چهارتا خار پِرپِرَک! + +من هم گرفتم نشستم. دیگر نمی‌توانستم سر پا بند بشوم. +گفت: -همین... همه‌اش همین و بس... +باز هم کمی دودلی نشان داد اما بالاخره پا شد و قدمی به جلو رفت. من قادر به حرکت نبودم. + +کنار قوزکِ پایش جرقه‌ی زردی جست و... فقط همین! یک دم بی‌حرکت ماند. فریادی نزد. مثل درختی که بیفتد آرام‌آرام به زمین افتاد که به وجود شن از آن هم صدایی بلند نشد. + +شهریار کوچولو در حالی که آرام‌آرام به زمین می‌افتد +۲۷ +شش سال گذشته است و من هنوز بابت این قضیه جایی لب‌ترنکرده‌ام. دوستانم از این که مرا دوباره زنده می‌دیدند سخت شاد شدند. من غم‌زده بودم اما به آن‌ها می‌گفتم اثر خستگی است. +حالا کمی تسلای خاطر پیدا کرده‌ام. یعنی نه کاملا... اما این را خوب می‌دانم که او به اخترکش برگشته. چون آفتاب که زد پیکرش را پیدا نکردم. پیکری هم نبود که چندان وزنی داشته باشد... و شب‌ها دوست دارم به ستاره‌ها گوش بدهم. عین هزار زنگوله‌اند. +اما موضوع خیلی مهمی که هست، من پاک یادم رفت به پوزه‌بندی که برای شهریار کوچولو کشیدم تسمه‌ی چرمی اضافه کنم و او ممکن نیست بتواند آن را به پوزه‌ی بَرّه ببندد. این است که از خودم می‌پرسم: «یعنی تو اخترکش چه اتفاقی افتاده؟ نکند بره‌هه گل را چریده باشد؟...» +گاه به خودم می‌گویم: «حتما نه، شهریار کوچولو هر شب گلش را زیر حباب شیشه‌ای می‌گذارد و هوای بره‌اش را هم دارد...» آن وقت است که خیالم راحت می‌شود و ستاره‌ها همه به شیرینی می‌خندند. +گاه به خودم می‌گویم: «همین کافی است که آدم یک بار حواسش نباشد... آمدیم و یک شب حباب یادش رفت یا بَرّه شب نصف‌شبی بی‌سروصدا از جعبه زد بیرون...» آن وقت است که زنگوله‌ها همه تبدیل به اشک می‌شوند!... + +یک راز خیلی خیلی بزرگ این جا هست: برای شما هم که او را دوست دارید، مثل من هیچ چیزِ عالم مهم‌تر از دانستن این نیست که تو فلان نقطه‌ای که نمی‌دانیم، فلان بره‌ای که نمی‌شماسیم گل سرخی را چریده یا نچریده... + +خب. آسمان را نگاه کنید و بپرسید: «بَرّه گل را چریده یا نچریده؟» و آن وقت با چشم‌های خودتان تفاوتش را ببینید... + +و محال است آدم بزرگ‌ها روح‌شان خبردار بشود که این موضوع چه قدر مهم است! + +بدونِ شهریار کوچولو +در نظر من این زیباترین و حزن‌انگیزترین منظره‌ی عالم است. این همان منظره‌ی دو صفحه پیش است گیرم آن را دوباره کشیده‌ام که به‌تر نشان‌تان بدهم: «ظهور شهریار کوچولو بر زمین در این جا بود؛ و بعد در همین جا هم بود که ناپدید شد». + +آن قدر به دقت این منظره را نگاه کنید که مطمئن بشوید اگر روزی تو آفریقا گذرتان به کویر صحرا افتاد حتما آن را خواهید شناخت. و اگر پاداد و گذارتان به آن جا افتاد به التماس ازتان می‌خواهم که عجله به خرج ندهید و درست زیر ستاره چند لحظه‌ای توقف کنید. آن وقت اگر بچه‌ای به طرف‌تان آمد، اگر خندید، اگر موهایش طلایی بود، اگر وقتی ازش سوالی کردید جوابی نداد، لابد حدس می‌زنید که کیست. در آن صورت لطف کنید و نگذارید من این جور افسرده خاطر بمانم: +بی درنگ بردارید به من بنویسید که او برگشته. + diff --git a/src/Makefile.am b/src/Makefile.am index 7173f4b7de555fd218409a35a3ac7691b15b3bc0..7a0ca29851a2ba5cb6124d0be0883e99594576a5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,6 +13,8 @@ TESTS = check_PROGRAMS = EXTRA_DIST += harfbuzz.cc +EXTRA_DIST += meson.build +EXTRA_DIST += fix_get_types.py # Convenience targets: lib: $(BUILT_SOURCES) libharfbuzz.la @@ -50,12 +52,7 @@ endif if HAVE_FREETYPE HBCFLAGS += $(FREETYPE_CFLAGS) HBLIBS += $(FREETYPE_LIBS) -# XXX -# The following creates a recursive dependency on FreeType if FreeType is -# built with HarfBuzz support enabled. Newer pkg-config handles that just -# fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes. Remove -# in a year or two, or otherwise work around it... -#HBDEPS += $(FREETYPE_DEPS) +HBDEPS += $(FREETYPE_DEPS) HBSOURCES += $(HB_FT_sources) HBHEADERS += $(HB_FT_headers) endif @@ -153,6 +150,7 @@ cmake_DATA = harfbuzz-config.cmake EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in lib_LTLIBRARIES += libharfbuzz-subset.la +libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS) libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources) libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS) libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS) @@ -237,7 +235,8 @@ DEF_FILES += harfbuzz-gobject.def endif check: $(DEF_FILES) # For check-symbols.sh CLEANFILES += $(DEF_FILES) -harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS) +harfbuzz.def: $(top_builddir)/config.status +harfbuzz.def: $(HBHEADERS) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-subset.def: $(HB_SUBSET_headers) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ @@ -250,11 +249,15 @@ harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h GENERATORS = \ + gen-arabic-joining-list.py \ gen-arabic-table.py \ gen-def.py \ gen-emoji-table.py \ + gen-harfbuzzcc.py \ + gen-hb-version.py \ gen-indic-table.py \ gen-os2-unicode-ranges.py \ + gen-ragel-artifacts.py \ gen-tag-table.py \ gen-ucd-table.py \ gen-use-table.py \ @@ -262,42 +265,9 @@ GENERATORS = \ $(NULL) EXTRA_DIST += $(GENERATORS) -unicode-tables: \ - arabic-table \ - emoji-table \ - indic-table \ - tag-table \ - ucd-table \ - use-table \ - emoji-table \ - $(NULL) - -arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \ - || ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false) -emoji-table: gen-emoji-table.py emoji-data.txt - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \ - || ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false) -indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \ - || ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false) -tag-table: gen-tag-table.py languagetags language-subtag-registry - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \ - || ($(RM) $(srcdir)/hb-ot-tag-table.hh; false) -ucd-table: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ucd-table.hh \ - || ($(RM) $(srcdir)/hb-ucd-table.hh; false) -use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \ - || ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false) -vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt - $(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \ - || ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false) - - built-sources: $(BUILT_SOURCES) -.PHONY: unicode-tables arabic-table indic-table tag-table use-table vowel-constraints emoji-table built-sources +.PHONY: built-sources RAGEL_GENERATED = \ $(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \ @@ -334,6 +304,7 @@ noinst_PROGRAMS = \ test-buffer-serialize \ test-ot-meta \ test-ot-name \ + test-ot-glyphname \ test-gpos-size-params \ test-gsub-would-substitute \ $(NULL) @@ -359,6 +330,10 @@ test_ot_name_SOURCES = test-ot-name.cc test_ot_name_CPPFLAGS = $(HBCFLAGS) test_ot_name_LDADD = libharfbuzz.la $(HBLIBS) +test_ot_glyphname_SOURCES = test-ot-glyphname.cc +test_ot_glyphname_CPPFLAGS = $(HBCFLAGS) +test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS) + test_gpos_size_params_SOURCES = test-gpos-size-params.cc test_gpos_size_params_CPPFLAGS = $(HBCFLAGS) test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS) @@ -367,51 +342,7 @@ test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) -if HAVE_FREETYPE -if HAVE_CAIRO_FT -noinst_PROGRAMS += test-ot-color -test_ot_color_SOURCES = test-ot-color.cc -test_ot_color_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS) -test_ot_color_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS) -endif # HAVE_CAIRO_FT -endif # HAVE_FREETYPE - -dist_check_SCRIPTS = \ - check-c-linkage-decls.sh \ - check-externs.sh \ - check-header-guards.sh \ - check-includes.sh \ - check-static-inits.sh \ - check-symbols.sh \ - $(NULL) -TESTS += $(dist_check_SCRIPTS) - -if !WITH_LIBSTDCXX -dist_check_SCRIPTS += \ - check-libstdc++.sh \ - $(NULL) -endif - -check_PROGRAMS += \ - dump-indic-data \ - dump-khmer-data \ - dump-myanmar-data \ - dump-use-data \ - $(NULL) -dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc -dump_indic_data_CPPFLAGS = $(HBCFLAGS) -dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS) -dump_khmer_data_SOURCES = dump-khmer-data.cc hb-ot-shape-complex-indic-table.cc -dump_khmer_data_CPPFLAGS = $(HBCFLAGS) -dump_khmer_data_LDADD = libharfbuzz.la $(HBLIBS) -dump_myanmar_data_SOURCES = dump-myanmar-data.cc hb-ot-shape-complex-indic-table.cc -dump_myanmar_data_CPPFLAGS = $(HBCFLAGS) -dump_myanmar_data_LDADD = libharfbuzz.la $(HBLIBS) -dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc -dump_use_data_CPPFLAGS = $(HBCFLAGS) -dump_use_data_LDADD = libharfbuzz.la $(HBLIBS) - -COMPILED_TESTS = test-algs test-iter test-meta test-ot-tag test-unicode-ranges test-bimap +COMPILED_TESTS = test-algs test-array test-iter test-meta test-number test-ot-tag test-priority-queue test-unicode-ranges test-bimap test-repacker COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS) check_PROGRAMS += $(COMPILED_TESTS) @@ -421,6 +352,18 @@ test_algs_SOURCES = test-algs.cc hb-static.cc test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_algs_LDADD = $(COMPILED_TESTS_LDADD) +test_array_SOURCES = test-array.cc +test_array_CPPFLAGS = $(HBCFLAGS) +test_array_LDADD = libharfbuzz.la $(HBLIBS) + +test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc +test_priority_queue_CPPFLAGS = $(HBCFLAGS) +test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS) + +test_repacker_SOURCES = test-repacker.cc hb-static.cc +test_repacker_CPPFLAGS = $(HBCFLAGS) +test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS) + test_iter_SOURCES = test-iter.cc hb-static.cc test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_iter_LDADD = $(COMPILED_TESTS_LDADD) @@ -429,6 +372,10 @@ test_meta_SOURCES = test-meta.cc hb-static.cc test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_meta_LDADD = $(COMPILED_TESTS_LDADD) +test_number_SOURCES = test-number.cc hb-number.cc +test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_number_LDADD = $(COMPILED_TESTS_LDADD) + test_ot_tag_SOURCES = hb-ot-tag.cc test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD) @@ -441,8 +388,25 @@ test_bimap_SOURCES = test-bimap.cc hb-static.cc test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_bimap_LDADD = $(COMPILED_TESTS_LDADD) +dist_check_SCRIPTS = \ + check-c-linkage-decls.py \ + check-externs.py \ + check-header-guards.py \ + check-includes.py \ + check-static-inits.py \ + check-symbols.py \ + $(NULL) +TESTS += $(dist_check_SCRIPTS) + +if !WITH_LIBSTDCXX +dist_check_SCRIPTS += \ + check-libstdc++.py \ + $(NULL) +endif + TESTS_ENVIRONMENT = \ srcdir="$(srcdir)" \ + builddir="$(builddir)" \ MAKE="$(MAKE) $(AM_MAKEFLAGS)" \ HBSOURCES="$(HBSOURCES)" \ HBHEADERS="$(HBHEADERS)" \ @@ -452,7 +416,16 @@ if HAVE_INTROSPECTION -include $(INTROSPECTION_MAKEFILE) INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?! -INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all +INTROSPECTION_SCANNER_ARGS = \ + -I$(srcdir) \ + --warn-all --verbose \ + --namespace=HarfBuzz \ + --nsversion=0.0 \ + --symbol-prefix=hb \ + --symbol-prefix=hb_gobject \ + --identifier-prefix=hb_ \ + --pkg-export=harfbuzz-gobject \ + --c-include=hb-gobject.h INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) INTROSPECTION_SCANNER_ENV = CC="$(CC)" @@ -461,14 +434,7 @@ HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 HarfBuzz_0_0_gir_CFLAGS = \ $(INCLUDES) \ $(HBCFLAGS) \ - -DHB_H \ - -DHB_H_IN \ - -DHB_OT_H \ - -DHB_OT_H_IN \ - -DHB_AAT_H \ - -DHB_AAT_H_IN \ - -DHB_GOBJECT_H \ - -DHB_GOBJECT_H_IN \ + -DHB_NO_SINGLE_HEADER_ERROR \ -DHAVE_GOBJECT \ -DHB_EXTERN= \ $(NULL) diff --git a/src/Makefile.sources b/src/Makefile.sources index 6e29b3f973361cd84094e8ee0de7c584b8318d44..14c97996b00011a5f7a15ecab09c277f9a7a7b40 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -1,14 +1,12 @@ # Base and default-included sources and headers HB_BASE_sources = \ - hb-aat-fdsc-table.hh \ hb-aat-layout-ankr-table.hh \ hb-aat-layout-bsln-table.hh \ hb-aat-layout-common.hh \ hb-aat-layout-feat-table.hh \ hb-aat-layout-just-table.hh \ hb-aat-layout-kerx-table.hh \ - hb-aat-layout-lcar-table.hh \ hb-aat-layout-morx-table.hh \ hb-aat-layout-opbd-table.hh \ hb-aat-layout-trak-table.hh \ @@ -20,6 +18,7 @@ HB_BASE_sources = \ hb-algs.hh \ hb-array.hh \ hb-atomic.hh \ + hb-bimap.hh \ hb-blob.cc \ hb-blob.hh \ hb-buffer-serialize.cc \ @@ -35,6 +34,8 @@ HB_BASE_sources = \ hb-config.hh \ hb-debug.hh \ hb-dispatch.hh \ + hb-draw.cc \ + hb-draw.hh \ hb-face.cc \ hb-face.hh \ hb-fallback-shape.cc \ @@ -45,14 +46,16 @@ HB_BASE_sources = \ hb-machinery.hh \ hb-map.cc \ hb-map.hh \ - hb-bimap.hh \ hb-meta.hh \ hb-mutex.hh \ hb-null.hh \ + hb-number.cc \ + hb-number.hh \ hb-object.hh \ hb-open-file.hh \ hb-open-type.hh \ hb-ot-cff-common.hh \ + hb-ot-cff1-std-str.hh \ hb-ot-cff1-table.cc \ hb-ot-cff1-table.hh \ hb-ot-cff2-table.cc \ @@ -64,9 +67,9 @@ HB_BASE_sources = \ hb-ot-color-sbix-table.hh \ hb-ot-color-svg-table.hh \ hb-ot-color.cc \ + hb-ot-face-table-list.hh \ hb-ot-face.cc \ hb-ot-face.hh \ - hb-ot-face-table-list.hh \ hb-ot-font.cc \ hb-ot-gasp-table.hh \ hb-ot-glyf-table.hh \ @@ -102,6 +105,7 @@ HB_BASE_sources = \ hb-ot-post-macroman.hh \ hb-ot-post-table.hh \ hb-ot-shape-complex-arabic-fallback.hh \ + hb-ot-shape-complex-arabic-joining-list.hh \ hb-ot-shape-complex-arabic-table.hh \ hb-ot-shape-complex-arabic-win1256.hh \ hb-ot-shape-complex-arabic.cc \ @@ -116,10 +120,11 @@ HB_BASE_sources = \ hb-ot-shape-complex-khmer.hh \ hb-ot-shape-complex-myanmar.cc \ hb-ot-shape-complex-myanmar.hh \ + hb-ot-shape-complex-syllabic.cc \ + hb-ot-shape-complex-syllabic.hh \ hb-ot-shape-complex-thai.cc \ - hb-ot-shape-complex-use-table.cc \ + hb-ot-shape-complex-use-table.hh \ hb-ot-shape-complex-use.cc \ - hb-ot-shape-complex-use.hh \ hb-ot-shape-complex-vowel-constraints.cc \ hb-ot-shape-complex-vowel-constraints.hh \ hb-ot-shape-complex.hh \ @@ -134,6 +139,7 @@ HB_BASE_sources = \ hb-ot-tag.cc \ hb-ot-var-avar-table.hh \ hb-ot-var-fvar-table.hh \ + hb-ot-var-gvar-table.hh \ hb-ot-var-hvar-table.hh \ hb-ot-var-mvar-table.hh \ hb-ot-var.cc \ @@ -153,6 +159,7 @@ HB_BASE_sources = \ hb-shaper.hh \ hb-static.cc \ hb-string-array.hh \ + hb-style.cc \ hb-ucd-table.hh \ hb-ucd.cc \ hb-unicode-emoji-table.hh \ @@ -160,13 +167,14 @@ HB_BASE_sources = \ hb-unicode.hh \ hb-utf.hh \ hb-vector.hh \ - hb-warning.cc \ + hb-priority-queue.hh \ hb.hh \ $(NULL) HB_BASE_RAGEL_GENERATED_sources = \ hb-buffer-deserialize-json.hh \ hb-buffer-deserialize-text.hh \ + hb-number-parser.hh \ hb-ot-shape-complex-indic-machine.hh \ hb-ot-shape-complex-khmer-machine.hh \ hb-ot-shape-complex-myanmar-machine.hh \ @@ -175,6 +183,7 @@ HB_BASE_RAGEL_GENERATED_sources = \ HB_BASE_RAGEL_sources = \ hb-buffer-deserialize-json.rl \ hb-buffer-deserialize-text.rl \ + hb-number-parser.rl \ hb-ot-shape-complex-indic-machine.rl \ hb-ot-shape-complex-khmer-machine.rl \ hb-ot-shape-complex-myanmar-machine.rl \ @@ -188,6 +197,7 @@ HB_BASE_headers = \ hb-buffer.h \ hb-common.h \ hb-deprecated.h \ + hb-draw.h \ hb-face.h \ hb-font.h \ hb-map.h \ @@ -205,6 +215,7 @@ HB_BASE_headers = \ hb-set.h \ hb-shape-plan.h \ hb-shape.h \ + hb-style.h \ hb-unicode.h \ hb-version.h \ hb.h \ @@ -241,6 +252,8 @@ HB_ICU_headers = hb-icu.h # Sources for libharfbuzz-subset HB_SUBSET_sources = \ + hb-number.cc \ + hb-number.hh \ hb-ot-cff1-table.cc \ hb-ot-cff2-table.cc \ hb-static.cc \ @@ -254,10 +267,9 @@ HB_SUBSET_sources = \ hb-subset-input.hh \ hb-subset-plan.cc \ hb-subset-plan.hh \ - hb-subset-plan.hh \ hb-subset.cc \ hb-subset.hh \ - hb-subset.hh \ + hb-repacker.hh \ $(NULL) HB_SUBSET_headers = \ diff --git a/src/check-c-linkage-decls.py b/src/check-c-linkage-decls.py new file mode 100644 index 0000000000000000000000000000000000000000..b7532a7e944ce96ebd58baedc4ba279ff2b31f7c --- /dev/null +++ b/src/check-c-linkage-decls.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +import sys, os + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')] +HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))] + +stat = 0 + +for x in HBHEADERS: + with open (x, 'r', encoding='utf-8') as f: content = f.read () + if ('HB_BEGIN_DECLS' not in content) or ('HB_END_DECLS' not in content): + print ('Ouch, file %s does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should' % x) + stat = 1 + +for x in HBSOURCES: + with open (x, 'r', encoding='utf-8') as f: content = f.read () + if ('HB_BEGIN_DECLS' in content) or ('HB_END_DECLS' in content): + print ('Ouch, file %s has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn\'t' % x) + stat = 1 + +sys.exit (stat) diff --git a/src/check-c-linkage-decls.sh b/src/check-c-linkage-decls.sh deleted file mode 100755 index 8234abc455a44803cfa165b365ece209f4319b63..0000000000000000000000000000000000000000 --- a/src/check-c-linkage-decls.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -stat=0 - -test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'` -test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.cc'` - -for x in $HBHEADERS; do - test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then - echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should" - stat=1 - fi -done -for x in $HBSOURCES; do - test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then - echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't" - stat=1 - fi -done - -exit $stat diff --git a/src/check-externs.py b/src/check-externs.py new file mode 100644 index 0000000000000000000000000000000000000000..a64d2e5b4a9f21af34ad46bc651ee65488f6c7ff --- /dev/null +++ b/src/check-externs.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import sys, os, re + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')] + +stat = 0 + +print ('Checking that all public symbols are exported with HB_EXTERN') +for x in HBHEADERS: + with open (x, 'r', encoding='utf-8') as f: content = f.read () + for s in re.findall (r'\n.+\nhb_.+\n', content): + if not s.startswith ('\nHB_EXTERN '): + print ('failure on:', s) + stat = 1 + +sys.exit (stat) diff --git a/src/check-externs.sh b/src/check-externs.sh deleted file mode 100755 index a6de375350cce035900599a7193dfea957a81a13..0000000000000000000000000000000000000000 --- a/src/check-externs.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -stat=0 - -test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'` -test "x$EGREP" = x && EGREP='grep -E' - - -echo 'Checking that all public symbols are exported with HB_EXTERN' - -for x in $HBHEADERS; do - test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - $EGREP -B1 -n '^hb_' /dev/null "$x" | - $EGREP -v '(^--|:hb_|-HB_EXTERN )' -A1 -done | -grep . >&2 && stat=1 - -exit $stat diff --git a/src/check-header-guards.py b/src/check-header-guards.py new file mode 100644 index 0000000000000000000000000000000000000000..0ad42cd845eb17a0adb8ab37af38b9638ccfd97b --- /dev/null +++ b/src/check-header-guards.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import sys, os, re + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')] +HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))] + +stat = 0 + +for x in HBHEADERS + HBSOURCES: + if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue + tag = x.upper ().replace ('.', '_').replace ('-', '_') + with open (x, 'r', encoding='utf-8') as f: content = f.read () + if len (re.findall (tag + r'\b', content)) != 3: + print ('Ouch, header file %s does not have correct preprocessor guards' % x) + stat = 1 + +sys.exit (stat) diff --git a/src/check-header-guards.sh b/src/check-header-guards.sh deleted file mode 100755 index b67640fc1975fdcdfd1bae697da0244e05b099cd..0000000000000000000000000000000000000000 --- a/src/check-header-guards.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -stat=0 - -test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h' ! -name 'hb-gobject-structs.h'` -test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'` - -for x in $HBHEADERS $HBSOURCES; do - test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - echo "$x" | grep -q '[^h]$' && continue; - xx=`echo "$x" | sed 's@.*/@@'` - tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'` - lines=`grep -w "$tag" "$x" | wc -l | sed 's/[ ]*//g'` - if test "x$lines" != x3; then - echo "Ouch, header file $x does not have correct preprocessor guards" - stat=1 - fi -done - -exit $stat diff --git a/src/check-includes.py b/src/check-includes.py new file mode 100644 index 0000000000000000000000000000000000000000..88eaa2eaa92746184ba3f3c9348696f7adfbec49 --- /dev/null +++ b/src/check-includes.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import sys, os, re + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')] +HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \ + [x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))] + +stat = 0 + +print ('Checking that public header files #include "hb-common.h" or "hb.h" first (or none)') +for x in HBHEADERS: + if x == 'hb.h' or x == 'hb-common.h': continue + with open (x, 'r', encoding='utf-8') as f: content = f.read () + first = re.findall (r'#.*include.*', content)[0] + if first not in ['#include "hb.h"', '#include "hb-common.h"']: + print ('failure on %s' % x) + stat = 1 + +print ('Checking that source files #include a private header first (or none)') +for x in HBSOURCES: + with open (x, 'r', encoding='utf-8') as f: content = f.read () + includes = re.findall (r'#.*include.*', content) + if includes: + if not len (re.findall (r'"hb.*\.hh"', includes[0])): + print ('failure on %s' % x) + stat = 1 + +print ('Checking that there is no #include ') +for x in HBHEADERS + HBSOURCES: + with open (x, 'r', encoding='utf-8') as f: content = f.read () + if re.findall ('#.*include.*<.*hb', content): + print ('failure on %s' % x) + stat = 1 + +sys.exit (stat) diff --git a/src/check-includes.sh b/src/check-includes.sh deleted file mode 100755 index f938f706cfd4d6a0845c2269b394445faf36856a..0000000000000000000000000000000000000000 --- a/src/check-includes.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -stat=0 - -test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'` -test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'` - - -echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)' - -for x in $HBHEADERS; do - test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - grep '#.*\' "$x" /dev/null | head -n 1 -done | -grep -v '"hb-common[.]h"' | -grep -v '"hb[.]h"' | -grep -v 'hb-common[.]h:' | -grep -v 'hb[.]h:' | -grep . >&2 && stat=1 - - -echo 'Checking that source files #include a private header first (or none)' - -for x in $HBSOURCES; do - test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x" - grep '#.*\' "$x" /dev/null | head -n 1 -done | -grep -v '"hb-.*[.]hh"' | -grep -v 'hb[.]hh' | -grep . >&2 && stat=1 - - -echo 'Checking that there is no #include ' -for x in $HBHEADERS $HBSOURCES; do - test -f "$srcdir/$x" && x="$srcdir/$x" - grep '#.*\.*<.*hb' "$x" /dev/null >&2 && stat=1 -done - - -exit $stat diff --git a/src/check-libstdc++.py b/src/check-libstdc++.py new file mode 100644 index 0000000000000000000000000000000000000000..200c6837490526d1345972df3a705ca5861e700c --- /dev/null +++ b/src/check-libstdc++.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import sys, os, shutil, subprocess + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +libs = os.getenv ('libs', '.libs') + +ldd = shutil.which ('ldd') +if ldd: + ldd = [ldd] +else: + ldd = shutil.which ('otool') + if ldd: + ldd = [ldd, '-L'] # otool -L + else: + print ('check-libstdc++.py: \'ldd\' not found; skipping test') + sys.exit (77) + +stat = 0 +tested = False + +# harfbuzz-icu links to libstdc++ because icu does. +for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']: + for suffix in ['so', 'dylib']: + so = os.path.join (libs, 'lib%s.%s' % (soname, suffix)) + if not os.path.exists (so): continue + + print ('Checking that we are not linking to libstdc++ or libc++ in %s' % so) + ldd_result = subprocess.check_output (ldd + [so]) + if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result): + print ('Ouch, %s is linked to libstdc++ or libc++' % so) + stat = 1 + + tested = True + +if not tested: + print ('check-libstdc++.py: libharfbuzz shared library not found; skipping test') + sys.exit (77) + +sys.exit (stat) diff --git a/src/check-libstdc++.sh b/src/check-libstdc++.sh deleted file mode 100755 index ce0bdab755f9ac5bbf1d1e68abac3fa1bbb13457..0000000000000000000000000000000000000000 --- a/src/check-libstdc++.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -test -z "$libs" && libs=.libs -stat=0 - - -if which ldd 2>/dev/null >/dev/null; then - LDD=ldd -else - # macOS specific tool - if which otool 2>/dev/null >/dev/null; then - LDD="otool -L" - else - echo "check-libstdc++.sh: 'ldd' not found; skipping test" - exit 77 - fi -fi - -tested=false -# harfbuzz-icu links to libstdc++ because icu does. -# harfbuzz-subset uses libstdc++. -for soname in harfbuzz harfbuzz-gobject; do - for suffix in so dylib; do - so=$libs/lib$soname.$suffix - if ! test -f "$so"; then continue; fi - - echo "Checking that we are not linking to libstdc++ or libc++ in $so" - if $LDD $so | grep 'libstdc[+][+]\|libc[+][+]'; then - echo "Ouch, linked to libstdc++ or libc++" - stat=1 - fi - tested=true - done -done -if ! $tested; then - echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test" - exit 77 -fi - -exit $stat diff --git a/src/check-static-inits.py b/src/check-static-inits.py new file mode 100644 index 0000000000000000000000000000000000000000..1c88f22ca2ba5ecfdb127925aaedac8d09c30d77 --- /dev/null +++ b/src/check-static-inits.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import sys, os, shutil, subprocess, glob, re + +builddir = os.getenv ('builddir', os.path.dirname (__file__)) +libs = os.getenv ('libs', '.libs') + +objdump = shutil.which ('objdump') +if not objdump: + print ('check-static-inits.py: \'ldd\' not found; skipping test') + sys.exit (77) + +if sys.version_info < (3, 5): + print ('check-static-inits.py: needs python 3.5 for recursive support in glob') + sys.exit (77) + +OBJS = glob.glob (os.path.join (builddir, libs, '**', '*.o'), recursive=True) +if not OBJS: + print ('check-static-inits.py: object files not found; skipping test') + sys.exit (77) + +stat = 0 + +for obj in OBJS: + result = subprocess.check_output ([objdump, '-t', obj]).decode ('utf-8') + + # Checking that no object file has static initializers + for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE): + if not re.match (r'.*\b0+\b', l): + print ('Ouch, %s has static initializers/finalizers' % obj) + stat = 1 + + # Checking that no object file has lazy static C++ constructors/destructors or other such stuff + if ('__cxa_' in result) and ('__ubsan_handle' not in result): + print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj) + stat = 1 + +sys.exit (stat) diff --git a/src/check-static-inits.sh b/src/check-static-inits.sh deleted file mode 100755 index def25c70143add8ce6f322bef5d0502b72143530..0000000000000000000000000000000000000000 --- a/src/check-static-inits.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -test -z "$libs" && libs=.libs -stat=0 - -if which objdump 2>/dev/null >/dev/null; then - : -else - echo "check-static-inits.sh: 'objdump' not found; skipping test" - exit 77 -fi - -OBJS=$libs/*.o -if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then - echo "check-static-inits.sh: object files not found; skipping test" - exit 77 -fi - -echo "Checking that no object file has static initializers" -for obj in $OBJS; do - if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then - echo "Ouch, $obj has static initializers/finalizers" - stat=1 - fi -done - -echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff" -for obj in $OBJS; do - if objdump -t "$obj" | grep -q '__cxa_' && ! objdump -t "$obj" | grep -q __ubsan_handle; then - objdump -t "$obj" | grep '__cxa_' - echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff" - stat=1 - fi -done - -exit $stat diff --git a/src/check-symbols.py b/src/check-symbols.py new file mode 100644 index 0000000000000000000000000000000000000000..c366dc0aafd7231cb62ea6b29407b3ada92162e5 --- /dev/null +++ b/src/check-symbols.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 + +import sys, os, shutil, subprocess, re, difflib + +os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order + +builddir = os.getenv ('builddir', os.path.dirname (__file__)) +libs = os.getenv ('libs', '.libs') + +IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss', + '__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__', + '__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path']) + +nm = shutil.which ('nm') +if not nm: + print ('check-symbols.py: \'nm\' not found; skipping test') + sys.exit (77) + +cxxflit = shutil.which ('c++filt') + +tested = False +stat = 0 + +for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']: + for suffix in ['so', 'dylib']: + so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix)) + if not os.path.exists (so): continue + + # On macOS, C symbols are prefixed with _ + symprefix = '_' if suffix == 'dylib' else '' + + EXPORTED_SYMBOLS = [s.split ()[2] + for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output ([nm, so]).decode ('utf-8'), re.MULTILINE) + if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)] + + # run again c++flit also if is available + if cxxflit: + EXPORTED_SYMBOLS = subprocess.check_output ( + [cxxflit], input='\n'.join (EXPORTED_SYMBOLS).encode () + ).decode ('utf-8').splitlines () + + prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0] + + print ('Checking that %s does not expose internal symbols' % so) + suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)] + if suspicious_symbols: + print ('Ouch, internal symbols exposed:', suspicious_symbols) + stat = 1 + + def_path = os.path.join (builddir, soname + '.def') + if not os.path.exists (def_path): + print ('\'%s\' not found; skipping' % def_path) + else: + print ('Checking that %s has the same symbol list as %s' % (so, def_path)) + with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read () + diff_result = list (difflib.context_diff ( + def_file.splitlines (), + ['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] + + # cheat: copy the last line from the def file! + [def_file.splitlines ()[-1]] + )) + + if diff_result: + print ('\n'.join (diff_result)) + stat = 1 + + tested = True + +if not tested: + print ('check-symbols.sh: no shared libraries found; skipping test') + sys.exit (77) + +sys.exit (stat) diff --git a/src/check-symbols.sh b/src/check-symbols.sh deleted file mode 100755 index f181b63121235c7d28bcb843473c7e6d7dceff5d..0000000000000000000000000000000000000000 --- a/src/check-symbols.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -LC_ALL=C -export LC_ALL - -test -z "$srcdir" && srcdir=. -test -z "$libs" && libs=.libs -stat=0 - -IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_.*\|llvm_.*' - -if which nm 2>/dev/null >/dev/null; then - : -else - echo "check-symbols.sh: 'nm' not found; skipping test" - exit 77 -fi - -tested=false -for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do - for suffix in so dylib; do - so=$libs/lib$soname.$suffix - if ! test -f "$so"; then continue; fi - - # On macOS, C symbols are prefixed with _ - symprefix= - if test $suffix = dylib; then symprefix=_; fi - - EXPORTED_SYMBOLS=`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt` - - prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'` - - echo "Checking that $so does not expose internal symbols" - if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}\(_\|$\)"; then - echo "Ouch, internal symbols exposed" - stat=1 - fi - - def=$soname.def - if ! test -f "$def"; then - echo "'$def' not found; skipping" - else - echo "Checking that $so has the same symbol list as $def" - { - echo EXPORTS - echo "$EXPORTED_SYMBOLS" | sed -e "s/^${symprefix}hb/hb/g" - # cheat: copy the last line from the def file! - tail -n1 "$def" - } | c++filt | diff "$def" - >&2 || stat=1 - fi - - tested=true - done -done -if ! $tested; then - echo "check-symbols.sh: no shared libraries found; skipping test" - exit 77 -fi - -exit $stat diff --git a/src/dump-indic-data.cc b/src/failing-alloc.c similarity index 56% rename from src/dump-indic-data.cc rename to src/failing-alloc.c index 8ddc9d5a4ef2c33a694405534cceccf872e7ba06..1bf18cd672d38b36cf5314bcf62c9c404e0fb4c1 100644 --- a/src/dump-indic-data.cc +++ b/src/failing-alloc.c @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Google, Inc. + * Copyright © 2020 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -20,24 +20,38 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-indic.hh" +#include +#include + +int alloc_state = 0; + +__attribute__((no_sanitize("integer"))) +static int fastrand () +{ + if (!alloc_state) return 1; + /* Based on https://software.intel.com/content/www/us/en/develop/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor.html */ + alloc_state = (214013 * alloc_state + 2531011); + return (alloc_state >> 16) & 0x7FFF; +} + +void* hb_malloc_impl (size_t size) +{ + return (fastrand () % 16) ? malloc (size) : NULL; +} + +void* hb_calloc_impl (size_t nmemb, size_t size) +{ + return (fastrand () % 16) ? calloc (nmemb, size) : NULL; +} + +void* hb_realloc_impl (void *ptr, size_t size) +{ + return (fastrand () % 16) ? realloc (ptr, size) : NULL; +} -int -main () +void hb_free_impl (void *ptr) { - for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) - { - hb_glyph_info_t info; - info.codepoint = u; - set_indic_properties (info); - if (info.indic_category() != INDIC_SYLLABIC_CATEGORY_OTHER || - info.indic_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE) - printf("U+%04X %u %u\n", u, - info.indic_category(), - info.indic_position()); - } + return free (ptr); } diff --git a/src/fix_get_types.py b/src/fix_get_types.py new file mode 100644 index 0000000000000000000000000000000000000000..208b9dfcd613d30748873ab7d475239bcb1858ea --- /dev/null +++ b/src/fix_get_types.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +import re +import argparse + +parser = argparse.ArgumentParser () +parser.add_argument ('input') +parser.add_argument ('output') +args = parser.parse_args () + +with open (args.input, 'r') as inp, open (args.output, 'w') as out: + for l in inp.readlines (): + l = re.sub ('_t_get_type', '_get_type', l) + l = re.sub ('_T \(', ' (', l) + out.write (l) diff --git a/src/gen-arabic-joining-list.py b/src/gen-arabic-joining-list.py new file mode 100644 index 0000000000000000000000000000000000000000..8162a4a3e268fa084032cec5f563dddb7e091262 --- /dev/null +++ b/src/gen-arabic-joining-list.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +"""usage: ./gen-arabic-joining-table.py ArabicShaping.txt Scripts.txt + +Input files: +* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt +* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt +""" + +import os.path, sys + +if len (sys.argv) != 3: + sys.exit (__doc__) + +files = [open (x, encoding='utf-8') for x in sys.argv[1:]] + +headers = [[f.readline (), f.readline ()] for f in files] +while files[0].readline ().find ('##################') < 0: + pass + +def read (f): + mapping = {} + for line in f: + + j = line.find ('#') + if j >= 0: + line = line[:j] + + fields = [x.strip () for x in line.split (';')] + if len (fields) == 1: + continue + + uu = fields[0].split ('..') + start = int (uu[0], 16) + if len (uu) == 1: + end = start + else: + end = int (uu[1], 16) + + t = fields[1] + + for u in range (start, end + 1): + mapping[u] = t + + return mapping + +def read_joining_uu (f): + values = set () + for line in f: + + if line[0] == '#': + continue + + fields = [x.strip () for x in line.split (';')] + if len (fields) == 1: + continue + if fields[2] in {'T', 'U'}: + continue + + values.add (int (fields[0], 16)) + + return sorted (values) + +def print_has_arabic_joining (scripts, joining_uu): + + print ("static bool") + print ("has_arabic_joining (hb_script_t script)") + print ("{") + print (" /* List of scripts that have data in arabic-table. */") + print (" switch ((int) script)") + print (" {") + + for script in sorted ({scripts[u] for u in joining_uu if scripts[u] not in {'Common', 'Inherited'}}): + print (" case HB_SCRIPT_{}:".format (script.upper ())) + + print (" return true;") + print () + print (" default:") + print (" return false;") + print (" }") + print ("}") + print () + +print ("/* == Start of generated function == */") +print ("/*") +print (" * The following function is generated by running:") +print (" *") +print (" * ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt") +print (" *") +print (" * on files with these headers:") +print (" *") +for h in headers: + for l in h: + print (" * %s" % (l.strip ())) +print (" */") +print () +print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH") +print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH") +print () + +print_has_arabic_joining (read (files[1]), read_joining_uu (files[0])) + +print () +print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */") +print () +print ("/* == End of generated function == */") diff --git a/src/gen-arabic-table.py b/src/gen-arabic-table.py index ccecb406a0b9b06ff497093d476a6e73e3daf4c8..621d5b60c89ee303ae4350a1a279d73be57ac9ed 100755 --- a/src/gen-arabic-table.py +++ b/src/gen-arabic-table.py @@ -1,14 +1,19 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import +"""usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt -import io, os.path, sys +Input files: +* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt +* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt +* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt +""" + +import os.path, sys if len (sys.argv) != 4: - print ("usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt", file=sys.stderr) - sys.exit (1) + sys.exit (__doc__) -files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]] +files = [open (x, encoding='utf-8') for x in sys.argv[1:]] headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]] headers.append (["UnicodeData.txt does not have a header."]) @@ -61,7 +66,7 @@ def print_joining_table(f): values[u] = value short_value = {} - for value in set([v for v in values.values()] + ['JOINING_TYPE_X']): + for value in sorted (set ([v for v in values.values ()] + ['JOINING_TYPE_X'])): short = ''.join(x[0] for x in value.split('_')[2:]) assert short not in short_value.values() short_value[value] = short @@ -122,7 +127,7 @@ def print_joining_table(f): print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)) print () - page_bits = 12; + page_bits = 12 print () print ("static unsigned int") print ("joining_type (hb_codepoint_t u)") @@ -176,7 +181,6 @@ def print_shaping_table(f): if items not in ligatures: ligatures[items] = {} ligatures[items][shape] = c - pass else: # Save shape if items[0] not in names: diff --git a/src/gen-def.py b/src/gen-def.py index 9111c698c36524a1cb261a96a422d4dacb71d635..aa6dcd95fbb5e9130ea45b078d3eea6cf00bb886 100755 --- a/src/gen-def.py +++ b/src/gen-def.py @@ -1,11 +1,11 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import +"usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]" -import io, os, re, sys +import os, re, sys if len (sys.argv) < 3: - sys.exit("usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]") + sys.exit(__doc__) output_file = sys.argv[1] header_paths = sys.argv[2:] @@ -13,12 +13,36 @@ header_paths = sys.argv[2:] headers_content = [] for h in header_paths: if h.endswith (".h"): - with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ()) - -symbols = "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))) - -result = symbols if os.environ.get('PLAIN_LIST', '') else """EXPORTS + with open (h, encoding='utf-8') as f: headers_content.append (f.read ()) + +symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M)) +if '--experimental-api' not in sys.argv: + # Move these to harfbuzz-sections.txt when got stable + experimental_symbols = \ +"""hb_font_draw_glyph +hb_draw_funcs_t +hb_draw_close_path_func_t +hb_draw_cubic_to_func_t +hb_draw_line_to_func_t +hb_draw_move_to_func_t +hb_draw_quadratic_to_func_t +hb_draw_funcs_create +hb_draw_funcs_destroy +hb_draw_funcs_is_immutable +hb_draw_funcs_make_immutable +hb_draw_funcs_reference +hb_draw_funcs_set_close_path_func +hb_draw_funcs_set_cubic_to_func +hb_draw_funcs_set_line_to_func +hb_draw_funcs_set_move_to_func +hb_draw_funcs_set_quadratic_to_func +hb_style_get_value +hb_font_get_var_coords_design""".splitlines () + symbols = [x for x in symbols if x not in experimental_symbols] +symbols = "\n".join (symbols) + +result = symbols if os.getenv ('PLAIN_LIST', '') else """EXPORTS %s -LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('.def', '')) +LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('src/', '').replace ('.def', '')) with open (output_file, "w") as f: f.write (result) diff --git a/src/gen-emoji-table.py b/src/gen-emoji-table.py index 49770d4fd8b6d0145138837a11039f348ed9e4c9..551bc9c7ced7c02d34b591253d2acff649c83227 100755 --- a/src/gen-emoji-table.py +++ b/src/gen-emoji-table.py @@ -1,14 +1,17 @@ -#!/usr/bin/python +#!/usr/bin/env python3 + +"""usage: ./gen-emoji-table.py emoji-data.txt + +Input file: +* https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt +""" -from __future__ import print_function, division, absolute_import import sys -import os.path from collections import OrderedDict import packTab if len (sys.argv) != 2: - print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr) - sys.exit (1) + sys.exit (__doc__) f = open(sys.argv[1]) header = [f.readline () for _ in range(10)] diff --git a/src/gen-harfbuzzcc.py b/src/gen-harfbuzzcc.py new file mode 100644 index 0000000000000000000000000000000000000000..b25bcc7abb9dacc86d8186f287ffb4e67486acee --- /dev/null +++ b/src/gen-harfbuzzcc.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +"This tool is intended to be used from meson" + +import os, sys, shutil + +if len (sys.argv) < 3: + sys.exit (__doc__) + +OUTPUT = sys.argv[1] +CURRENT_SOURCE_DIR = sys.argv[2] +sources = sys.argv[3:] + +with open (OUTPUT, "wb") as f: + f.write ("".join ('#include "{}"\n'.format (os.path.basename (x)) for x in sources if x.endswith (".cc")).encode ()) + +# copy it also to src/ +shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))) diff --git a/src/gen-hb-version.py b/src/gen-hb-version.py new file mode 100644 index 0000000000000000000000000000000000000000..879811ffc834f4a33bce832298de21524bf7d483 --- /dev/null +++ b/src/gen-hb-version.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +"This tool is intended to be used from meson" + +import os, sys, shutil, re + +if len (sys.argv) < 4: + sys.exit(__doc__) + +version = sys.argv[1] +major, minor, micro = version.split (".") + +OUTPUT = sys.argv[2] +INPUT = sys.argv[3] +CURRENT_SOURCE_DIR = os.path.dirname(INPUT) + +try: + with open (OUTPUT, "r") as old_output: + for line in old_output: + old_version = re.match (r"#define HB_VERSION_STRING \"(\d.\d.\d)\"", line) + if old_version and old_version[1] == version: + sys.exit () +except IOError: + pass + +with open (INPUT, "r", encoding='utf-8') as template: + with open (OUTPUT, "wb") as output: + output.write (template.read () + .replace ("@HB_VERSION_MAJOR@", major) + .replace ("@HB_VERSION_MINOR@", minor) + .replace ("@HB_VERSION_MICRO@", micro) + .replace ("@HB_VERSION@", version) + .encode ()) + +# copy it also to src/ +shutil.copyfile (OUTPUT, os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))) diff --git a/src/gen-indic-table.py b/src/gen-indic-table.py index cdf81fe75247b51fd6e31a25f3b8b9d667fa4522..367e55e272367a57ce25c1ff1c44733056457bdb 100755 --- a/src/gen-indic-table.py +++ b/src/gen-indic-table.py @@ -1,12 +1,17 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import +"""usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt -import io, sys +Input files: +* https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt +* https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt +* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt +""" + +import sys if len (sys.argv) != 4: - print ("usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt", file=sys.stderr) - sys.exit (1) + sys.exit (__doc__) ALLOWED_SINGLES = [0x00A0, 0x25CC] ALLOWED_BLOCKS = [ @@ -32,12 +37,12 @@ ALLOWED_BLOCKS = [ 'Myanmar Extended-A', ] -files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]] +files = [open (x, encoding='utf-8') for x in sys.argv[1:]] headers = [[f.readline () for i in range (2)] for f in files] -data = [{} for f in files] -values = [{} for f in files] +data = [{} for _ in files] +values = [{} for _ in files] for i, f in enumerate (files): for line in f: @@ -77,7 +82,6 @@ for i,d in enumerate (data): combined = {k:v for k,v in combined.items() if k in ALLOWED_SINGLES or v[2] in ALLOWED_BLOCKS} data = combined del combined -num = len (data) # Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out singles = {} @@ -133,8 +137,8 @@ what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"] what_short = ["ISC", "IMC"] print ('#pragma GCC diagnostic push') print ('#pragma GCC diagnostic ignored "-Wunused-macros"') +cat_defs = [] for i in range (2): - print () vv = sorted (values[i].keys ()) for v in vv: v_no_and = v.replace ('_And_', '_') @@ -146,10 +150,17 @@ for i in range (2): raise Exception ("Duplicate short value alias", v, all_shorts[i][s]) all_shorts[i][s] = v short[i][v] = s - print ("#define %s_%s %s_%s %s/* %3d chars; %s */" % - (what_short[i], s, what[i], v.upper (), - ' '* ((48-1 - len (what[i]) - 1 - len (v)) // 8), - values[i][v], v)) + cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + v.upper (), str (values[i][v]), v)) + +maxlen_s = max ([len (c[0]) for c in cat_defs]) +maxlen_l = max ([len (c[1]) for c in cat_defs]) +maxlen_n = max ([len (c[2]) for c in cat_defs]) +for s in what_short: + print () + for c in [c for c in cat_defs if s in c[0]]: + print ("#define %s %s /* %s chars; %s */" % + (c[0].ljust (maxlen_s), c[1].ljust (maxlen_l), c[2].rjust (maxlen_n), c[3])) +print () print ('#pragma GCC diagnostic pop') print () print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)") @@ -189,7 +200,7 @@ num = 0 offset = 0 starts = [] ends = [] -print ("static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = {") +print ("static const uint16_t indic_table[] = {") for u in uu: if u <= last: continue @@ -204,7 +215,6 @@ for u in uu: if start != last + 1: if start - last <= 1+16*3: print_block (None, last+1, start-1, data) - last = start-1 else: if last >= 0: ends.append (last + 1) @@ -224,7 +234,7 @@ occupancy = used * 100. / total page_bits = 12 print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)) print () -print ("INDIC_TABLE_ELEMENT_TYPE") +print ("uint16_t") print ("hb_indic_get_categories (hb_codepoint_t u)") print ("{") print (" switch (u >> %d)" % page_bits) @@ -249,14 +259,14 @@ print ("}") print () print ("#undef _") for i in range (2): - print + print () vv = sorted (values[i].keys ()) for v in vv: print ("#undef %s_%s" % (what_short[i], short[i][v])) print () -print () print ('#endif') +print () print ("/* == End of generated table == */") # Maintain at least 30% occupancy in the table */ diff --git a/src/gen-os2-unicode-ranges.py b/src/gen-os2-unicode-ranges.py index 515f4ca1492712f7e30bf7f7befd9d54cdee1bba..21aa1b9c000d4df7d1dd628f3c8e071878d6b94b 100755 --- a/src/gen-os2-unicode-ranges.py +++ b/src/gen-os2-unicode-ranges.py @@ -1,22 +1,13 @@ -#!/usr/bin/python +#!/usr/bin/env python3 -# -*- coding: utf-8 -*- +"""Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh +Input is a tab seperated list of unicode ranges from the otspec +(https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur). +""" -# Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh -# Input is a tab seperated list of unicode ranges from the otspec -# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur). - -from __future__ import print_function, division, absolute_import - -import io import re import sys -try: - reload(sys) - sys.setdefaultencoding('utf-8') -except NameError: - pass # Python 3 print ("""static OS2Range _hb_os2_unicode_ranges[] = {""") @@ -24,9 +15,9 @@ print ("""static OS2Range _hb_os2_unicode_ranges[] = args = sys.argv[1:] input_file = args[0] -with io.open(input_file, mode="r", encoding="utf-8") as f: +with open (input_file, mode="r", encoding="utf-8") as f: - all_ranges = []; + all_ranges = [] current_bit = 0 while True: line = f.readline().strip() diff --git a/src/gen-ragel-artifacts.py b/src/gen-ragel-artifacts.py new file mode 100644 index 0000000000000000000000000000000000000000..b60ec3bff58f38be1c49f8ce042e81131e8effe9 --- /dev/null +++ b/src/gen-ragel-artifacts.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +"This tool is intended to be used from meson" + +import os, os.path, sys, subprocess, shutil + +ragel = shutil.which ('ragel') +if not ragel: + sys.exit ('You have to install ragel if you are going to develop HarfBuzz itself') + +if len (sys.argv) < 4: + sys.exit (__doc__) + +OUTPUT = sys.argv[1] +CURRENT_SOURCE_DIR = sys.argv[2] +INPUT = sys.argv[3] + +outdir = os.path.dirname (OUTPUT) +shutil.copy (INPUT, outdir) +rl = os.path.basename (INPUT) +hh = rl.replace ('.rl', '.hh') +subprocess.Popen ([ragel, '-e', '-F1', '-o', hh, rl], cwd=outdir).wait () + +# copy it also to src/ +shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh)) diff --git a/src/gen-tag-table.py b/src/gen-tag-table.py index 49f5b30bbe5863a0aac551c827c50d74c26f2b2d..d1b5d4342eca404eb6ffe1572c066f28548d1cd4 100755 --- a/src/gen-tag-table.py +++ b/src/gen-tag-table.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 """Generator of the mapping from OpenType tags to BCP 47 tags and vice versa. @@ -16,37 +16,24 @@ back to BCP 47 tags. Ambiguous OpenType tags (those that correspond to multiple BCP 47 tags) are listed here, except when the alphabetically first BCP 47 tag happens to be the chosen disambiguated tag. In that case, the fallback behavior will choose the right tag anyway. -""" -from __future__ import absolute_import, division, print_function, unicode_literals +usage: ./gen-tag-table.py languagetags language-subtag-registry + +Input files: +* https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags +* https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry +""" import collections -try: - from HTMLParser import HTMLParser - def write (s): - print (s.encode ('utf-8'), end='') -except ImportError: - from html.parser import HTMLParser - def write (s): - sys.stdout.flush () - sys.stdout.buffer.write (s.encode ('utf-8')) -import io +import html +from html.parser import HTMLParser import itertools import re import sys import unicodedata if len (sys.argv) != 3: - print ('usage: ./gen-tag-table.py languagetags language-subtag-registry', file=sys.stderr) - sys.exit (1) - -try: - from html import unescape - def html_unescape (parser, entity): - return unescape (entity) -except ImportError: - def html_unescape (parser, entity): - return parser.unescape (entity) + sys.exit (__doc__) def expect (condition, message=None): if not condition: @@ -54,7 +41,13 @@ def expect (condition, message=None): raise AssertionError raise AssertionError (message) -# from http://www-01.sil.org/iso639-3/iso-639-3.tab +def write (s): + sys.stdout.flush () + sys.stdout.buffer.write (s.encode ('utf-8')) + +DEFAULT_LANGUAGE_SYSTEM = '' + +# from https://www-01.sil.org/iso639-3/iso-639-3.tab ISO_639_3_TO_1 = { 'aar': 'aa', 'abk': 'ab', @@ -388,10 +381,10 @@ class OpenTypeRegistryParser (HTMLParser): self._current_tr[-1] += data def handle_charref (self, name): - self.handle_data (html_unescape (self, '&#%s;' % name)) + self.handle_data (html.unescape ('&#%s;' % name)) def handle_entityref (self, name): - self.handle_data (html_unescape (self, '&%s;' % name)) + self.handle_data (html.unescape ('&%s;' % name)) def parse (self, filename): """Parse the OpenType language system tag registry. @@ -399,7 +392,7 @@ class OpenTypeRegistryParser (HTMLParser): Args: filename (str): The file name of the registry. """ - with io.open (filename, encoding='utf-8') as f: + with open (filename, encoding='utf-8') as f: self.feed (f.read ()) expect (self.header) for tag, iso_codes in self.to_bcp_47.items (): @@ -475,11 +468,8 @@ class OpenTypeRegistryParser (HTMLParser): if ot_macrolanguages: for ot_macrolanguage in ot_macrolanguages: for language in languages: - # Remove the following condition if e.g. nn should map to NYN,NOR - # instead of just NYN. - if language not in original_ot_from_bcp_47: - self.add_language (language, ot_macrolanguage) - self.ranks[ot_macrolanguage] += 1 + self.add_language (language, ot_macrolanguage) + self.ranks[ot_macrolanguage] += 1 else: for language in languages: if language in original_ot_from_bcp_47: @@ -541,7 +531,7 @@ class BCP47Parser (object): Args: filename (str): The file name of the registry. """ - with io.open (filename, encoding='utf-8') as f: + with open (filename, encoding='utf-8') as f: subtag_type = None subtag = None deprecated = False @@ -563,7 +553,7 @@ class BCP47Parser (object): self.grandfathered.add (subtag.lower ()) elif line.startswith ('Description: '): description = line.split (' ', 1)[1].replace (' (individual language)', '') - description = re.sub (' (\((individual |macro)language\)|languages)$', '', + description = re.sub (' (\(family\)|\((individual |macro)language\)|languages)$', '', description) if subtag in self.names: self.names[subtag] += '\n' + description @@ -598,7 +588,9 @@ class BCP47Parser (object): elif not has_preferred_value and line.startswith ('Macrolanguage: '): self._add_macrolanguage (line.split (' ')[1], subtag) elif subtag_type == 'variant': - if line.startswith ('Prefix: '): + if line.startswith ('Deprecated: '): + self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '') + elif line.startswith ('Prefix: '): self.prefixes[subtag].add (line.split (' ')[1]) elif line.startswith ('File-Date: '): self.header = line @@ -629,6 +621,17 @@ class BCP47Parser (object): for macrolanguage in macrolanguages: self._add_macrolanguage (biggest_macrolanguage, macrolanguage) + def _get_name_piece (self, subtag): + """Return the first name of a subtag plus its scope suffix. + + Args: + subtag (str): A BCP 47 subtag. + + Returns: + The name form of ``subtag``. + """ + return self.names[subtag].split ('\n')[0] + self.scopes.get (subtag, '') + def get_name (self, lt): """Return the names of the subtags in a language tag. @@ -638,13 +641,13 @@ class BCP47Parser (object): Returns: The name form of ``lt``. """ - name = self.names[lt.language].split ('\n')[0] + name = self._get_name_piece (lt.language) if lt.script: - name += '; ' + self.names[lt.script.title ()].split ('\n')[0] + name += '; ' + self._get_name_piece (lt.script.title ()) if lt.region: - name += '; ' + self.names[lt.region.upper ()].split ('\n')[0] + name += '; ' + self._get_name_piece (lt.region.upper ()) if lt.variant: - name += '; ' + self.names[lt.variant].split ('\n')[0] + name += '; ' + self._get_name_piece (lt.variant) return name bcp_47 = BCP47Parser () @@ -680,22 +683,18 @@ ot.add_language ('und-fonnapa', 'APPH') ot.remove_language_ot ('IRT') ot.add_language ('ga-Latg', 'IRT') +ot.add_language ('hy-arevmda', 'HYE') + ot.remove_language_ot ('KGE') ot.add_language ('und-Geok', 'KGE') -ot.add_language ('guk', 'GUK') -ot.names['GUK'] = 'Gumuz (SIL fonts)' -ot.ranks['GUK'] = ot.ranks['GMZ'] + 1 - bcp_47.macrolanguages['id'] = {'in'} bcp_47.macrolanguages['ijo'] = {'ijc'} ot.add_language ('kht', 'KHN') ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)' -ot.names['KHT'] = ot.names['KHT'] + ' (OpenType spec and SIL fonts)' -ot.ranks['KHN'] = ot.ranks['KHT'] -ot.ranks['KHT'] += 1 +ot.ranks['KHN'] = ot.ranks['KHT'] + 1 ot.ranks['LCR'] = ot.ranks['MCR'] + 1 @@ -713,6 +712,7 @@ ot.add_language ('qu', 'QUZ') ot.add_language ('qub', 'QWH') ot.add_language ('qud', 'QVI') ot.add_language ('qug', 'QVI') +ot.add_language ('qul', 'QUH') ot.add_language ('qup', 'QVI') ot.add_language ('qur', 'QWH') ot.add_language ('qus', 'QUH') @@ -743,10 +743,6 @@ ot.add_language ('qxw', 'QWH') bcp_47.macrolanguages['ro'].remove ('mo') bcp_47.macrolanguages['ro-MD'].add ('mo') -ot.add_language ('sgw', 'SGW') -ot.names['SGW'] = ot.names['CHG'] + ' (SIL fonts)' -ot.ranks['SGW'] = ot.ranks['CHG'] + 1 - ot.remove_language_ot ('SYRE') ot.remove_language_ot ('SYRJ') ot.remove_language_ot ('SYRN') @@ -754,7 +750,7 @@ ot.add_language ('und-Syre', 'SYRE') ot.add_language ('und-Syrj', 'SYRJ') ot.add_language ('und-Syrn', 'SYRN') -bcp_47.names['xst'] = u"Silt'e" +bcp_47.names['xst'] = "Silt'e" bcp_47.scopes['xst'] = ' (retired code)' bcp_47.macrolanguages['xst'] = {'stv', 'wle'} @@ -763,14 +759,17 @@ ot.add_language ('xwo', 'TOD') ot.remove_language_ot ('ZHH') ot.remove_language_ot ('ZHP') ot.remove_language_ot ('ZHT') +ot.remove_language_ot ('ZHTM') bcp_47.macrolanguages['zh'].remove ('lzh') bcp_47.macrolanguages['zh'].remove ('yue') ot.add_language ('zh-Hant-MO', 'ZHH') +ot.add_language ('zh-Hant-MO', 'ZHTM') ot.add_language ('zh-Hant-HK', 'ZHH') ot.add_language ('zh-Hans', 'ZHS') ot.add_language ('zh-Hant', 'ZHT') ot.add_language ('zh-HK', 'ZHH') ot.add_language ('zh-MO', 'ZHH') +ot.add_language ('zh-MO', 'ZHTM') ot.add_language ('zh-TW', 'ZHT') ot.add_language ('lzh', 'ZHT') ot.add_language ('lzh-Hans', 'ZHS') @@ -802,6 +801,7 @@ def rank_delta (bcp_47, ot): disambiguation = { 'ALT': 'alt', 'ARK': 'rki', + 'ATH': 'ath', 'BHI': 'bhb', 'BLN': 'bjt', 'BTI': 'beb', @@ -813,7 +813,9 @@ disambiguation = { 'ECR': 'crj', 'HAL': 'cfm', 'HND': 'hnd', + 'HYE': 'hyw', 'KIS': 'kqs', + 'KUI': 'uki', 'LRC': 'bqi', 'NDB': 'nd', 'NIS': 'njz', @@ -824,15 +826,24 @@ disambiguation = { 'QVI': 'qvi', 'QWH': 'qwh', 'SIG': 'stv', - 'TNE': 'yrk', + 'SRB': 'sr', + 'SXT': 'xnj', 'ZHH': 'zh-HK', 'ZHS': 'zh-Hans', 'ZHT': 'zh-Hant', + 'ZHTM': 'zh-MO', } ot.inherit_from_macrolanguages () bcp_47.remove_extra_macrolanguages () ot.inherit_from_macrolanguages () +ot.names[DEFAULT_LANGUAGE_SYSTEM] = '*/' +ot.ranks[DEFAULT_LANGUAGE_SYSTEM] = max (ot.ranks.values ()) + 1 +for tricky_ot_tag in filter (lambda tag: re.match ('[A-Z]{3}$', tag), ot.names): + possible_bcp_47_tag = tricky_ot_tag.lower () + if possible_bcp_47_tag in bcp_47.names and not ot.from_bcp_47[possible_bcp_47_tag]: + ot.add_language (possible_bcp_47_tag, DEFAULT_LANGUAGE_SYSTEM) + bcp_47.macrolanguages[possible_bcp_47_tag] = set () ot.sort_languages () print ('/* == Start of generated table == */') @@ -861,7 +872,9 @@ def hb_tag (tag): Returns: A snippet of C++ representing ``tag``. """ - return u"HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4]) + if tag == DEFAULT_LANGUAGE_SYSTEM: + return 'HB_TAG_NONE\t ' + return "HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4]) def get_variant_set (name): """Return a set of variant language names from a name. @@ -873,7 +886,7 @@ def get_variant_set (name): Returns: A set of normalized language names. """ - return set (unicodedata.normalize ('NFD', n.replace ('\u2019', u"'")) + return set (unicodedata.normalize ('NFD', n.replace ('\u2019', "'")) .encode ('ASCII', 'ignore') .strip () for n in re.split ('[\n(),]', name) if n) @@ -909,14 +922,18 @@ for language, tags in sorted (ot.from_bcp_47.items ()): print ('\t/* ', end='') bcp_47_name = bcp_47.names.get (language, '') bcp_47_name_candidates = bcp_47_name.split ('\n') - intersection = language_name_intersection (bcp_47_name, ot.names[tag]) + ot_name = ot.names[tag] scope = bcp_47.scopes.get (language, '') - if not intersection: - write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot.names[tag])) + if tag == DEFAULT_LANGUAGE_SYSTEM: + write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}') else: - name = get_matching_language_name (intersection, bcp_47_name_candidates) - bcp_47.names[language] = name - write ('%s%s' % (name if len (name) > len (ot.names[tag]) else ot.names[tag], scope)) + intersection = language_name_intersection (bcp_47_name, ot_name) + if not intersection: + write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name)) + else: + name = get_matching_language_name (intersection, bcp_47_name_candidates) + bcp_47.names[language] = name + write ('%s%s' % (name if len (name) > len (ot_name) else ot_name, scope)) print (' */') print ('};') @@ -998,22 +1015,24 @@ for initial, items in sorted (complex_tags.items ()): print (" case '%s':" % initial) for lt, tags in items: print (' if (', end='') + script = lt.script + region = lt.region if lt.grandfathered: print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='') else: string_literal = lt.language[1:] + '-' - if lt.script: - string_literal += lt.script - lt.script = None - if lt.region: - string_literal += '-' + lt.region - lt.region = None + if script: + string_literal += script + script = None + if region: + string_literal += '-' + region + region = None if string_literal[-1] == '-': print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='') else: print ('lang_matches (&lang_str[1], "%s")' % string_literal, end='') - print_subtag_matches (lt.script, True) - print_subtag_matches (lt.region, True) + print_subtag_matches (script, True) + print_subtag_matches (region, True) print_subtag_matches (lt.variant, True) print (')') print (' {') @@ -1080,11 +1099,18 @@ def verify_disambiguation_dict (): global disambiguation global ot for ot_tag, bcp_47_tags in ot.to_bcp_47.items (): - primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag) + if ot_tag == DEFAULT_LANGUAGE_SYSTEM: + primary_tags = [] + else: + primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag) if len (primary_tags) == 1: expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag) if '-' in primary_tags[0]: disambiguation[ot_tag] = primary_tags[0] + else: + first_tag = sorted (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot_tag in ot.from_bcp_47.get (t))[0] + if primary_tags[0] != first_tag: + disambiguation[ot_tag] = primary_tags[0] elif len (primary_tags) == 0: expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag) else: @@ -1099,8 +1125,8 @@ def verify_disambiguation_dict (): '%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag)) elif ot_tag not in disambiguation: disambiguation[ot_tag] = macrolanguages[0] - different_primary_tags = sorted (t for t in primary_tags if not same_tag (t, ot.from_bcp_47.get (t))) - if different_primary_tags and disambiguation[ot_tag] == different_primary_tags[0] and '-' not in disambiguation[ot_tag]: + different_bcp_47_tags = sorted (t for t in bcp_47_tags if not same_tag (t, ot.from_bcp_47.get (t))) + if different_bcp_47_tags and disambiguation[ot_tag] == different_bcp_47_tags[0] and '-' not in disambiguation[ot_tag]: del disambiguation[ot_tag] for ot_tag in disambiguation.keys (): expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag) diff --git a/src/gen-ucd-table.py b/src/gen-ucd-table.py index 552c3c675c17b850c5db3a05477000d661bf287f..35fba2d072903bb5ee0c22de0b3d526dd694708c 100755 --- a/src/gen-ucd-table.py +++ b/src/gen-ucd-table.py @@ -1,14 +1,17 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import +"""usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h] -import io, os.path, sys, re +Input file: +* https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip +""" + +import sys, re import logging logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) if len (sys.argv) not in (2, 3): - print("usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]", file=sys.stderr) - sys.exit(1) + sys.exit (__doc__) # https://github.com/harfbuzz/packtab import packTab diff --git a/src/gen-use-table.py b/src/gen-use-table.py index a8a03a77b8442f4447945e36081791f177756c7f..35d9abf1e44b33274d1aff7e5ee66fb7642f5721 100755 --- a/src/gen-use-table.py +++ b/src/gen-use-table.py @@ -1,27 +1,53 @@ -#!/usr/bin/env python -# flake8: noqa +#!/usr/bin/env python3 +# flake8: noqa: F821 -from __future__ import print_function, division, absolute_import +"""usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt ArabicShaping.txt Blocks.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt + +Input files: +* https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt +* https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt +* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt +* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt +* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt +* ms-use/IndicSyllabicCategory-Additional.txt +* ms-use/IndicPositionalCategory-Additional.txt +""" -import io import sys -if len (sys.argv) != 5: - print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr) - sys.exit (1) +if len (sys.argv) != 8: + sys.exit (__doc__) -BLACKLISTED_BLOCKS = ["Thai", "Lao"] +BLACKLISTED_BLOCKS = [ + 'Samaritan', + 'Thai', + 'Lao', +] -files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]] +files = [open (x, encoding='utf-8') for x in sys.argv[1:]] headers = [[f.readline () for i in range (2)] for j,f in enumerate(files) if j != 2] +for j in range(5, 7): + for line in files[j]: + line = line.rstrip() + if not line: + break + headers[j - 1].append(line) headers.append (["UnicodeData.txt does not have a header."]) -data = [{} for f in files] -values = [{} for f in files] +data = [{} for _ in files] +values = [{} for _ in files] for i, f in enumerate (files): + extended = False + for line in f: + # TODO: https://github.com/MicrosoftDocs/typography-issues/issues/522 + if extended and line.startswith ('# ') and line.find (';'): + line = line[2:] + elif 'USE_Syllabic_Category' in line: + extended = True + j = line.find ('#') if j >= 0: line = line[:j] @@ -37,16 +63,25 @@ for i, f in enumerate (files): else: end = int (uu[1], 16) - t = fields[1 if i != 2 else 2] + t = fields[1 if i not in [2, 3] else 2] + if i == 3: + t = 'jt_' + t + elif i == 5 and t == 'Consonant_Final_Modifier': + # TODO: https://github.com/MicrosoftDocs/typography-issues/issues/336 + t = 'Syllable_Modifier' + elif i == 6 and t == 'NA': + t = 'Not_Applicable' + + i0 = i if i < 5 else i - 5 for u in range (start, end + 1): - data[i][u] = t - values[i][t] = values[i].get (t, 0) + end - start + 1 + data[i0][u] = t + values[i0][t] = values[i0].get (t, 0) + end - start + 1 -defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block') +defaults = ('Other', 'Not_Applicable', 'Cn', 'jt_X', 'No_Block') # TODO Characters that are not in Unicode Indic files, but used in USE -data[0][0x034F] = defaults[0] +data[0][0x0640] = defaults[0] data[0][0x1B61] = defaults[0] data[0][0x1B63] = defaults[0] data[0][0x1B64] = defaults[0] @@ -56,6 +91,29 @@ data[0][0x1B67] = defaults[0] data[0][0x1B69] = defaults[0] data[0][0x1B6A] = defaults[0] data[0][0x2060] = defaults[0] +for u in range (0x07CA, 0x07EA + 1): + data[0][u] = defaults[0] +data[0][0x07FA] = defaults[0] +for u in range (0x0840, 0x0858 + 1): + data[0][u] = defaults[0] +for u in range (0x1887, 0x18A8 + 1): + data[0][u] = defaults[0] +data[0][0x18AA] = defaults[0] +for u in range (0xA840, 0xA872 + 1): + data[0][u] = defaults[0] +for u in range (0x10B80, 0x10B91 + 1): + data[0][u] = defaults[0] +for u in range (0x10BA9, 0x10BAE + 1): + data[0][u] = defaults[0] +data[0][0x10FB0] = defaults[0] +for u in range (0x10FB2, 0x10FB6 + 1): + data[0][u] = defaults[0] +for u in range (0x10FB8, 0x10FBF + 1): + data[0][u] = defaults[0] +for u in range (0x10FC1, 0x10FC4 + 1): + data[0][u] = defaults[0] +for u in range (0x10FC9, 0x10FCB + 1): + data[0][u] = defaults[0] # TODO https://github.com/harfbuzz/harfbuzz/pull/1685 data[0][0x1B5B] = 'Consonant_Placeholder' data[0][0x1B5C] = 'Consonant_Placeholder' @@ -67,8 +125,6 @@ data[0][0x11C44] = 'Consonant_Placeholder' data[0][0x11C45] = 'Consonant_Placeholder' # TODO https://github.com/harfbuzz/harfbuzz/pull/1399 data[0][0x111C8] = 'Consonant_Placeholder' -for u in range (0xFE00, 0xFE0F + 1): - data[0][u] = defaults[0] # Merge data into one dict: for i,v in enumerate (defaults): @@ -81,10 +137,9 @@ for i,d in enumerate (data): if not u in combined: combined[u] = list (defaults) combined[u][i] = v -combined = {k:v for k,v in combined.items() if v[3] not in BLACKLISTED_BLOCKS} +combined = {k:v for k,v in combined.items() if v[4] not in BLACKLISTED_BLOCKS} data = combined del combined -num = len (data) property_names = [ @@ -129,6 +184,10 @@ property_names = [ 'Number_Joiner', 'Number', 'Brahmi_Joining_Number', + 'Hieroglyph', + 'Hieroglyph_Joiner', + 'Hieroglyph_Segment_Begin', + 'Hieroglyph_Segment_End', # Indic_Positional_Category 'Not_Applicable', 'Right', @@ -138,6 +197,7 @@ property_names = [ 'Top', 'Bottom', 'Top_And_Bottom', + 'Top_And_Bottom_And_Left', 'Top_And_Right', 'Top_And_Left', 'Top_And_Left_And_Right', @@ -145,20 +205,23 @@ property_names = [ 'Bottom_And_Right', 'Top_And_Bottom_And_Right', 'Overstruck', + # Joining_Type + 'jt_C', + 'jt_D', + 'jt_L', + 'jt_R', + 'jt_T', + 'jt_U', + 'jt_X', ] -try: - basestring -except NameError: - basestring = str - class PropertyValue(object): def __init__(self, name_): self.name = name_ def __str__(self): return self.name def __eq__(self, other): - return self.name == (other if isinstance(other, basestring) else other.name) + return self.name == (other if isinstance(other, str) else other.name) def __ne__(self, other): return not (self == other) def __hash__(self): @@ -174,99 +237,86 @@ for name in property_names: globals().update(property_values) -def is_BASE(U, UISC, UGC): +def is_BASE(U, UISC, UGC, AJT): return (UISC in [Number, Consonant, Consonant_Head_Letter, - #SPEC-DRAFT Consonant_Placeholder, Tone_Letter, - Vowel_Independent #SPEC-DRAFT + Vowel_Independent, ] or + # TODO: https://github.com/MicrosoftDocs/typography-issues/issues/484 + AJT in [jt_C, jt_D, jt_L, jt_R] and UISC != Joiner or (UGC == Lo and UISC in [Avagraha, Bindu, Consonant_Final, Consonant_Medial, Consonant_Subjoined, Vowel, Vowel_Dependent])) -def is_BASE_IND(U, UISC, UGC): - #SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po) - return (UISC in [Consonant_Dead, Modifying_Letter] or - (UGC == Po and not U in [0x104B, 0x104E, 0x1B5B, 0x1B5C, 0x1B5F, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or - False # SPEC-DRAFT-OUTDATED! U == 0x002D - ) -def is_BASE_NUM(U, UISC, UGC): +def is_BASE_NUM(U, UISC, UGC, AJT): return UISC == Brahmi_Joining_Number -def is_BASE_OTHER(U, UISC, UGC): - if UISC == Consonant_Placeholder: return True #SPEC-DRAFT - #SPEC-DRAFT return U in [0x00A0, 0x00D7, 0x2015, 0x2022, 0x25CC, 0x25FB, 0x25FC, 0x25FD, 0x25FE] +def is_BASE_OTHER(U, UISC, UGC, AJT): + if UISC == Consonant_Placeholder: return True return U in [0x2015, 0x2022, 0x25FB, 0x25FC, 0x25FD, 0x25FE] -def is_CGJ(U, UISC, UGC): - return U == 0x034F -def is_CONS_FINAL(U, UISC, UGC): +def is_CONS_FINAL(U, UISC, UGC, AJT): return ((UISC == Consonant_Final and UGC != Lo) or UISC == Consonant_Succeeding_Repha) -def is_CONS_FINAL_MOD(U, UISC, UGC): - #SPEC-DRAFT return UISC in [Consonant_Final_Modifier, Syllable_Modifier] - return UISC == Syllable_Modifier -def is_CONS_MED(U, UISC, UGC): +def is_CONS_FINAL_MOD(U, UISC, UGC, AJT): + return UISC == Syllable_Modifier +def is_CONS_MED(U, UISC, UGC, AJT): # Consonant_Initial_Postfixed is new in Unicode 11; not in the spec. return (UISC == Consonant_Medial and UGC != Lo or UISC == Consonant_Initial_Postfixed) -def is_CONS_MOD(U, UISC, UGC): - return UISC in [Nukta, Gemination_Mark, Consonant_Killer] -def is_CONS_SUB(U, UISC, UGC): - #SPEC-DRAFT return UISC == Consonant_Subjoined +def is_CONS_MOD(U, UISC, UGC, AJT): + return (UISC in [Nukta, Gemination_Mark, Consonant_Killer] and + not is_SYM_MOD(U, UISC, UGC, AJT)) +def is_CONS_SUB(U, UISC, UGC, AJT): return UISC == Consonant_Subjoined and UGC != Lo -def is_CONS_WITH_STACKER(U, UISC, UGC): +def is_CONS_WITH_STACKER(U, UISC, UGC, AJT): return UISC == Consonant_With_Stacker -def is_HALANT(U, UISC, UGC): +def is_HALANT(U, UISC, UGC, AJT): return (UISC in [Virama, Invisible_Stacker] - and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC) - and not is_SAKOT(U, UISC, UGC)) -def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC): + and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC, AJT) + and not is_SAKOT(U, UISC, UGC, AJT)) +def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC, AJT): # https://github.com/harfbuzz/harfbuzz/issues/1102 # https://github.com/harfbuzz/harfbuzz/issues/1379 return U in [0x11046, 0x1134D] -def is_HALANT_NUM(U, UISC, UGC): +def is_HALANT_NUM(U, UISC, UGC, AJT): return UISC == Number_Joiner -def is_ZWNJ(U, UISC, UGC): +def is_HIEROGLYPH(U, UISC, UGC, AJT): + return UISC == Hieroglyph +def is_HIEROGLYPH_JOINER(U, UISC, UGC, AJT): + return UISC == Hieroglyph_Joiner +def is_HIEROGLYPH_SEGMENT_BEGIN(U, UISC, UGC, AJT): + return UISC == Hieroglyph_Segment_Begin +def is_HIEROGLYPH_SEGMENT_END(U, UISC, UGC, AJT): + return UISC == Hieroglyph_Segment_End +def is_ZWNJ(U, UISC, UGC, AJT): return UISC == Non_Joiner -def is_ZWJ(U, UISC, UGC): - return UISC == Joiner -def is_Word_Joiner(U, UISC, UGC): - return U == 0x2060 -def is_OTHER(U, UISC, UGC): - #SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters - return (UISC == Other - and not is_SYM(U, UISC, UGC) - and not is_SYM_MOD(U, UISC, UGC) - and not is_CGJ(U, UISC, UGC) - and not is_Word_Joiner(U, UISC, UGC) - and not is_VARIATION_SELECTOR(U, UISC, UGC) +def is_OTHER(U, UISC, UGC, AJT): + return ((UGC in [Cn, Po] or UISC in [Consonant_Dead, Joiner, Modifying_Letter, Other]) + and not is_BASE(U, UISC, UGC, AJT) + and not is_BASE_OTHER(U, UISC, UGC, AJT) + and not is_SYM(U, UISC, UGC, AJT) + and not is_SYM_MOD(U, UISC, UGC, AJT) ) -def is_Reserved(U, UISC, UGC): - return UGC == 'Cn' -def is_REPHA(U, UISC, UGC): +def is_REPHA(U, UISC, UGC, AJT): return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed] -def is_SAKOT(U, UISC, UGC): +def is_SAKOT(U, UISC, UGC, AJT): return U == 0x1A60 -def is_SYM(U, UISC, UGC): - if U == 0x25CC: return False #SPEC-DRAFT - #SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter - return UGC in [So, Sc] and U not in [0x1B62, 0x1B68] -def is_SYM_MOD(U, UISC, UGC): +def is_SYM(U, UISC, UGC, AJT): + if U in [0x25CC, 0x1E14F]: return False + return UGC in [So, Sc] and U not in [0x0F01, 0x1B62, 0x1B68] +def is_SYM_MOD(U, UISC, UGC, AJT): return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73] -def is_VARIATION_SELECTOR(U, UISC, UGC): - return 0xFE00 <= U <= 0xFE0F -def is_VOWEL(U, UISC, UGC): +def is_VOWEL(U, UISC, UGC, AJT): # https://github.com/harfbuzz/harfbuzz/issues/376 return (UISC == Pure_Killer or (UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29])) -def is_VOWEL_MOD(U, UISC, UGC): +def is_VOWEL_MOD(U, UISC, UGC, AJT): # https://github.com/harfbuzz/harfbuzz/issues/376 return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or (UGC != Lo and (UISC == Bindu or U in [0xAA29]))) +# CGJ, VS, WJ, and ZWJ are handled in find_syllables use_mapping = { 'B': is_BASE, - 'IND': is_BASE_IND, 'N': is_BASE_NUM, 'GB': is_BASE_OTHER, - 'CGJ': is_CGJ, 'F': is_CONS_FINAL, 'FM': is_CONS_FINAL_MOD, 'M': is_CONS_MED, @@ -276,16 +326,16 @@ use_mapping = { 'H': is_HALANT, 'HVM': is_HALANT_OR_VOWEL_MODIFIER, 'HN': is_HALANT_NUM, + 'G': is_HIEROGLYPH, + 'J': is_HIEROGLYPH_JOINER, + 'SB': is_HIEROGLYPH_SEGMENT_BEGIN, + 'SE': is_HIEROGLYPH_SEGMENT_END, 'ZWNJ': is_ZWNJ, - 'ZWJ': is_ZWJ, - 'WJ': is_Word_Joiner, 'O': is_OTHER, - 'Rsv': is_Reserved, 'R': is_REPHA, 'S': is_SYM, 'Sk': is_SAKOT, 'SM': is_SYM_MOD, - 'VS': is_VARIATION_SELECTOR, 'V': is_VOWEL, 'VM': is_VOWEL_MOD, } @@ -298,19 +348,19 @@ use_positions = { }, 'M': { 'Abv': [Top], - 'Blw': [Bottom, Bottom_And_Left], + 'Blw': [Bottom, Bottom_And_Left, Bottom_And_Right], 'Pst': [Right], - 'Pre': [Left], + 'Pre': [Left, Top_And_Bottom_And_Left], }, 'CM': { 'Abv': [Top], - 'Blw': [Bottom], + 'Blw': [Bottom, Overstruck], }, 'V': { 'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right], 'Blw': [Bottom, Overstruck, Bottom_And_Right], - 'Pst': [Right, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], - 'Pre': [Left], + 'Pst': [Right], + 'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right], }, 'VM': { 'Abv': [Top], @@ -330,36 +380,23 @@ use_positions = { 'Blw': [Bottom], 'Pst': [Not_Applicable], }, + 'R': None, 'SUB': None, } def map_to_use(data): out = {} items = use_mapping.items() - for U,(UISC,UIPC,UGC,UBlock) in data.items(): + for U,(UISC,UIPC,UGC,AJT,UBlock) in data.items(): # Resolve Indic_Syllabic_Category - # TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC + # TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark # Tibetan: - # TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC + # TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent - if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark - # Overrides to allow NFC order matching syllable - # https://github.com/harfbuzz/harfbuzz/issues/1012 - if UBlock == 'Tibetan' and is_VOWEL (U, UISC, UGC): - if UIPC == Top: - UIPC = Bottom - - # TODO: https://github.com/harfbuzz/harfbuzz/pull/982 - # also https://github.com/harfbuzz/harfbuzz/issues/1012 - if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC): - if UIPC == Top: - UIPC = Bottom - elif UIPC == Bottom: - UIPC = Top # TODO: https://github.com/harfbuzz/harfbuzz/pull/627 if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom @@ -368,36 +405,37 @@ def map_to_use(data): # the nasalization marks, maybe only for U+1CE9..U+1CF1. if U == 0x1CED: UISC = Tone_Mark - # TODO: https://github.com/harfbuzz/harfbuzz/issues/1105 - if U == 0x11134: UISC = Gemination_Mark + # TODO: https://github.com/microsoft/font-tools/issues/1 + if U == 0xA982: UISC = Consonant_Succeeding_Repha - values = [k for k,v in items if v(U,UISC,UGC)] - assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values) + values = [k for k,v in items if v(U,UISC,UGC,AJT)] + assert len(values) == 1, "%s %s %s %s %s" % (hex(U), UISC, UGC, AJT, values) USE = values[0] # Resolve Indic_Positional_Category - # TODO: These should die, but have UIPC in Unicode 12.0 + # TODO: These should die, but have UIPC in Unicode 13.0.0 if U in [0x953, 0x954]: UIPC = Not_Applicable - # TODO: In USE's override list but not in Unicode 12.0 - if U == 0x103C: UIPC = Left - - # TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0 + # TODO: These are not in USE's override list that we have, nor are they in Unicode 13.0.0 if 0xA926 <= U <= 0xA92A: UIPC = Top # TODO: https://github.com/harfbuzz/harfbuzz/pull/1037 # and https://github.com/harfbuzz/harfbuzz/issues/1631 if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top - if U == 0x1171E: UIPC = Left if 0x1CF8 <= U <= 0x1CF9: UIPC = Top - assert (UIPC in [Not_Applicable, Visual_Order_Left] or - USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC) + # TODO: https://github.com/harfbuzz/harfbuzz/pull/982 + # also https://github.com/harfbuzz/harfbuzz/issues/1012 + if 0x1112A <= U <= 0x1112B: UIPC = Top + if 0x11131 <= U <= 0x11132: UIPC = Top + + assert (UIPC in [Not_Applicable, Visual_Order_Left] or U == 0x0F7F or + USE in use_positions), "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, AJT) pos_mapping = use_positions.get(USE, None) if pos_mapping: values = [k for k,v in pos_mapping.items() if v and UIPC in v] - assert len(values) == 1, "%s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, values) + assert len(values) == 1, "%s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC, AJT, values) USE = USE + values[0] out[U] = (USE, UBlock) @@ -410,7 +448,7 @@ print ("/* == Start of generated table == */") print ("/*") print (" * The following table is generated by running:") print (" *") -print (" * ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt") +print (" * {} IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt ArabicShaping.txt Blocks.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt".format (sys.argv[0])) print (" *") print (" * on files with these headers:") print (" *") @@ -419,11 +457,12 @@ for h in headers: print (" * %s" % (l.strip())) print (" */") print () -print ('#include "hb.hh"') +print ("#ifndef HB_OT_SHAPE_COMPLEX_USE_TABLE_HH") +print ("#define HB_OT_SHAPE_COMPLEX_USE_TABLE_HH") print () -print ('#ifndef HB_NO_OT_SHAPE') +print ('#include "hb.hh"') print () -print ('#include "hb-ot-shape-complex-use.hh"') +print ('#include "hb-ot-shape-complex-use-machine.hh"') print () total = 0 @@ -465,18 +504,20 @@ print ('#pragma GCC diagnostic push') print ('#pragma GCC diagnostic ignored "-Wunused-macros"') for k,v in sorted(use_mapping.items()): if k in use_positions and use_positions[k]: continue - print ("#define %s USE_%s /* %s */" % (k, k, v.__name__[3:])) + print ("#define %s USE(%s) /* %s */" % (k, k, v.__name__[3:])) for k,v in sorted(use_positions.items()): if not v: continue for suf in v.keys(): tag = k + suf - print ("#define %s USE_%s" % (tag, tag)) + print ("#define %s USE(%s)" % (tag, tag)) print ('#pragma GCC diagnostic pop') print ("") -print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {") +print ("static const uint8_t use_table[] = {") for u in uu: if u <= last: continue + if data[u][0] == 'O': + continue block = data[u][1] start = u//8*8 @@ -488,7 +529,6 @@ for u in uu: if start != last + 1: if start - last <= 1+16*3: print_block (None, last+1, start-1, data) - last = start-1 else: if last >= 0: ends.append (last + 1) @@ -508,7 +548,7 @@ occupancy = used * 100. / total page_bits = 12 print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)) print () -print ("USE_TABLE_ELEMENT_TYPE") +print ("static inline uint8_t") print ("hb_use_get_category (hb_codepoint_t u)") print ("{") print (" switch (u >> %d)" % page_bits) @@ -525,7 +565,7 @@ for p in sorted(pages): print (" default:") print (" break;") print (" }") -print (" return USE_O;") +print (" return USE(O);") print ("}") print () for k in sorted(use_mapping.keys()): @@ -538,7 +578,7 @@ for k,v in sorted(use_positions.items()): print ("#undef %s" % tag) print () print () -print ('#endif') +print ("#endif /* HB_OT_SHAPE_COMPLEX_USE_TABLE_HH */") print ("/* == End of generated table == */") # Maintain at least 50% occupancy in the table */ diff --git a/src/gen-vowel-constraints.py b/src/gen-vowel-constraints.py index 8ca90c819cbe9dfda90f330665991148bd2da3f3..184ec29cf8b1043b34af28cc0d5a085b937418e9 100755 --- a/src/gen-vowel-constraints.py +++ b/src/gen-vowel-constraints.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 """Generator of the function to prohibit certain vowel sequences. @@ -6,29 +6,23 @@ It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted circles into sequences prohibited by the USE script development spec. This function should be used as the ``preprocess_text`` of an ``hb_ot_complex_shaper_t``. -""" -from __future__ import absolute_import, division, print_function, unicode_literals +usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt + +Input file: +* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt +""" import collections -try: - from HTMLParser import HTMLParser - def write (s): - print (s.encode ('utf-8'), end='') -except ImportError: - from html.parser import HTMLParser - def write (s): - sys.stdout.flush () - sys.stdout.buffer.write (s.encode ('utf-8')) -import itertools -import io +def write (s): + sys.stdout.flush () + sys.stdout.buffer.write (s.encode ('utf-8')) import sys if len (sys.argv) != 3: - print ('usage: ./gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt', file=sys.stderr) - sys.exit (1) + sys.exit (__doc__) -with io.open (sys.argv[2], encoding='utf-8') as f: +with open (sys.argv[2], encoding='utf-8') as f: scripts_header = [f.readline () for i in range (2)] scripts = {} script_order = {} @@ -84,7 +78,8 @@ class ConstraintSet (object): else: self._c[first] = ConstraintSet (rest) - def _indent (self, depth): + @staticmethod + def _indent (depth): return (' ' * depth).replace (' ', '\t') def __str__ (self, index=0, depth=4): @@ -92,19 +87,22 @@ class ConstraintSet (object): indent = self._indent (depth) if isinstance (self._c, list): if len (self._c) == 0: + assert index == 2, 'Cannot use `matched` for this constraint; the general case has not been implemented' s.append ('{}matched = true;\n'.format (indent)) elif len (self._c) == 1: + assert index == 1, 'Cannot use `matched` for this constraint; the general case has not been implemented' s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or '')) else: - s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index)) - s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), len (self._c))) + s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index or '')) + if index: + s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), index + 1)) for i, cp in enumerate (self._c[1:], start=1): s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format ( self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&')) s.append ('{}{{\n'.format (indent)) - for i in range (len (self._c)): - s.append ('{}buffer->next_glyph ();\n'.format (self._indent (depth + 1))) - s.append ('{}_output_dotted_circle (buffer);\n'.format (self._indent (depth + 1))) + for i in range (index): + s.append ('{}(void) buffer->next_glyph ();\n'.format (self._indent (depth + 1))) + s.append ('{}matched = true;\n'.format (self._indent (depth + 1))) s.append ('{}}}\n'.format (indent)) else: s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or '')) @@ -127,8 +125,13 @@ class ConstraintSet (object): return ''.join (s) constraints = {} -with io.open (sys.argv[1], encoding='utf-8') as f: - constraints_header = [f.readline ().strip () for i in range (2)] +with open (sys.argv[1], encoding='utf-8') as f: + constraints_header = [] + while True: + line = f.readline ().strip () + if line == '#': + break + constraints_header.append(line) for line in f: j = line.find ('#') if j >= 0: @@ -147,7 +150,7 @@ print ('/* == Start of generated functions == */') print ('/*') print (' * The following functions are generated by running:') print (' *') -print (' * %s use Scripts.txt' % sys.argv[0]) +print (' * %s ms-use/IndicShapingInvalidCluster.txt Scripts.txt' % sys.argv[0]) print (' *') print (' * on files with these headers:') print (' *') @@ -168,15 +171,15 @@ print () print ('static void') print ('_output_dotted_circle (hb_buffer_t *buffer)') print ('{') -print (' hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);') -print (' _hb_glyph_info_reset_continuation (&dottedcircle);') +print (' (void) buffer->output_glyph (0x25CCu);') +print (' _hb_glyph_info_reset_continuation (&buffer->prev());') print ('}') print () print ('static void') print ('_output_with_dotted_circle (hb_buffer_t *buffer)') print ('{') print (' _output_dotted_circle (buffer);') -print (' buffer->next_glyph ();') +print (' (void) buffer->next_glyph ();') print ('}') print () @@ -185,7 +188,7 @@ print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB print ('\t\t\t\t hb_buffer_t *buffer,') print ('\t\t\t\t hb_font_t *font HB_UNUSED)') print ('{') -print ('#if defined(HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS)') +print ('#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS') print (' return;') print ('#endif') print (' if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)') @@ -197,7 +200,6 @@ print (' * collected from the USE script development spec.') print (' *') print (' * https://github.com/harfbuzz/harfbuzz/issues/1019') print (' */') -print (' bool processed = false;') print (' buffer->clear_output ();') print (' unsigned int count = buffer->len;') print (' switch ((unsigned) buffer->props.script)') @@ -209,22 +211,16 @@ for script, constraints in sorted (constraints.items (), key=lambda s_c: script_ print (' {') print ('\tbool matched = false;') write (str (constraints)) - print ('\tbuffer->next_glyph ();') + print ('\t(void) buffer->next_glyph ();') print ('\tif (matched) _output_with_dotted_circle (buffer);') print (' }') - print (' processed = true;') print (' break;') print () print (' default:') print (' break;') print (' }') -print (' if (processed)') -print (' {') -print (' if (buffer->idx < count)') -print (' buffer->next_glyph ();') -print (' buffer->swap_buffers ();') -print (' }') +print (' buffer->swap_buffers ();') print ('}') print () diff --git a/src/harfbuzz.cc b/src/harfbuzz.cc index d338d1735cde2d66d98339de6850fee6456a39be..fe00100974ed365688fd0f0db004e1057a3f8b6c 100644 --- a/src/harfbuzz.cc +++ b/src/harfbuzz.cc @@ -4,10 +4,12 @@ #include "hb-buffer-serialize.cc" #include "hb-buffer.cc" #include "hb-common.cc" +#include "hb-draw.cc" #include "hb-face.cc" #include "hb-fallback-shape.cc" #include "hb-font.cc" #include "hb-map.cc" +#include "hb-number.cc" #include "hb-ot-cff1-table.cc" #include "hb-ot-cff2-table.cc" #include "hb-ot-color.cc" @@ -27,8 +29,8 @@ #include "hb-ot-shape-complex-indic.cc" #include "hb-ot-shape-complex-khmer.cc" #include "hb-ot-shape-complex-myanmar.cc" +#include "hb-ot-shape-complex-syllabic.cc" #include "hb-ot-shape-complex-thai.cc" -#include "hb-ot-shape-complex-use-table.cc" #include "hb-ot-shape-complex-use.cc" #include "hb-ot-shape-complex-vowel-constraints.cc" #include "hb-ot-shape-fallback.cc" @@ -41,9 +43,9 @@ #include "hb-shape.cc" #include "hb-shaper.cc" #include "hb-static.cc" +#include "hb-style.cc" #include "hb-ucd.cc" #include "hb-unicode.cc" -#include "hb-warning.cc" #include "hb-glib.cc" #include "hb-ft.cc" #include "hb-graphite2.cc" diff --git a/src/hb-aat-fdsc-table.hh b/src/hb-aat-fdsc-table.hh deleted file mode 100644 index 1188e352f03458f9bb05a5113585108a5e03c435..0000000000000000000000000000000000000000 --- a/src/hb-aat-fdsc-table.hh +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#ifndef HB_AAT_FDSC_TABLE_HH -#define HB_AAT_FDSC_TABLE_HH - -#include "hb-aat-layout-common.hh" -#include "hb-open-type.hh" - -/* - * fdsc -- Font descriptors - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html - */ -#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c') - - -namespace AAT { - - -struct FontDescriptor -{ - bool has_data () const { return tag; } - - int cmp (hb_tag_t a) const { return tag.cmp (a); } - - float get_value () const { return u.value.to_float (); } - - enum non_alphabetic_value_t { - Alphabetic = 0, - Dingbats = 1, - PiCharacters = 2, - Fleurons = 3, - DecorativeBorders = 4, - InternationalSymbols= 5, - MathSymbols = 6 - }; - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this)); - } - - protected: - Tag tag; /* The 4-byte table tag name. */ - union { - Fixed value; /* The value for the descriptor tag. */ - HBUINT32 nalfType; /* If the tag is `nalf`, see non_alphabetic_value_t */ - } u; - public: - DEFINE_SIZE_STATIC (8); -}; - -struct fdsc -{ - static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc; - - enum { - Weight = HB_TAG ('w','g','h','t'), - /* Percent weight relative to regular weight. - * (defaul value: 1.0) */ - Width = HB_TAG ('w','d','t','h'), - /* Percent width relative to regular width. - * (default value: 1.0) */ - Slant = HB_TAG ('s','l','n','t'), - /* Angle of slant in degrees, where positive - * is clockwise from straight up. - * (default value: 0.0) */ - OpticalSize = HB_TAG ('o','p','s','z'), - /* Point size the font was designed for. - * (default value: 12.0) */ - NonAlphabetic= HB_TAG ('n','a','l','f') - /* These values are treated as integers, - * not fixed32s. 0 means alphabetic, and greater - * integers mean the font is non-alphabetic (e.g. symbols). - * (default value: 0) */ - }; - - const FontDescriptor &get_descriptor (hb_tag_t style) const - { return descriptors.lsearch (style); } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && - descriptors.sanitize (c)); - } - - protected: - Fixed version; /* Version number of the font descriptors - * table (0x00010000 for the current version). */ - LArrayOf - descriptors; /* List of tagged-coordinate pairs style descriptors - * that will be included to characterize this font. - * Each descriptor consists of a pair. - * These pairs are located in the gxFontDescriptor - * array that follows. */ - public: - DEFINE_SIZE_ARRAY (8, descriptors); -}; - -} /* namespace AAT */ - - -#endif /* HB_AAT_FDSC_TABLE_HH */ diff --git a/src/hb-aat-layout-ankr-table.hh b/src/hb-aat-layout-ankr-table.hh index ef988841a94fe70e95233fe5fae824fb0c695ee3..63fac84524f336b5239c3898d5f523d2422c4a6c 100644 --- a/src/hb-aat-layout-ankr-table.hh +++ b/src/hb-aat-layout-ankr-table.hh @@ -54,7 +54,7 @@ struct Anchor DEFINE_SIZE_STATIC (4); }; -typedef LArrayOf GlyphAnchors; +typedef Array32Of GlyphAnchors; struct ankr { @@ -64,9 +64,9 @@ struct ankr unsigned int i, unsigned int num_glyphs) const { - const NNOffsetTo *offset = (this+lookupTable).get_value (glyph_id, num_glyphs); + const NNOffset16To *offset = (this+lookupTable).get_value (glyph_id, num_glyphs); if (!offset) - return Null(Anchor); + return Null (Anchor); const GlyphAnchors &anchors = &(this+anchorData) + *offset; return anchors[i]; } @@ -81,11 +81,11 @@ struct ankr } protected: - HBUINT16 version; /* Version number (set to zero) */ + HBUINT16 version; /* Version number (set to zero) */ HBUINT16 flags; /* Flags (currently unused; set to zero) */ - LOffsetTo>> + Offset32To>> lookupTable; /* Offset to the table's lookup table */ - LNNOffsetTo + NNOffset32To anchorData; /* Offset to the glyph data table */ public: diff --git a/src/hb-aat-layout-bsln-table.hh b/src/hb-aat-layout-bsln-table.hh index 9139d28183cb7b2971b9856176ec7bf446afd940..cd36fc895325edc83d58eef0643f00c1b726fdfe 100644 --- a/src/hb-aat-layout-bsln-table.hh +++ b/src/hb-aat-layout-bsln-table.hh @@ -82,7 +82,7 @@ struct BaselineTableFormat2Part } protected: - GlyphID stdGlyph; /* The specific glyph index number in this + HBGlyphID stdGlyph; /* The specific glyph index number in this * font that is used to set the baseline values. * This is the standard glyph. * This glyph must contain a set of control points @@ -101,11 +101,11 @@ struct BaselineTableFormat3Part bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && lookupTable.sanitize (c)); + return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c))); } protected: - GlyphID stdGlyph; /* ditto */ + HBGlyphID stdGlyph; /* ditto */ HBUINT16 ctlPoints[32]; /* ditto */ Lookup lookupTable; /* Lookup table that maps glyphs to their diff --git a/src/hb-aat-layout-common.hh b/src/hb-aat-layout-common.hh index a8c4b7637627c0d2d5ca1becceb384d4ee11c964..8e7b7b529098a2b4f2e59ae60c457cd4e0d3bb7d 100644 --- a/src/hb-aat-layout-common.hh +++ b/src/hb-aat-layout-common.hh @@ -93,8 +93,8 @@ struct LookupSegmentSingle return_trace (c->check_struct (this) && value.sanitize (c, base)); } - GlyphID last; /* Last GlyphID in this segment */ - GlyphID first; /* First GlyphID in this segment */ + HBGlyphID last; /* Last GlyphID in this segment */ + HBGlyphID first; /* First GlyphID in this segment */ T value; /* The lookup value (only one) */ public: DEFINE_SIZE_STATIC (4 + T::static_size); @@ -162,9 +162,9 @@ struct LookupSegmentArray valuesZ.sanitize (c, base, last - first + 1, hb_forward (ds)...)); } - GlyphID last; /* Last GlyphID in this segment */ - GlyphID first; /* First GlyphID in this segment */ - NNOffsetTo> + HBGlyphID last; /* Last GlyphID in this segment */ + HBGlyphID first; /* First GlyphID in this segment */ + NNOffset16To> valuesZ; /* A 16-bit offset from the start of * the table to the data. */ public: @@ -222,7 +222,7 @@ struct LookupSingle return_trace (c->check_struct (this) && value.sanitize (c, base)); } - GlyphID glyph; /* Last GlyphID */ + HBGlyphID glyph; /* Last GlyphID */ T value; /* The lookup value (only one) */ public: DEFINE_SIZE_STATIC (2 + T::static_size); @@ -284,7 +284,7 @@ struct LookupFormat8 protected: HBUINT16 format; /* Format identifier--format = 8 */ - GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */ HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last * glyph minus the value of firstGlyph plus 1). */ UnsizedArrayOf @@ -303,7 +303,7 @@ struct LookupFormat10 const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const { if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount)) - return Null(T); + return Null (T); const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize]; @@ -326,7 +326,7 @@ struct LookupFormat10 protected: HBUINT16 format; /* Format identifier--format = 8 */ HBUINT16 valueSize; /* Byte size of each value. */ - GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */ HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last * glyph minus the value of firstGlyph plus 1). */ UnsizedArrayOf @@ -358,7 +358,7 @@ struct Lookup case 10: return u.format10.get_value_or_null (glyph_id); default: const T *v = get_value (glyph_id, num_glyphs); - return v ? *v : Null(T); + return v ? *v : Null (T); } } @@ -510,7 +510,7 @@ struct StateTable const Entry &get_entry (int state, unsigned int klass) const { if (unlikely (klass >= nClasses)) - klass = StateTable>::CLASS_OUT_OF_BOUNDS; + klass = StateTable::CLASS_OUT_OF_BOUNDS; const HBUSHORT *states = (this+stateArrayTable).arrayZ; const Entry *entries = (this+entryTable).arrayZ; @@ -576,7 +576,7 @@ struct StateTable if (unlikely (stop > states)) return_trace (false); for (const HBUSHORT *p = states; stop < p; p--) - num_entries = hb_max (num_entries, *(p - 1) + 1); + num_entries = hb_max (num_entries, *(p - 1) + 1u); state_neg = min_state; } } @@ -597,7 +597,7 @@ struct StateTable if (unlikely (stop < states)) return_trace (false); for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++) - num_entries = hb_max (num_entries, *p + 1); + num_entries = hb_max (num_entries, *p + 1u); state_pos = max_state + 1; } } @@ -658,8 +658,8 @@ struct ClassTable return_trace (c->check_struct (this) && classArray.sanitize (c)); } protected: - GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ - ArrayOf classArray; /* The class codes (indexed by glyph index minus + HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + Array16Of classArray; /* The class codes (indexed by glyph index minus * firstGlyph). */ public: DEFINE_SIZE_ARRAY (4, classArray); @@ -678,7 +678,8 @@ struct ObsoleteTypes const void *base, const T *array) { - return (offset - ((const char *) array - (const char *) base)) / sizeof (T); + /* https://github.com/harfbuzz/harfbuzz/issues/2816 */ + return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size; } template static unsigned int byteOffsetToIndex (unsigned int offset, @@ -729,7 +730,10 @@ struct ExtendedTypes template struct StateTableDriver { - StateTableDriver (const StateTable &machine_, + using StateTableT = StateTable; + using EntryT = Entry; + + StateTableDriver (const StateTableT &machine_, hb_buffer_t *buffer_, hb_face_t *face_) : machine (machine_), @@ -742,59 +746,101 @@ struct StateTableDriver if (!c->in_place) buffer->clear_output (); - int state = StateTable::STATE_START_OF_TEXT; + int state = StateTableT::STATE_START_OF_TEXT; for (buffer->idx = 0; buffer->successful;) { unsigned int klass = buffer->idx < buffer->len ? machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : - (unsigned) StateTable::CLASS_END_OF_TEXT; + (unsigned) StateTableT::CLASS_END_OF_TEXT; DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); - const Entry &entry = machine.get_entry (state, klass); + const EntryT &entry = machine.get_entry (state, klass); + const int next_state = machine.new_state (entry.newState); - /* Unsafe-to-break before this if not in state 0, as things might - * go differently if we start from state 0 here. + /* Conditions under which it's guaranteed safe-to-break before current glyph: * - * Ugh. The indexing here is ugly... */ - if (state && buffer->backtrack_len () && buffer->idx < buffer->len) - { - /* If there's no action and we're just epsilon-transitioning to state 0, - * safe to break. */ - if (c->is_actionable (this, entry) || - !(entry.newState == StateTable::STATE_START_OF_TEXT && - entry.flags == context_t::DontAdvance)) - buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); - } - - /* Unsafe-to-break if end-of-text would kick in here. */ - if (buffer->idx + 2 <= buffer->len) - { - const Entry &end_entry = machine.get_entry (state, StateTable::CLASS_END_OF_TEXT); - if (c->is_actionable (this, end_entry)) - buffer->unsafe_to_break (buffer->idx, buffer->idx + 2); - } + * 1. There was no action in this transition; and + * + * 2. If we break before current glyph, the results will be the same. That + * is guaranteed if: + * + * 2a. We were already in start-of-text state; or + * + * 2b. We are epsilon-transitioning to start-of-text state; or + * + * 2c. Starting from start-of-text state seeing current glyph: + * + * 2c'. There won't be any actions; and + * + * 2c". We would end up in the same state that we were going to end up + * in now, including whether epsilon-transitioning. + * + * and + * + * 3. If we break before current glyph, there won't be any end-of-text action + * after previous glyph. + * + * This triples the transitions we need to look up, but is worth returning + * granular unsafe-to-break results. See eg.: + * + * https://github.com/harfbuzz/harfbuzz/issues/2860 + */ + const EntryT *wouldbe_entry; + bool safe_to_break = + /* 1. */ + !c->is_actionable (this, entry) + && + /* 2. */ + ( + /* 2a. */ + state == StateTableT::STATE_START_OF_TEXT + || + /* 2b. */ + ( + (entry.flags & context_t::DontAdvance) && + next_state == StateTableT::STATE_START_OF_TEXT + ) + || + /* 2c. */ + ( + wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass) + , + /* 2c'. */ + !c->is_actionable (this, *wouldbe_entry) + && + /* 2c". */ + ( + next_state == machine.new_state (wouldbe_entry->newState) + && + (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance) + ) + ) + ) + && + /* 3. */ + !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT)) + ; + + if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len) + buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); c->transition (this, entry); - state = machine.new_state (entry.newState); + state = next_state; DEBUG_MSG (APPLY, nullptr, "s%d", state); - if (buffer->idx == buffer->len) + if (buffer->idx == buffer->len || unlikely (!buffer->successful)) break; if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) - buffer->next_glyph (); + (void) buffer->next_glyph (); } if (!c->in_place) - { - for (; buffer->successful && buffer->idx < buffer->len;) - buffer->next_glyph (); buffer->swap_buffers (); - } } public: - const StateTable &machine; + const StateTableT &machine; hb_buffer_t *buffer; unsigned int num_glyphs; }; @@ -820,12 +866,11 @@ struct hb_aat_apply_context_t : /* Unused. For debug tracing only. */ unsigned int lookup_index; - unsigned int debug_depth; HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, hb_font_t *font_, hb_buffer_t *buffer_, - hb_blob_t *blob = const_cast (&Null(hb_blob_t))); + hb_blob_t *blob = const_cast (&Null (hb_blob_t))); HB_INTERNAL ~hb_aat_apply_context_t (); diff --git a/src/hb-aat-layout-feat-table.hh b/src/hb-aat-layout-feat-table.hh index c8229940dc0a6f3083ff2b6a852f8543e6425fcc..573f0cf9f6be2ce3168f2ff960267c29f6d99cb0 100644 --- a/src/hb-aat-layout-feat-table.hh +++ b/src/hb-aat-layout-feat-table.hh @@ -129,6 +129,11 @@ struct FeatureName hb_ot_name_id_t get_feature_name_id () const { return nameIndex; } + bool is_exclusive () const { return featureFlags & Exclusive; } + + /* A FeatureName with no settings is meaningless */ + bool has_data () const { return nSettings; } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -139,7 +144,7 @@ struct FeatureName protected: HBUINT16 feature; /* Feature type. */ HBUINT16 nSettings; /* The number of records in the setting name array. */ - LOffsetTo, false> + NNOffset32To> settingTableZ; /* Offset in bytes from the beginning of this table to * this feature's setting name array. The actual type of * record this offset refers to will depend on the @@ -172,6 +177,9 @@ struct feat return featureNameCount; } + bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const + { return get_feature (feature_type).has_data (); } + const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const { return namesZ.bsearch (featureNameCount, feature_type); } @@ -206,7 +214,7 @@ struct feat SortedUnsizedArrayOf namesZ; /* The feature name array. */ public: - DEFINE_SIZE_STATIC (24); + DEFINE_SIZE_ARRAY (12, namesZ); }; } /* namespace AAT */ diff --git a/src/hb-aat-layout-just-table.hh b/src/hb-aat-layout-just-table.hh index e15c946a2db41ef301599f2162086784de60b608..556d4ad75b19d3b48aaa1154d2364e78335487ff 100644 --- a/src/hb-aat-layout-just-table.hh +++ b/src/hb-aat-layout-just-table.hh @@ -51,10 +51,10 @@ struct ActionSubrecordHeader return_trace (likely (c->check_struct (this))); } - HBUINT16 actionClass; /* The JustClass value associated with this + HBUINT16 actionClass; /* The JustClass value associated with this * ActionSubrecord. */ - HBUINT16 actionType; /* The type of postcompensation action. */ - HBUINT16 actionLength; /* Length of this ActionSubrecord record, which + HBUINT16 actionType; /* The type of postcompensation action. */ + HBUINT16 actionLength; /* Length of this ActionSubrecord record, which * must be a multiple of 4. */ public: DEFINE_SIZE_STATIC (6); @@ -70,16 +70,16 @@ struct DecompositionAction ActionSubrecordHeader header; - Fixed lowerLimit; /* If the distance factor is less than this value, + HBFixed lowerLimit; /* If the distance factor is less than this value, * then the ligature is decomposed. */ - Fixed upperLimit; /* If the distance factor is greater than this value, + HBFixed upperLimit; /* If the distance factor is greater than this value, * then the ligature is decomposed. */ - HBUINT16 order; /* Numerical order in which this ligature will + HBUINT16 order; /* Numerical order in which this ligature will * be decomposed; you may want infrequent ligatures * to decompose before more frequent ones. The ligatures * on the line of text will decompose in increasing * value of this field. */ - ArrayOf + Array16Of decomposedglyphs; /* Number of 16-bit glyph indexes that follow; * the ligature will be decomposed into these glyphs. @@ -100,7 +100,7 @@ struct UnconditionalAddGlyphAction protected: ActionSubrecordHeader header; - GlyphID addGlyph; /* Glyph that should be added if the distance factor + HBGlyphID addGlyph; /* Glyph that should be added if the distance factor * is growing. */ public: @@ -118,14 +118,14 @@ struct ConditionalAddGlyphAction protected: ActionSubrecordHeader header; - Fixed substThreshold; /* Distance growth factor (in ems) at which + HBFixed substThreshold; /* Distance growth factor (in ems) at which * this glyph is replaced and the growth factor * recalculated. */ - GlyphID addGlyph; /* Glyph to be added as kashida. If this value is + HBGlyphID addGlyph; /* Glyph to be added as kashida. If this value is * 0xFFFF, no extra glyph will be added. Note that * generally when a glyph is added, justification * will need to be redone. */ - GlyphID substGlyph; /* Glyph to be substituted for this glyph if the + HBGlyphID substGlyph; /* Glyph to be substituted for this glyph if the * growth factor equals or exceeds the value of * substThreshold. */ public: @@ -143,16 +143,16 @@ struct DuctileGlyphAction protected: ActionSubrecordHeader header; - HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. + HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. * This would normally be 0x64756374 ('duct'), * but you may use any axis the font contains. */ - Fixed minimumLimit; /* The lowest value for the ductility axis tha + HBFixed minimumLimit; /* The lowest value for the ductility axis tha * still yields an acceptable appearance. Normally * this will be 1.0. */ - Fixed noStretchValue; /* This is the default value that corresponds to + HBFixed noStretchValue; /* This is the default value that corresponds to * no change in appearance. Normally, this will * be 1.0. */ - Fixed maximumLimit; /* The highest value for the ductility axis that + HBFixed maximumLimit; /* The highest value for the ductility axis that * still yields an acceptable appearance. */ public: DEFINE_SIZE_STATIC (22); @@ -169,8 +169,8 @@ struct RepeatedAddGlyphAction protected: ActionSubrecordHeader header; - HBUINT16 flags; /* Currently unused; set to 0. */ - GlyphID glyph; /* Glyph that should be added if the distance factor + HBUINT16 flags; /* Currently unused; set to 0. */ + HBGlyphID glyph; /* Glyph that should be added if the distance factor * is growing. */ public: DEFINE_SIZE_STATIC (10); @@ -271,14 +271,14 @@ struct JustWidthDeltaEntry }; protected: - Fixed beforeGrowLimit;/* The ratio by which the advance width of the + HBFixed beforeGrowLimit;/* The ratio by which the advance width of the * glyph is permitted to grow on the left or top side. */ - Fixed beforeShrinkLimit; + HBFixed beforeShrinkLimit; /* The ratio by which the advance width of the * glyph is permitted to shrink on the left or top side. */ - Fixed afterGrowLimit; /* The ratio by which the advance width of the glyph + HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph * is permitted to shrink on the left or top side. */ - Fixed afterShrinkLimit; + HBFixed afterShrinkLimit; /* The ratio by which the advance width of the glyph * is at most permitted to shrink on the right or * bottom side. */ @@ -310,7 +310,7 @@ struct WidthDeltaPair DEFINE_SIZE_STATIC (24); }; -typedef OT::LArrayOf WidthDeltaCluster; +typedef OT::Array32Of WidthDeltaCluster; struct JustificationCategory { @@ -358,21 +358,21 @@ struct JustificationHeader } protected: - OffsetTo + Offset16To justClassTable; /* Offset to the justification category state table. */ - OffsetTo - wdcTable; /* Offset from start of justification table to start + Offset16To + wdcTable; /* Offset from start of justification table to start * of the subtable containing the width delta factors * for the glyphs in your font. * * The width delta clusters table. */ - OffsetTo + Offset16To pcTable; /* Offset from start of justification table to start * of postcompensation subtable (set to zero if none). * * The postcompensation subtable, if present in the font. */ - Lookup> - lookupTable; /* Lookup table associating glyphs with width delta + Lookup> + lookupTable; /* Lookup table associating glyphs with width delta * clusters. See the description of Width Delta Clusters * table for details on how to interpret the lookup values. */ @@ -397,14 +397,14 @@ struct just protected: FixedVersion<>version; /* Version of the justification table * (0x00010000u for version 1.0). */ - HBUINT16 format; /* Format of the justification table (set to 0). */ - OffsetTo + HBUINT16 format; /* Format of the justification table (set to 0). */ + Offset16To horizData; /* Byte offset from the start of the justification table * to the header for tables that contain justification * information for horizontal text. * If you are not including this information, * store 0. */ - OffsetTo + Offset16To vertData; /* ditto, vertical */ public: diff --git a/src/hb-aat-layout-kerx-table.hh b/src/hb-aat-layout-kerx-table.hh index cec63ac6d1d90e72fab52a5370f33662e266f012..d0eacf0e61cdcffd928750b3d990cefd78f30222 100644 --- a/src/hb-aat-layout-kerx-table.hh +++ b/src/hb-aat-layout-kerx-table.hh @@ -82,8 +82,8 @@ struct KernPair } protected: - GlyphID left; - GlyphID right; + HBGlyphID left; + HBGlyphID right; FWORD value; public: DEFINE_SIZE_STATIC (6); @@ -229,9 +229,7 @@ struct KerxSubTableFormat1 bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry &entry) - { - return Format1EntryT::performAction (entry); - } + { return Format1EntryT::performAction (entry); } void transition (StateTableDriver *driver, const Entry &entry) { @@ -281,35 +279,28 @@ struct KerxSubTableFormat1 hb_glyph_position_t &o = buffer->pos[idx]; - /* Testing shows that CoreText only applies kern (cross-stream or not) - * if none has been applied by previous subtables. That is, it does - * NOT seem to accumulate as otherwise implied by specs. */ - - /* The following flag is undocumented in the spec, but described - * in the 'kern' table example. */ - if (v == -0x8000) - { - o.attach_type() = ATTACH_TYPE_NONE; - o.attach_chain() = 0; - o.x_offset = o.y_offset = 0; - } - else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) + if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction)) { if (crossStream) { - if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset) + /* The following flag is undocumented in the spec, but described + * in the 'kern' table example. */ + if (v == -0x8000) { - o.y_offset = c->font->em_scale_y (v); + o.attach_type() = ATTACH_TYPE_NONE; + o.attach_chain() = 0; + o.y_offset = 0; + } + else if (o.attach_type()) + { + o.y_offset += c->font->em_scale_y (v); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } } else if (buffer->info[idx].mask & kern_mask) { - if (!buffer->pos[idx].x_offset) - { - buffer->pos[idx].x_advance += c->font->em_scale_x (v); - buffer->pos[idx].x_offset += c->font->em_scale_x (v); - } + o.x_advance += c->font->em_scale_x (v); + o.x_offset += c->font->em_scale_x (v); } } else @@ -317,19 +308,22 @@ struct KerxSubTableFormat1 if (crossStream) { /* CoreText doesn't do crossStream kerning in vertical. We do. */ - if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset) + if (v == -0x8000) { - o.x_offset = c->font->em_scale_x (v); + o.attach_type() = ATTACH_TYPE_NONE; + o.attach_chain() = 0; + o.x_offset = 0; + } + else if (o.attach_type()) + { + o.x_offset += c->font->em_scale_x (v); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; } } else if (buffer->info[idx].mask & kern_mask) { - if (!buffer->pos[idx].y_offset) - { - buffer->pos[idx].y_advance += c->font->em_scale_y (v); - buffer->pos[idx].y_offset += c->font->em_scale_y (v); - } + o.y_advance += c->font->em_scale_y (v); + o.y_offset += c->font->em_scale_y (v); } } } @@ -392,7 +386,7 @@ struct KerxSubTableFormat2 const UnsizedArrayOf &arrayZ = this+array; unsigned int kern_idx = l + r; - kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ); + kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ); const FWORD *v = &arrayZ[kern_idx]; if (unlikely (!v->sanitize (&c->sanitizer))) return 0; @@ -488,7 +482,7 @@ struct KerxSubTableFormat4 }; driver_context_t (const KerxSubTableFormat4 *table, - hb_aat_apply_context_t *c_) : + hb_aat_apply_context_t *c_) : c (c_), action_type ((table->flags & ActionType) >> 30), ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))), @@ -497,9 +491,7 @@ struct KerxSubTableFormat4 bool is_actionable (StateTableDriver *driver HB_UNUSED, const Entry &entry) - { - return entry.data.ankrActionIndex != 0xFFFF; - } + { return entry.data.ankrActionIndex != 0xFFFF; } void transition (StateTableDriver *driver, const Entry &entry) { @@ -512,11 +504,13 @@ struct KerxSubTableFormat4 { case 0: /* Control Point Actions.*/ { - /* indexed into glyph outline. */ - const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex]; + /* Indexed into glyph outline. */ + /* Each action (record in ankrData) contains two 16-bit fields, so we must + double the ankrActionIndex to get the correct offset here. */ + const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; if (!c->sanitizer.check_array (data, 2)) return; - HB_UNUSED unsigned int markControlPoint = *data++; - HB_UNUSED unsigned int currControlPoint = *data++; + unsigned int markControlPoint = *data++; + unsigned int currControlPoint = *data++; hb_position_t markX = 0; hb_position_t markY = 0; hb_position_t currX = 0; @@ -538,8 +532,10 @@ struct KerxSubTableFormat4 case 1: /* Anchor Point Actions. */ { - /* Indexed into 'ankr' table. */ - const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex]; + /* Indexed into 'ankr' table. */ + /* Each action (record in ankrData) contains two 16-bit fields, so we must + double the ankrActionIndex to get the correct offset here. */ + const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2]; if (!c->sanitizer.check_array (data, 2)) return; unsigned int markAnchorPoint = *data++; unsigned int currAnchorPoint = *data++; @@ -557,7 +553,9 @@ struct KerxSubTableFormat4 case 2: /* Control Point Coordinate Actions. */ { - const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex]; + /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex + by 4 to get the correct offset for the given action. */ + const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4]; if (!c->sanitizer.check_array (data, 4)) return; int markX = *data++; int markY = *data++; @@ -628,7 +626,7 @@ struct KerxSubTableFormat6 bool is_long () const { return flags & ValuesAreLong; } int get_kerning (hb_codepoint_t left, hb_codepoint_t right, - hb_aat_apply_context_t *c) const + hb_aat_apply_context_t *c) const { unsigned int num_glyphs = c->sanitizer.get_num_glyphs (); if (is_long ()) @@ -712,18 +710,18 @@ struct KerxSubTableFormat6 { struct Long { - LNNOffsetTo> rowIndexTable; - LNNOffsetTo> columnIndexTable; - LNNOffsetTo> array; + NNOffset32To> rowIndexTable; + NNOffset32To> columnIndexTable; + NNOffset32To> array; } l; struct Short { - LNNOffsetTo> rowIndexTable; - LNNOffsetTo> columnIndexTable; - LNNOffsetTo> array; + NNOffset32To> rowIndexTable; + NNOffset32To> columnIndexTable; + NNOffset32To> array; } s; } u; - LNNOffsetTo> vector; + NNOffset32To> vector; public: DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24); }; @@ -733,8 +731,8 @@ struct KerxSubTableHeader { typedef ExtendedTypes Types; - unsigned int tuple_count () const { return tupleCount; } - bool is_horizontal () const { return !(coverage & Vertical); } + unsigned tuple_count () const { return tupleCount; } + bool is_horizontal () const { return !(coverage & Vertical); } enum Coverage { @@ -830,7 +828,7 @@ struct KerxTable for (unsigned int i = 0; i < count; i++) { if (st->get_type () == 1) - return true; + return true; st = &StructAfter (*st); } return false; @@ -845,7 +843,7 @@ struct KerxTable for (unsigned int i = 0; i < count; i++) { if (st->u.header.coverage & st->u.header.CrossStream) - return true; + return true; st = &StructAfter (*st); } return false; @@ -862,7 +860,7 @@ struct KerxTable { if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) || !st->u.header.is_horizontal ()) - continue; + continue; v += st->get_kerning (left, right); st = &StructAfter (*st); } @@ -883,7 +881,7 @@ struct KerxTable bool reverse; if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation)) - goto skip; + goto skip; if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ()) goto skip; @@ -891,14 +889,14 @@ struct KerxTable reverse = bool (st->u.header.coverage & st->u.header.Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index)) + if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index)) goto skip; if (!seenCrossStream && (st->u.header.coverage & st->u.header.CrossStream)) { - /* Attach all glyphs into a chain. */ - seenCrossStream = true; + /* Attach all glyphs into a chain. */ + seenCrossStream = true; hb_glyph_position_t *pos = c->buffer->pos; unsigned int count = c->buffer->len; for (unsigned int i = 0; i < count; i++) @@ -923,7 +921,7 @@ struct KerxTable if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index); + (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index); skip: st = &StructAfter (*st); diff --git a/src/hb-aat-layout-lcar-table.hh b/src/hb-aat-layout-lcar-table.hh deleted file mode 100644 index 7063b386c2e3c6f8a3343a87fe936af363af0b5f..0000000000000000000000000000000000000000 --- a/src/hb-aat-layout-lcar-table.hh +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ -#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH -#define HB_AAT_LAYOUT_LCAR_TABLE_HH - -#include "hb-open-type.hh" -#include "hb-aat-layout-common.hh" - -/* - * lcar -- Ligature caret - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html - */ -#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r') - - -namespace AAT { - -typedef ArrayOf LigCaretClassEntry; - -struct lcarFormat0 -{ - unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */, - const void *base) const - { - const OffsetTo* entry_offset = lookupTable.get_value (glyph, - font->face->get_num_glyphs ()); - const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry); - if (caret_count) - { - hb_array_t arr = array.sub_array (start_offset, caret_count); - for (unsigned int i = 0; i < arr.length; ++i) - caret_array[i] = font->em_scale_dir (arr[i], direction); - } - return array.len; - } - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base))); - } - - protected: - Lookup> - lookupTable; /* data Lookup table associating glyphs */ - public: - DEFINE_SIZE_MIN (2); -}; - -struct lcarFormat1 -{ - unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */, - const void *base) const - { - const OffsetTo* entry_offset = lookupTable.get_value (glyph, - font->face->get_num_glyphs ()); - const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry); - if (caret_count) - { - hb_array_t arr = array.sub_array (start_offset, caret_count); - for (unsigned int i = 0; i < arr.length; ++i) - { - hb_position_t x = 0, y = 0; - font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y); - caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; - } - } - return array.len; - } - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base))); - } - - protected: - Lookup> - lookupTable; /* data Lookup table associating glyphs */ - public: - DEFINE_SIZE_MIN (2); -}; - -struct lcar -{ - static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar; - - unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */) const - { - switch (format) - { - case 0: return u.format0.get_lig_carets (font, direction, glyph, start_offset, - caret_count, caret_array, this); - case 1: return u.format1.get_lig_carets (font, direction, glyph, start_offset, - caret_count, caret_array, this); - default:if (caret_count) *caret_count = 0; return 0; - } - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this) || version.major != 1)) - return_trace (false); - - switch (format) { - case 0: return_trace (u.format0.sanitize (c, this)); - case 1: return_trace (u.format1.sanitize (c, this)); - default:return_trace (true); - } - } - - protected: - FixedVersion<>version; /* Version number of the ligature caret table */ - HBUINT16 format; /* Format of the ligature caret table. */ - union { - lcarFormat0 format0; - lcarFormat0 format1; - } u; - public: - DEFINE_SIZE_MIN (8); -}; - -} /* namespace AAT */ - -#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */ diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index 81d78972a2255b095f935c1a4c3ae197b5bf551a..dea69c9ab873a6c71c3d4b4dfdaa81b2be641c2f 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -226,7 +226,7 @@ struct ContextualSubtable hb_buffer_t *buffer = driver->buffer; if (buffer->idx == buffer->len && !mark_set) - return false; + return false; return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; } @@ -238,23 +238,23 @@ struct ContextualSubtable /* Looks like CoreText applies neither mark nor current substitution for * end-of-text if mark was not explicitly set. */ if (buffer->idx == buffer->len && !mark_set) - return; + return; - const GlyphID *replacement; + const HBGlyphID *replacement; replacement = nullptr; if (Types::extended) { if (entry.data.markIndex != 0xFFFF) { - const Lookup &lookup = subs[entry.data.markIndex]; + const Lookup &lookup = subs[entry.data.markIndex]; replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs); } } else { unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; - const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; + const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; if (!replacement->sanitize (&c->sanitizer) || !*replacement) replacement = nullptr; @@ -272,14 +272,14 @@ struct ContextualSubtable { if (entry.data.currentIndex != 0xFFFF) { - const Lookup &lookup = subs[entry.data.currentIndex]; + const Lookup &lookup = subs[entry.data.currentIndex]; replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs); } } else { unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; - const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; + const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs; replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; if (!replacement->sanitize (&c->sanitizer) || !*replacement) replacement = nullptr; @@ -304,7 +304,7 @@ struct ContextualSubtable bool mark_set; unsigned int mark; const ContextualSubtable *table; - const UnsizedOffsetListOf, HBUINT, false> &subs; + const UnsizedListOfOffset16To, HBUINT, false> &subs; }; bool apply (hb_aat_apply_context_t *c) const @@ -337,9 +337,9 @@ struct ContextualSubtable const EntryData &data = entries[i].data; if (data.markIndex != 0xFFFF) - num_lookups = hb_max (num_lookups, 1 + data.markIndex); + num_lookups = hb_max (num_lookups, 1u + data.markIndex); if (data.currentIndex != 0xFFFF) - num_lookups = hb_max (num_lookups, 1 + data.currentIndex); + num_lookups = hb_max (num_lookups, 1u + data.currentIndex); } return_trace (substitutionTables.sanitize (c, this, num_lookups)); @@ -348,7 +348,7 @@ struct ContextualSubtable protected: StateTable machine; - NNOffsetTo, HBUINT, false>, HBUINT> + NNOffsetTo, HBUINT, false>, HBUINT> substitutionTables; public: DEFINE_SIZE_STATIC (20); @@ -488,7 +488,7 @@ struct LigatureSubtable unsigned int ligature_idx = 0; unsigned int action; - do + do { if (unlikely (!cursor)) { @@ -499,7 +499,7 @@ struct LigatureSubtable } DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1); - buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]); + if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return; if (unlikely (!actionData->sanitize (&c->sanitizer))) break; action = *actionData; @@ -520,30 +520,30 @@ struct LigatureSubtable if (action & (LigActionStore | LigActionLast)) { ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); - const GlyphID &ligatureData = ligature[ligature_idx]; + const HBGlyphID &ligatureData = ligature[ligature_idx]; if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; hb_codepoint_t lig = ligatureData; DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); - buffer->replace_glyph (lig); + if (unlikely (!buffer->replace_glyph (lig))) return; unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u; /* Now go and delete all subsequent components. */ while (match_length - 1u > cursor) { DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); - buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]); - buffer->replace_glyph (DELETED_GLYPH); + if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; + if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; } - buffer->move_to (lig_end); + if (unlikely (!buffer->move_to (lig_end))) return; buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len); } actionData++; } while (!(action & LigActionLast)); - buffer->move_to (end); + if (unlikely (!buffer->move_to (end))) return; } } @@ -554,7 +554,7 @@ struct LigatureSubtable const LigatureSubtable *table; const UnsizedArrayOf &ligAction; const UnsizedArrayOf &component; - const UnsizedArrayOf &ligature; + const UnsizedArrayOf &ligature; unsigned int match_length; unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; }; @@ -586,7 +586,7 @@ struct LigatureSubtable ligAction; /* Offset to the ligature action table. */ NNOffsetTo, HBUINT> component; /* Offset to the component table. */ - NNOffsetTo, HBUINT> + NNOffsetTo, HBUINT> ligature; /* Offset to the actual ligature lists. */ public: DEFINE_SIZE_STATIC (28); @@ -606,7 +606,7 @@ struct NoncontextualSubtable unsigned int count = c->buffer->len; for (unsigned int i = 0; i < count; i++) { - const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs); + const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement) { info[i].codepoint = *replacement; @@ -624,7 +624,7 @@ struct NoncontextualSubtable } protected: - Lookup substitute; + Lookup substitute; public: DEFINE_SIZE_MIN (2); }; @@ -725,24 +725,24 @@ struct InsertionSubtable if (entry.data.markedInsertIndex != 0xFFFF) { unsigned int count = (flags & MarkedInsertCount); + if (unlikely ((buffer->max_ops -= count) <= 0)) return; unsigned int start = entry.data.markedInsertIndex; - const GlyphID *glyphs = &insertionAction[start]; + const HBGlyphID *glyphs = &insertionAction[start]; if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; bool before = flags & MarkedInsertBefore; unsigned int end = buffer->out_len; - buffer->move_to (mark); + if (unlikely (!buffer->move_to (mark))) return; if (buffer->idx < buffer->len && !before) - buffer->copy_glyph (); + if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ - for (unsigned int i = 0; i < count; i++) - buffer->output_glyph (glyphs[i]); + if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); - buffer->move_to (end + count); + if (unlikely (!buffer->move_to (end + count))) return; buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len)); } @@ -753,8 +753,9 @@ struct InsertionSubtable if (entry.data.currentInsertIndex != 0xFFFF) { unsigned int count = (flags & CurrentInsertCount) >> 5; + if (unlikely ((buffer->max_ops -= count) <= 0)) return; unsigned int start = entry.data.currentInsertIndex; - const GlyphID *glyphs = &insertionAction[start]; + const HBGlyphID *glyphs = &insertionAction[start]; if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; bool before = flags & CurrentInsertBefore; @@ -762,10 +763,9 @@ struct InsertionSubtable unsigned int end = buffer->out_len; if (buffer->idx < buffer->len && !before) - buffer->copy_glyph (); + if (unlikely (!buffer->copy_glyph ())) return; /* TODO We ignore KashidaLike setting. */ - for (unsigned int i = 0; i < count; i++) - buffer->output_glyph (glyphs[i]); + if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; if (buffer->idx < buffer->len && !before) buffer->skip_glyph (); @@ -784,7 +784,7 @@ struct InsertionSubtable * * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417 */ - buffer->move_to ((flags & DontAdvance) ? end : end + count); + if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return; } } @@ -793,7 +793,7 @@ struct InsertionSubtable private: hb_aat_apply_context_t *c; unsigned int mark; - const UnsizedArrayOf &insertionAction; + const UnsizedArrayOf &insertionAction; }; bool apply (hb_aat_apply_context_t *c) const @@ -819,7 +819,7 @@ struct InsertionSubtable protected: StateTable machine; - NNOffsetTo, HBUINT> + NNOffsetTo, HBUINT> insertionAction; /* Byte offset from stateHeader to the start of * the insertion glyph table. */ public: @@ -948,8 +948,10 @@ struct Chain hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType; hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting; retry: - const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type); - if (info && info->setting == setting) + // Check whether this type/setting pair was requested in the map, and if so, apply its flags. + // (The search here only looks at the type and setting fields of feature_info_t.) + hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; + if (map->features.bsearch (info)) { flags &= feature.disableFlags; flags |= feature.enableFlags; @@ -967,7 +969,7 @@ struct Chain } void apply (hb_aat_apply_context_t *c, - hb_mask_t flags) const + hb_mask_t flags) const { const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount)); unsigned int count = subtableCount; @@ -976,12 +978,12 @@ struct Chain bool reverse; if (!(subtable->subFeatureFlags & flags)) - goto skip; + goto skip; if (!(subtable->get_coverage() & ChainSubtable::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != bool (subtable->get_coverage() & ChainSubtable::Vertical)) - goto skip; + goto skip; /* Buffer contents is always in logical direction. Determine if * we need to reverse before applying this subtable. We reverse @@ -1015,18 +1017,18 @@ struct Chain bool (subtable->get_coverage () & ChainSubtable::Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index)) - goto skip; + if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index)) + goto skip; if (reverse) - c->buffer->reverse (); + c->buffer->reverse (); subtable->apply (c); if (reverse) - c->buffer->reverse (); + c->buffer->reverse (); - (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); if (unlikely (!c->buffer->successful)) return; @@ -1080,10 +1082,10 @@ struct Chain * The 'mort'/'morx' Table */ -template +template struct mortmorx { - static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx; + static constexpr hb_tag_t tableTag = TAG; bool has_data () const { return version != 0; } @@ -1143,14 +1145,8 @@ struct mortmorx DEFINE_SIZE_MIN (8); }; -struct morx : mortmorx -{ - static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx; -}; -struct mort : mortmorx -{ - static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort; -}; +struct morx : mortmorx {}; +struct mort : mortmorx {}; } /* namespace AAT */ diff --git a/src/hb-aat-layout-opbd-table.hh b/src/hb-aat-layout-opbd-table.hh index 4e0234074feeb6c7c693d0e438ce4c4a4e2ca312..b1a1512821d8cb355a1b48c2baf99650a2d1e1ca 100644 --- a/src/hb-aat-layout-opbd-table.hh +++ b/src/hb-aat-layout-opbd-table.hh @@ -58,7 +58,7 @@ struct opbdFormat0 bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id, hb_glyph_extents_t *extents, const void *base) const { - const OffsetTo *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ()); + const Offset16To *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ()); if (!bounds_offset) return false; const OpticalBounds &bounds = base+*bounds_offset; @@ -79,7 +79,7 @@ struct opbdFormat0 } protected: - Lookup> + Lookup> lookupTable; /* Lookup table associating glyphs with the four * int16 values for the left-side, top-side, * right-side, and bottom-side optical bounds. */ @@ -92,7 +92,7 @@ struct opbdFormat1 bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id, hb_glyph_extents_t *extents, const void *base) const { - const OffsetTo *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ()); + const Offset16To *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ()); if (!bounds_offset) return false; const OpticalBounds &bounds = base+*bounds_offset; @@ -116,7 +116,7 @@ struct opbdFormat1 } protected: - Lookup> + Lookup> lookupTable; /* Lookup table associating glyphs with the four * int16 values for the left-side, top-side, * right-side, and bottom-side optical bounds. */ @@ -160,8 +160,8 @@ struct opbd * Format 0 indicates distance and Format 1 indicates * control point. */ union { - opbdFormat0 format0; - opbdFormat1 format1; + opbdFormat0 format0; + opbdFormat1 format1; } u; public: DEFINE_SIZE_MIN (8); diff --git a/src/hb-aat-layout-trak-table.hh b/src/hb-aat-layout-trak-table.hh index e6b6d55e043f73573dc81708bcc397aa8bd1d6f9..68bcb2396f50345b1fcf77449d90e2dff6c16ab6 100644 --- a/src/hb-aat-layout-trak-table.hh +++ b/src/hb-aat-layout-trak-table.hh @@ -62,11 +62,11 @@ struct TrackTableEntry } protected: - Fixed track; /* Track value for this record. */ + HBFixed track; /* Track value for this record. */ NameID trackNameID; /* The 'name' table index for this track. * (a short word or phrase like "loose" * or "very tight") */ - NNOffsetTo> + NNOffset16To> valuesZ; /* Offset from start of tracking table to * per-size tracking values for this track. */ @@ -82,7 +82,7 @@ struct TrackData const void *base) const { unsigned int sizes = nSizes; - hb_array_t size_table ((base+sizeTable).arrayZ, sizes); + hb_array_t size_table ((base+sizeTable).arrayZ, sizes); float s0 = size_table[idx].to_float (); float s1 = size_table[idx + 1].to_float (); @@ -120,11 +120,11 @@ struct TrackData if (!sizes) return 0.; if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); - hb_array_t size_table ((base+sizeTable).arrayZ, sizes); + hb_array_t size_table ((base+sizeTable).arrayZ, sizes); unsigned int size_index; for (size_index = 0; size_index < sizes - 1; size_index++) if (size_table[size_index].to_float () >= ptem) - break; + break; return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem, *trackTableEntry, base)); @@ -141,7 +141,7 @@ struct TrackData protected: HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */ - LOffsetTo, false> + NNOffset32To> sizeTable; /* Offset from start of the tracking table to * Array[nSizes] of size values.. */ UnsizedArrayOf @@ -176,7 +176,7 @@ struct trak hb_position_t advance_to_add = c->font->em_scalef_x (tracking); foreach_grapheme (buffer, start, end) { - if (!(buffer->info[start].mask & trak_mask)) continue; + if (!(buffer->info[start].mask & trak_mask)) continue; buffer->pos[start].x_advance += advance_to_add; buffer->pos[start].x_offset += offset_to_add; } @@ -189,7 +189,7 @@ struct trak hb_position_t advance_to_add = c->font->em_scalef_y (tracking); foreach_grapheme (buffer, start, end) { - if (!(buffer->info[start].mask & trak_mask)) continue; + if (!(buffer->info[start].mask & trak_mask)) continue; buffer->pos[start].y_advance += advance_to_add; buffer->pos[start].y_offset += offset_to_add; } @@ -210,12 +210,12 @@ struct trak protected: FixedVersion<>version; /* Version of the tracking table - * (0x00010000u for version 1.0). */ - HBUINT16 format; /* Format of the tracking table (set to 0). */ - OffsetTo + * (0x00010000u for version 1.0). */ + HBUINT16 format; /* Format of the tracking table (set to 0). */ + Offset16To horizData; /* Offset from start of tracking table to TrackData * for horizontal text (or 0 if none). */ - OffsetTo + Offset16To vertData; /* Offset from start of tracking table to TrackData * for vertical text (or 0 if none). */ HBUINT16 reserved; /* Reserved. Set to 0. */ diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 4e506de16e899245ded653196af5ad0b99fcf7c1..0e9f2b495491458aa8f66a7dc1c9bc49d7ec7979 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -28,7 +28,6 @@ #include "hb.hh" #include "hb-aat-layout.hh" -#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-ankr-table.hh" #include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise. #include "hb-aat-layout-feat-table.hh" @@ -55,9 +54,8 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p face (font->face), buffer (buffer_), sanitizer (), - ankr_table (&Null(AAT::ankr)), - lookup_index (0), - debug_depth (0) + ankr_table (&Null (AAT::ankr)), + lookup_index (0) { sanitizer.init (blob); sanitizer.set_num_glyphs (face->get_num_glyphs ()); @@ -81,13 +79,18 @@ AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_) * @short_description: Apple Advanced Typography Layout * @include: hb-aat.h * - * Functions for querying OpenType Layout features in the font face. + * Functions for querying AAT Layout features in the font face. + * + * HarfBuzz supports all of the AAT tables used to implement shaping. Other + * AAT tables and their associated features are not supported. **/ #if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT) -/* Table data courtesy of Apple. Converted from mnemonics to integers +/* Mapping from OpenType feature tags to AAT feature names and selectors. + * + * Table data courtesy of Apple. Converted from mnemonics to integers * when moving to this file. */ static const hb_aat_feature_mapping_t feature_mappings[] = { @@ -169,14 +172,21 @@ static const hb_aat_feature_mapping_t feature_mappings[] = {HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF}, }; +/** + * hb_aat_layout_find_feature_mapping: + * @tag: The requested #hb_tag_t feature tag + * + * Fetches the AAT feature-and-selector combination that corresponds + * to a given OpenType feature tag. + * + * Return value: the AAT features and selectors corresponding to the + * OpenType feature tag queried + * + **/ const hb_aat_feature_mapping_t * hb_aat_layout_find_feature_mapping (hb_tag_t tag) { - return (const hb_aat_feature_mapping_t *) hb_bsearch (&tag, - feature_mappings, - ARRAY_LENGTH (feature_mappings), - sizeof (feature_mappings[0]), - hb_aat_feature_mapping_t::cmp); + return hb_sorted_array (feature_mappings).bsearch (tag); } #endif @@ -208,11 +218,17 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, } -/* +/** * hb_aat_layout_has_substitution: - * @face: + * @face: #hb_face_t to work upon + * + * Tests whether the specified face includes any substitutions in the + * `morx` or `mort` tables. + * + * Note: does not examine the `GSUB` table. + * + * Return value: %true if data found, %false otherwise * - * Returns: * Since: 2.3.0 */ hb_bool_t @@ -269,11 +285,17 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph); } -/* +/** * hb_aat_layout_has_positioning: - * @face: + * @face: #hb_face_t to work upon + * + * Tests whether the specified face includes any positioning information + * in the `kerx` table. + * + * Note: does not examine the `GPOS` table. + * + * Return value: %true if data found, %false otherwise * - * Returns: * Since: 2.3.0 */ hb_bool_t @@ -296,11 +318,15 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan, } -/* +/** * hb_aat_layout_has_tracking: - * @face: + * @face:: #hb_face_t to work upon + * + * Tests whether the specified face includes any tracking information + * in the `trak` table. + * + * Return value: %true if data found, %false otherwise * - * Returns: * Since: 2.3.0 */ hb_bool_t @@ -322,10 +348,13 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan, /** * hb_aat_layout_get_feature_types: - * @face: a face object - * @start_offset: iteration's start offset - * @feature_count:(inout) (allow-none): buffer size as input, filled size as output - * @features: (out caller-allocates) (array length=feature_count): features buffer + * @face: #hb_face_t to work upon + * @start_offset: offset of the first feature type to retrieve + * @feature_count: (inout) (optional): Input = the maximum number of feature types to return; + * Output = the actual number of feature types returned (may be zero) + * @features: (out caller-allocates) (array length=feature_count): Array of feature types found + * + * Fetches a list of the AAT feature types included in the specified face. * * Return value: Number of all available feature types. * @@ -342,10 +371,12 @@ hb_aat_layout_get_feature_types (hb_face_t *face, /** * hb_aat_layout_feature_type_get_name_id: - * @face: a face object - * @feature_type: feature id + * @face: #hb_face_t to work upon + * @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type * - * Return value: Name ID index + * Fetches the name identifier of the specified feature type in the face's `name` table. + * + * Return value: Name identifier of the requested feature type * * Since: 2.2.0 */ @@ -357,19 +388,23 @@ hb_aat_layout_feature_type_get_name_id (hb_face_t *face, } /** - * hb_aat_layout_feature_type_get_selectors: - * @face: a face object - * @feature_type: feature id - * @start_offset: iteration's start offset - * @selector_count: (inout) (allow-none): buffer size as input, filled size as output - * @selectors: (out caller-allocates) (array length=selector_count): settings buffer - * @default_index: (out) (allow-none): index of default selector if any + * hb_aat_layout_feature_type_get_selector_infos: + * @face: #hb_face_t to work upon + * @feature_type: The #hb_aat_layout_feature_type_t of the requested feature type + * @start_offset: offset of the first feature type to retrieve + * @selector_count: (inout) (optional): Input = the maximum number of selectors to return; + * Output = the actual number of selectors returned (may be zero) + * @selectors: (out caller-allocates) (array length=selector_count) (optional): + * A buffer pointer. The selectors available for the feature type queries. + * @default_index: (out) (optional): The index of the feature's default selector, if any + * + * Fetches a list of the selectors available for the specified feature in the given face. * * If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then * the feature type is non-exclusive. Otherwise, @default_index is the index of * the selector that is selected by default. * - * Return value: Number of all available feature selectors. + * Return value: Number of all available feature selectors * * Since: 2.2.0 */ diff --git a/src/hb-aat-layout.h b/src/hb-aat-layout.h index b617e8b703d3a022750675d2df596788c9a028e7..9af27400886a3f98fceba75bd481db3306fe6e02 100644 --- a/src/hb-aat-layout.h +++ b/src/hb-aat-layout.h @@ -22,7 +22,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#ifndef HB_AAT_H_IN +#if !defined(HB_AAT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -37,7 +37,48 @@ HB_BEGIN_DECLS /** * hb_aat_layout_feature_type_t: + * @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type + * @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0) + * @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2) + * @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3) + * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4) + * @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5) + * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING: [Number Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type6) + * @HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE: [Smart Swash](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type8) + * @HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE: [Diacritics](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type9) + * @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION: [Vertical Position](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type10) + * @HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS: [Fractions](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type11) + * @HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE: [Overlapping Characters](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type13) + * @HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS: [Typographic Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type14) + * @HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS: [Mathematical Extras](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type15) + * @HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE: [Ornament Sets](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type16) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES: [Character Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type17) + * @HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE: [Design Complexity](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type18) + * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS: [Style Options](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type19) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE: [Character Shape](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type20) + * @HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE: [Number Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type21) + * @HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING: [Text Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type22) + * @HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION: [Transliteration](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type23) + * @HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE: [Annotation](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type24) + * @HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE: [Kana Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type25) + * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE: [Ideographic Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type26) + * @HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE: [Unicode Decomposition](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type27) + * @HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA: [Ruby Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type28) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE: [CJK Symbol Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type29) + * @HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE: [Ideographic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type30) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE: [CJK Vertical Roman Placement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type31) + * @HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN: [Italic CJK Roman](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type32) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT: [Case Sensitive Layout](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type33) + * @HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA: [Alternate Kana](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type34) + * @HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES: [Stylistic Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type35) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES: [Contextual Alternatives](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type36) + * @HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE: [Lower Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type37) + * @HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE: [Upper Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type38) + * @HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE: [Language Tag](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type39) + * @HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE: [CJK Roman Spacing](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type103) * + * The possible feature types defined for AAT shaping, from Apple [Font Feature Registry](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html). * * Since: 2.2.0 */ @@ -85,12 +126,265 @@ typedef enum HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39, HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103, + /*< private >*/ _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_aat_layout_feature_type_t; /** * hb_aat_layout_feature_selector_t: + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID: Initial, unset feature selector + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE: Deprecated + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS: Deprecated + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE: Deprecated + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS: Deprecated + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS: Deprecated + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS: Deprecated + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS: for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS: for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS: for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS: for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS: for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5: for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS: for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT: for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION: for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA: for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE: for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN: Deprecated; use #HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF: for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE: for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE: for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS: for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE + * @HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN: for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE * + * The selectors defined for specifying AAT feature settings. * * Since: 2.2.0 */ @@ -424,6 +718,7 @@ typedef enum HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2, HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3, + /*< private >*/ _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_aat_layout_feature_selector_t; @@ -437,8 +732,15 @@ HB_EXTERN hb_ot_name_id_t hb_aat_layout_feature_type_get_name_id (hb_face_t *face, hb_aat_layout_feature_type_t feature_type); -typedef struct hb_aat_layout_feature_selector_info_t -{ +/** + * hb_aat_layout_feature_selector_info_t: + * @name_id: The selector's name identifier + * @enable: The value to turn the selector on + * @disable: The value to turn the selector off + * + * Structure representing a setting for an #hb_aat_layout_feature_type_t. + */ +typedef struct hb_aat_layout_feature_selector_info_t { hb_ot_name_id_t name_id; hb_aat_layout_feature_selector_t enable; hb_aat_layout_feature_selector_t disable; @@ -446,6 +748,13 @@ typedef struct hb_aat_layout_feature_selector_info_t unsigned int reserved; } hb_aat_layout_feature_selector_info_t; +/** + * HB_AAT_LAYOUT_NO_SELECTOR_INDEX + * + * Used when getting or setting AAT feature selectors. Indicates that + * there is no selector index corresponding to the selector of interest. + * + */ #define HB_AAT_LAYOUT_NO_SELECTOR_INDEX 0xFFFFu HB_EXTERN unsigned int diff --git a/src/hb-aat-layout.hh b/src/hb-aat-layout.hh index 8310bfcc2d22d12e2b985d49cf87421f1985fe4b..5e4e3bda154574d1cafec2a46cb8f10682ff2cd6 100644 --- a/src/hb-aat-layout.hh +++ b/src/hb-aat-layout.hh @@ -39,14 +39,8 @@ struct hb_aat_feature_mapping_t hb_aat_layout_feature_selector_t selectorToEnable; hb_aat_layout_feature_selector_t selectorToDisable; - HB_INTERNAL static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (unsigned int *) key_; - const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_; - return key < entry->otFeatureTag ? -1 : - key > entry->otFeatureTag ? 1 : - 0; - } + int cmp (hb_tag_t key) const + { return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; } }; HB_INTERNAL const hb_aat_feature_mapping_t * diff --git a/src/hb-aat-ltag-table.hh b/src/hb-aat-ltag-table.hh index 711f9aa6c18cf0c0dae9d163260d18cbdff60e44..6d771e1513e467cea4c68e06a2e3bee13a7197f5 100644 --- a/src/hb-aat-ltag-table.hh +++ b/src/hb-aat-ltag-table.hh @@ -50,7 +50,7 @@ struct FTStringRange } protected: - NNOffsetTo> + NNOffset16To> tag; /* Offset from the start of the table to * the beginning of the string */ HBUINT16 length; /* String length (in bytes) */ @@ -80,7 +80,7 @@ struct ltag protected: HBUINT32 version; /* Table version; currently 1 */ HBUINT32 flags; /* Table flags; currently none defined */ - LArrayOf + Array32Of tagRanges; /* Range for each tag's string */ public: DEFINE_SIZE_ARRAY (12, tagRanges); diff --git a/src/hb-aat-map.cc b/src/hb-aat-map.cc index bc879359aae6e77fe797e679ffd5277d67f0937a..2c38c3502968937d8f61e37114a6d2ae0643c574 100644 --- a/src/hb-aat-map.cc +++ b/src/hb-aat-map.cc @@ -33,25 +33,48 @@ #include "hb-aat-map.hh" #include "hb-aat-layout.hh" +#include "hb-aat-layout-feat-table.hh" -void hb_aat_map_builder_t::add_feature (hb_tag_t tag, - unsigned int value) +void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) { + if (!face->table.feat->has_data ()) return; + if (tag == HB_TAG ('a','a','l','t')) { + if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES)) + return; feature_info_t *info = features.push(); info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; info->setting = (hb_aat_layout_feature_selector_t) value; + info->seq = features.length; + info->is_exclusive = true; return; } const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); if (!mapping) return; + const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType); + if (!feature->has_data ()) + { + /* Special case: Chain::compile_flags will fall back to the deprecated version of + * small-caps if necessary, so we need to check for that possibility. + * https://github.com/harfbuzz/harfbuzz/issues/2307 */ + if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE && + mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) + { + feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); + if (!feature->has_data ()) return; + } + else return; + } + feature_info_t *info = features.push(); info->type = mapping->aatFeatureType; info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; + info->seq = features.length; + info->is_exclusive = feature->is_exclusive (); } void @@ -63,7 +86,11 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m) features.qsort (); unsigned int j = 0; for (unsigned int i = 1; i < features.length; i++) - if (features[i].type != features[j].type) + if (features[i].type != features[j].type || + /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off + * respectively, so we mask out the low-order bit when checking for "duplicates" + * (selectors referring to the same feature setting) here. */ + (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1)))) features[++j] = features[i]; features.shrink (j + 1); } diff --git a/src/hb-aat-map.hh b/src/hb-aat-map.hh index 984a59cca5b5c817721c4c9cfd922f23de3780b8..5a0fa7054453c53aeb05710b25d73e0b6ba8e2dd 100644 --- a/src/hb-aat-map.hh +++ b/src/hb-aat-map.hh @@ -64,19 +64,24 @@ struct hb_aat_map_builder_t { hb_aat_layout_feature_type_t type; hb_aat_layout_feature_selector_t setting; + bool is_exclusive; unsigned seq; /* For stable sorting only. */ HB_INTERNAL static int cmp (const void *pa, const void *pb) { const feature_info_t *a = (const feature_info_t *) pa; const feature_info_t *b = (const feature_info_t *) pb; - return (a->type != b->type) ? (a->type < b->type ? -1 : 1) : - (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); + if (a->type != b->type) return (a->type < b->type ? -1 : 1); + if (!a->is_exclusive && + (a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1); + return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); } - int cmp (hb_aat_layout_feature_type_t ty) const + /* compares type & setting only, not is_exclusive flag or seq number */ + int cmp (const feature_info_t& f) const { - return (type != ty) ? (type < ty ? -1 : 1) : 0; + return (f.type != type) ? (f.type < type ? -1 : 1) : + (f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0; } }; diff --git a/src/hb-algs.hh b/src/hb-algs.hh index 788689478d2aabb93f0395542c52d3fd1235cb94..bc170b0546c0777a93e7c6063145f367ed748314 100644 --- a/src/hb-algs.hh +++ b/src/hb-algs.hh @@ -32,6 +32,133 @@ #include "hb.hh" #include "hb-meta.hh" #include "hb-null.hh" +#include "hb-number.hh" + + +/* + * Flags + */ + +/* Enable bitwise ops on enums marked as flags_t */ +/* To my surprise, looks like the function resolver is happy to silently cast + * one enum to another... So this doesn't provide the type-checking that I + * originally had in mind... :(. + * + * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163 + */ +#ifdef _MSC_VER +# pragma warning(disable:4200) +# pragma warning(disable:4800) +#endif +#define HB_MARK_AS_FLAG_T(T) \ + extern "C++" { \ + static inline constexpr T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \ + static inline constexpr T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \ + static inline constexpr T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ + static inline constexpr T operator ~ (T r) { return T (~(unsigned int) r); } \ + static inline T& operator |= (T &l, T r) { l = l | r; return l; } \ + static inline T& operator &= (T& l, T r) { l = l & r; return l; } \ + static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \ + } \ + static_assert (true, "") + +/* Useful for set-operations on small enums. + * For example, for testing "x ∈ {x1, x2, x3}" use: + * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) + */ +#define FLAG(x) (static_assert_expr ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x))) +#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0) +#define FLAG_RANGE(x,y) (static_assert_expr ((x) < (y)) + FLAG(y+1) - FLAG(x)) +#define FLAG64(x) (static_assert_expr ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x))) +#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0) + + +/* + * Big-endian integers. + */ + +/* Endian swap, used in Windows related backends */ +static inline constexpr uint16_t hb_uint16_swap (uint16_t v) +{ return (v >> 8) | (v << 8); } +static inline constexpr uint32_t hb_uint32_swap (uint32_t v) +{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } + +template +struct BEInt; +template +struct BEInt +{ + public: + BEInt () = default; + constexpr BEInt (Type V) : v {uint8_t (V)} {} + constexpr operator Type () const { return v; } + private: uint8_t v; +}; +template +struct BEInt +{ + public: + BEInt () = default; + constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} + + struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; + constexpr operator Type () const + { +#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + /* Spoon-feed the compiler a big-endian integer with alignment 1. + * https://github.com/harfbuzz/harfbuzz/pull/1398 */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + return __builtin_bswap16 (((packed_uint16_t *) this)->v); +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + return ((packed_uint16_t *) this)->v; +#endif +#else + return (v[0] << 8) + + (v[1] ); +#endif + } + private: uint8_t v[2]; +}; +template +struct BEInt +{ + static_assert (!hb_is_signed (Type), ""); + public: + BEInt () = default; + constexpr BEInt (Type V) : v {uint8_t ((V >> 16) & 0xFF), + uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} + + constexpr operator Type () const { return (v[0] << 16) + + (v[1] << 8) + + (v[2] ); } + private: uint8_t v[3]; +}; +template +struct BEInt +{ + public: + BEInt () = default; + constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF), + uint8_t ((V >> 16) & 0xFF), + uint8_t ((V >> 8) & 0xFF), + uint8_t ((V ) & 0xFF)} {} + constexpr operator Type () const { return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); } + private: uint8_t v[4]; +}; + +/* Floats. */ + +/* We want our rounding towards +infinity. */ +static inline float +_hb_roundf (float x) { return floorf (x + .5f); } +#define roundf(x) _hb_roundf(x) /* Encodes three unsigned integers in one 64-bit number. If the inputs have more than 21 bits, @@ -47,6 +174,7 @@ #define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300) #define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu) + struct { /* Note. This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */ @@ -82,6 +210,7 @@ HB_FUNCOBJ (hb_bool); struct { private: + template constexpr auto impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) @@ -213,7 +342,9 @@ struct template auto impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN - (hb_deref (hb_forward (p)).has (hb_forward (v))) + ( + hb_deref (hb_forward (p)).has (hb_forward (v)) + ) template auto impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN @@ -267,7 +398,9 @@ struct template auto impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN - (hb_deref (hb_forward (f)).get (hb_forward (v))) + ( + hb_deref (hb_forward (f)).get (hb_forward (v)) + ) template auto impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN @@ -294,6 +427,40 @@ struct } HB_FUNCOBJ (hb_get); +struct +{ + private: + + template auto + impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN + ( + hb_forward (v2).cmp (hb_forward (v1)) == 0 + ) + + template auto + impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN + ( + hb_forward (v1).cmp (hb_forward (v2)) == 0 + ) + + template auto + impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN + ( + hb_forward (v1) == hb_forward (v2) + ) + + public: + + template auto + operator () (T1&& v1, T2 &&v2) const HB_AUTO_RETURN + ( + impl (hb_forward (v1), + hb_forward (v2), + hb_prioritize) + ) +} +HB_FUNCOBJ (hb_equal); + template struct hb_pair_t @@ -348,16 +515,23 @@ struct { template constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN - (hb_forward (a) <= hb_forward (b) ? hb_forward (a) : hb_forward (b)) + (a <= b ? hb_forward (a) : hb_forward (b)) } HB_FUNCOBJ (hb_min); struct { template constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN - (hb_forward (a) >= hb_forward (b) ? hb_forward (a) : hb_forward (b)) + (a >= b ? hb_forward (a) : hb_forward (b)) } HB_FUNCOBJ (hb_max); +struct +{ + template constexpr auto + operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN + (hb_min (hb_max (hb_forward (x), hb_forward (min)), hb_forward (max))) +} +HB_FUNCOBJ (hb_clamp); /* @@ -366,7 +540,7 @@ HB_FUNCOBJ (hb_max); /* Return the number of 1 bits in v. */ template -static inline HB_CONST_FUNC unsigned int +static inline unsigned int hb_popcount (T v) { #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) @@ -407,7 +581,7 @@ hb_popcount (T v) /* Returns the number of bits needed to store number */ template -static inline HB_CONST_FUNC unsigned int +static inline unsigned int hb_bit_storage (T v) { if (unlikely (!v)) return 0; @@ -481,10 +655,10 @@ hb_bit_storage (T v) /* Returns the number of zero bits in the least significant side of v */ template -static inline HB_CONST_FUNC unsigned int +static inline unsigned int hb_ctz (T v) { - if (unlikely (!v)) return 0; + if (unlikely (!v)) return 8 * sizeof (T); #if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) if (sizeof (T) <= sizeof (unsigned int)) @@ -568,6 +742,12 @@ static inline unsigned char TOUPPER (unsigned char c) { return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } static inline unsigned char TOLOWER (unsigned char c) { return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } +static inline bool ISHEX (unsigned char c) +{ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } +static inline unsigned char TOHEX (uint8_t c) +{ return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; } +static inline uint8_t FROMHEX (unsigned char c) +{ return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; } static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b) { return (a + (b - 1)) / b; } @@ -586,14 +766,16 @@ hb_memcmp (const void *a, const void *b, unsigned int len) /* It's illegal to pass NULL to memcmp(), even if len is zero. * So, wrap it. * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ - if (!len) return 0; + if (unlikely (!len)) return 0; return memcmp (a, b, len); } -static inline bool -hb_unsigned_mul_overflows (unsigned int count, unsigned int size) +static inline void * +hb_memset (void *s, int c, unsigned int n) { - return (size > 0) && (count >= ((unsigned int) -1) / size); + /* It's illegal to pass NULL to memset(), even if n is zero. */ + if (unlikely (!n)) return 0; + return memset (s, c, n); } static inline unsigned int @@ -623,30 +805,91 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) } +/* + * Overflow checking. + */ + +/* Consider __builtin_mul_overflow use here also */ +static inline bool +hb_unsigned_mul_overflows (unsigned int count, unsigned int size) +{ + return (size > 0) && (count >= ((unsigned int) -1) / size); +} + + /* * Sort and search. */ -template -static inline void * -hb_bsearch (const void *key, const void *base, - size_t nmemb, size_t size, - int (*compar)(const void *_key, const void *_item, Ts... _ds), - Ts... ds) + +template +static int +_hb_cmp_method (const void *pkey, const void *pval, Ts... ds) +{ + const K& key = * (const K*) pkey; + const V& val = * (const V*) pval; + + return val.cmp (key, ds...); +} + +template +static inline bool +hb_bsearch_impl (unsigned *pos, /* Out */ + const K& key, + V* base, size_t nmemb, size_t stride, + int (*compar)(const void *_key, const void *_item, Ts... _ds), + Ts... ds) { + /* This is our *only* bsearch implementation. */ + int min = 0, max = (int) nmemb - 1; while (min <= max) { int mid = ((unsigned int) min + (unsigned int) max) / 2; - const void *p = (const void *) (((const char *) base) + (mid * size)); - int c = compar (key, p, ds...); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + V* p = (V*) (((const char *) base) + (mid * stride)); +#pragma GCC diagnostic pop + int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...); if (c < 0) max = mid - 1; else if (c > 0) min = mid + 1; else - return (void *) p; + { + *pos = mid; + return true; + } } - return nullptr; + *pos = min; + return false; +} + +template +static inline V* +hb_bsearch (const K& key, V* base, + size_t nmemb, size_t stride = sizeof (V), + int (*compar)(const void *_key, const void *_item) = _hb_cmp_method) +{ + unsigned pos; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar) ? + (V*) (((const char *) base) + (pos * stride)) : nullptr; +#pragma GCC diagnostic pop +} +template +static inline V* +hb_bsearch (const K& key, V* base, + size_t nmemb, size_t stride, + int (*compar)(const void *_key, const void *_item, Ts... _ds), + Ts... ds) +{ + unsigned pos; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar, ds...) ? + (V*) (((const char *) base) + (pos * stride)) : nullptr; +#pragma GCC diagnostic pop } @@ -895,17 +1138,12 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) static inline hb_bool_t hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) { - /* Pain because we don't know whether s is nul-terminated. */ - char buf[64]; - len = hb_min (ARRAY_LENGTH (buf) - 1, len); - strncpy (buf, s, len); - buf[len] = '\0'; - - char *end; - errno = 0; - unsigned long v = strtoul (buf, &end, base); - if (errno) return false; - if (*end) return false; + unsigned int v; + const char *p = s; + const char *end = p + len; + if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base))) + return false; + *out = v; return true; } @@ -915,32 +1153,24 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o struct hb_bitwise_and { HB_PARTIALIZE(2); - static constexpr bool passthru_left = false; - static constexpr bool passthru_right = false; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b) } HB_FUNCOBJ (hb_bitwise_and); struct hb_bitwise_or { HB_PARTIALIZE(2); - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = true; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b) } HB_FUNCOBJ (hb_bitwise_or); struct hb_bitwise_xor { HB_PARTIALIZE(2); - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = true; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b) } HB_FUNCOBJ (hb_bitwise_xor); struct hb_bitwise_sub { HB_PARTIALIZE(2); - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = false; template constexpr auto operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b) } @@ -994,6 +1224,18 @@ struct operator () (const T &a) const HB_AUTO_RETURN (-a) } HB_FUNCOBJ (hb_neg); +struct +{ + template constexpr auto + operator () (T &a) const HB_AUTO_RETURN (++a) +} +HB_FUNCOBJ (hb_inc); +struct +{ + template constexpr auto + operator () (T &a) const HB_AUTO_RETURN (--a) +} +HB_FUNCOBJ (hb_dec); /* Compiler-assisted vectorization. */ diff --git a/src/hb-array.hh b/src/hb-array.hh index d60c2494946f625685b6eefa157a620b4b7629a2..9af98b103c08dd183fd6a70cc1363f2bbdb07e8c 100644 --- a/src/hb-array.hh +++ b/src/hb-array.hh @@ -50,7 +50,7 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> template hb_array_t (const hb_array_t
&o) : - hb_iter_with_fallback_t, Type&> (), + hb_iter_with_fallback_t (), arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {} template @@ -99,14 +99,21 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> template operator T * () const { return arrayZ; } HB_INTERNAL bool operator == (const hb_array_t &o) const; - HB_INTERNAL uint32_t hash () const; + + uint32_t hash () const { + uint32_t current = 0; + for (unsigned int i = 0; i < this->length; i++) { + current = current * 31 + hb_hash (this->arrayZ[i]); + } + return current; + } /* * Compare, Sort, and Search. */ /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */ - int cmp (const hb_array_t &a) const + int cmp (const hb_array_t &a) const { if (length != a.length) return (int) a.length - (int) length; @@ -114,40 +121,47 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> } HB_INTERNAL static int cmp (const void *pa, const void *pb) { - hb_array_t *a = (hb_array_t *) pa; - hb_array_t *b = (hb_array_t *) pb; + hb_array_t *a = (hb_array_t *) pa; + hb_array_t *b = (hb_array_t *) pb; return b->cmp (*a); } template Type *lsearch (const T &x, Type *not_found = nullptr) { - unsigned int count = length; - for (unsigned int i = 0; i < count; i++) - if (!this->arrayZ[i].cmp (x)) - return &this->arrayZ[i]; - return not_found; + unsigned i; + return lfind (x, &i) ? &this->arrayZ[i] : not_found; } template const Type *lsearch (const T &x, const Type *not_found = nullptr) const { - unsigned int count = length; - for (unsigned int i = 0; i < count; i++) - if (!this->arrayZ[i].cmp (x)) - return &this->arrayZ[i]; - return not_found; + unsigned i; + return lfind (x, &i) ? &this->arrayZ[i] : not_found; + } + template + bool lfind (const T &x, unsigned *pos = nullptr) const + { + for (unsigned i = 0; i < length; ++i) + if (hb_equal (x, this->arrayZ[i])) + { + if (pos) + *pos = i; + return true; + } + + return false; } hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*)) { if (likely (length)) - hb_qsort (arrayZ, length, this->item_size, cmp_); + hb_qsort (arrayZ, length, this->get_item_size (), cmp_); return hb_sorted_array_t (*this); } hb_sorted_array_t qsort () { if (likely (length)) - hb_qsort (arrayZ, length, this->item_size, Type::cmp); + hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp); return hb_sorted_array_t (*this); } void qsort (unsigned int start, unsigned int end) @@ -155,16 +169,34 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> end = hb_min (end, length); assert (start <= end); if (likely (start < end)) - hb_qsort (arrayZ + start, end - start, this->item_size, Type::cmp); + hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp); } /* * Other methods. */ - unsigned int get_size () const { return length * this->item_size; } + unsigned int get_size () const { return length * this->get_item_size (); } - hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const + /* + * Reverse the order of items in this array in the range [start, end). + */ + void reverse (unsigned start = 0, unsigned end = -1) + { + start = hb_min (start, length); + end = hb_min (end, length); + + if (end < start + 2) + return; + + for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) { + Type temp = arrayZ[rhs]; + arrayZ[rhs] = arrayZ[lhs]; + arrayZ[lhs] = temp; + } + } + + hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const { if (!start_offset && !seg_count) return *this; @@ -176,11 +208,29 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> count -= start_offset; if (seg_count) count = *seg_count = hb_min (count, *seg_count); - return hb_array_t (arrayZ + start_offset, count); + return hb_array_t (arrayZ + start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const + hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const { return sub_array (start_offset, &seg_count); } + hb_array_t truncate (unsigned length) const { return sub_array (0, length); } + + template + const T *as () const + { return length < hb_min_size (T) ? &Null (T) : reinterpret_cast (arrayZ); } + + template + bool check_range (const T *p, unsigned int size = T::static_size) const + { + return arrayZ <= ((const char *) p) + && ((const char *) p) <= arrayZ + length + && (unsigned int) (arrayZ + length - (const char *) p) >= size; + } + /* Only call if you allocated the underlying array using malloc() or similar. */ void free () { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; } @@ -228,7 +278,7 @@ struct hb_sorted_array_t : hb_iter_t, Type&>, hb_array_t { - typedef hb_iter_t, Type&> iter_base_t; + typedef hb_iter_t iter_base_t; HB_ITER_USING (iter_base_t); static constexpr bool is_random_access_iterator = true; static constexpr bool is_sorted_iterator = true; @@ -241,7 +291,7 @@ struct hb_sorted_array_t : template hb_sorted_array_t (const hb_array_t &o) : - hb_iter_t, Type&> (), + hb_iter_t (), hb_array_t (o) {} template @@ -252,11 +302,13 @@ struct hb_sorted_array_t : bool operator != (const hb_sorted_array_t& o) const { return this->arrayZ != o.arrayZ || this->length != o.length; } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const - { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const + { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); } + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const { return sub_array (start_offset, &seg_count); } + hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); } + template Type *bsearch (const T &x, Type *not_found = nullptr) { @@ -271,26 +323,18 @@ struct hb_sorted_array_t : } template bool bfind (const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { - int min = 0, max = (int) this->length - 1; - const Type *array = this->arrayZ; - while (min <= max) + unsigned pos; + + if (bsearch_impl (x, &pos)) { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - int c = array[mid].cmp (x); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - { - if (i) - *i = mid; - return true; - } + if (i) + *i = pos; + return true; } + if (i) { switch (not_found) @@ -303,14 +347,22 @@ struct hb_sorted_array_t : break; case HB_BFIND_NOT_FOUND_STORE_CLOSEST: - if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0)) - max++; - *i = max; + *i = pos; break; } } return false; } + template + bool bsearch_impl (const T &x, unsigned *pos) const + { + return hb_bsearch_impl (pos, + x, + this->arrayZ, + this->length, + sizeof (Type), + _hb_cmp_method); + } }; template inline hb_sorted_array_t hb_sorted_array (T *array, unsigned int length) @@ -322,27 +374,35 @@ hb_sorted_array (T (&array_)[length_]) template bool hb_array_t::operator == (const hb_array_t &o) const { - return length == o.length && - + hb_zip (*this, o) - | hb_map ([] (hb_pair_t &&_) { return _.first == _.second; }) - | hb_all - ; + if (o.length != this->length) return false; + for (unsigned int i = 0; i < this->length; i++) { + if (this->arrayZ[i] != o.arrayZ[i]) return false; + } + return true; } -template -uint32_t hb_array_t::hash () const -{ - return - + hb_iter (*this) - | hb_map (hb_hash) - | hb_reduce ([] (uint32_t a, uint32_t b) { return a * 31 + b; }, 0) - ; + +/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */ + +template <> +inline uint32_t hb_array_t::hash () const { + uint32_t current = 0; + for (unsigned int i = 0; i < this->length; i++) + current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); + return current; +} + +template <> +inline uint32_t hb_array_t::hash () const { + uint32_t current = 0; + for (unsigned int i = 0; i < this->length; i++) + current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); + return current; } + typedef hb_array_t hb_bytes_t; typedef hb_array_t hb_ubytes_t; -/* TODO Specialize opeator==/hash() for hb_bytes_t and hb_ubytes_t. */ -//template <> -//uint32_t hb_array_t::hash () const { return 0; } + #endif /* HB_ARRAY_HH */ diff --git a/src/hb-atomic.hh b/src/hb-atomic.hh index 09d88937c238f1cbfc0f9220364d5974961df14c..93265f655f7b12ffca5419a3ef9296edc6fa6d44 100644 --- a/src/hb-atomic.hh +++ b/src/hb-atomic.hh @@ -52,7 +52,7 @@ #elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE) -/* C++11-style GCC primitives. */ +/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */ #define _hb_memory_barrier() __sync_synchronize () @@ -73,7 +73,8 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) } #define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) -#elif !defined(HB_NO_MT) && __cplusplus >= 201103L + +#elif !defined(HB_NO_MT) /* C++11 atomics. */ @@ -101,136 +102,19 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N)) -#elif !defined(HB_NO_MT) && defined(_WIN32) - -#include - -static inline void _hb_memory_barrier () -{ -#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION) - /* MinGW has a convoluted history of supporting MemoryBarrier. */ - LONG dummy = 0; - InterlockedExchange (&dummy, 1); -#else - MemoryBarrier (); -#endif -} -#define _hb_memory_barrier() _hb_memory_barrier () - -#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V)) -static_assert ((sizeof (LONG) == sizeof (int)), ""); - -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O)) - - -#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) - -#define _hb_memory_barrier() __sync_synchronize () - -#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V)) - -#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N)) - - -#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS) - -#include -#include - -#define _hb_memory_r_barrier() __machine_r_barrier () -#define _hb_memory_w_barrier() __machine_w_barrier () -#define _hb_memory_barrier() __machine_rw_barrier () - -static inline int _hb_fetch_and_add (int *AI, int V) -{ - _hb_memory_w_barrier (); - int result = atomic_add_int_nv ((uint_t *) AI, V) - V; - _hb_memory_r_barrier (); - return result; -} -static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N) -{ - _hb_memory_w_barrier (); - bool result = atomic_cas_ptr (P, O, N) == O; - _hb_memory_r_barrier (); - return result; -} - -#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V)) - -#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N)) - - -#elif !defined(HB_NO_MT) && defined(__APPLE__) - -#include -#ifdef __MAC_OS_X_MIN_REQUIRED -#include -#elif defined(__IPHONE_OS_MIN_REQUIRED) -#include -#endif - -#define _hb_memory_barrier() OSMemoryBarrier () - -#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V)) +#elif defined(HB_NO_MT) -#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100) -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P)) -#else -#if __ppc64__ || __x86_64__ || __aarch64__ -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P)) -#else -#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P)) -#endif -#endif - - -#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__)) - -#include - -#define _hb_memory_barrier() __lwsync () - -static inline int _hb_fetch_and_add (int *AI, int V) -{ - _hb_memory_barrier (); - int result = __fetch_and_add (AI, V); - _hb_memory_barrier (); - return result; -} -static inline bool _hb_compare_and_swaplp (long *P, long O, long N) -{ - _hb_memory_barrier (); - bool result = __compare_and_swaplp (P, &O, N); - _hb_memory_barrier (); - return result; -} - -#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V)) - -#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N)) -static_assert ((sizeof (long) == sizeof (void *)), ""); - - -#elif !defined(HB_NO_MT) - -#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */ +#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) #define _hb_memory_barrier() do {} while (0) -#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) - #define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) -#else /* HB_NO_MT */ - -#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V)) - -#define _hb_memory_barrier() do {} while (0) - -#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false) +#else +#error "Could not find any system to define atomic_int macros." +#error "Check hb-atomic.hh for possible resolutions." #endif @@ -265,9 +149,11 @@ inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory #endif -#define HB_ATOMIC_INT_INIT(V) {V} struct hb_atomic_int_t { + hb_atomic_int_t () = default; + constexpr hb_atomic_int_t (int v) : v (v) {} + void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } void set (int v_) { hb_atomic_int_impl_set (&v, v_); } int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } @@ -275,16 +161,17 @@ struct hb_atomic_int_t int inc () { return hb_atomic_int_impl_add (&v, 1); } int dec () { return hb_atomic_int_impl_add (&v, -1); } - int v; + int v = 0; }; - -#define HB_ATOMIC_PTR_INIT(V) {V} template struct hb_atomic_ptr_t { typedef hb_remove_pointer

T; + hb_atomic_ptr_t () = default; + constexpr hb_atomic_ptr_t (T* v) : v (v) {} + void init (T* v_ = nullptr) { set_relaxed (v_); } void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } @@ -294,7 +181,7 @@ struct hb_atomic_ptr_t T * operator -> () const { return get (); } template operator C * () const { return get (); } - T *v; + T *v = nullptr; }; diff --git a/src/hb-bimap.hh b/src/hb-bimap.hh index a773951abdf299900d8159ff1c8a9999fa7b3b51..e9f3a6a52df74b33dc9366e37a897f4cc347f20a 100644 --- a/src/hb-bimap.hh +++ b/src/hb-bimap.hh @@ -94,6 +94,14 @@ struct hb_bimap_t /* Inremental bimap: only lhs is given, rhs is incrementally assigned */ struct hb_inc_bimap_t : hb_bimap_t { + hb_inc_bimap_t () { init (); } + + void init () + { + hb_bimap_t::init (); + next_value = 0; + } + /* Add a mapping from lhs to rhs with a unique value if lhs is unknown. * Return the rhs value as the result. */ @@ -102,12 +110,24 @@ struct hb_inc_bimap_t : hb_bimap_t hb_codepoint_t rhs = forw_map[lhs]; if (rhs == HB_MAP_VALUE_INVALID) { - rhs = get_population (); + rhs = next_value++; set (lhs, rhs); } return rhs; } + hb_codepoint_t skip () + { return next_value++; } + + hb_codepoint_t get_next_value () const + { return next_value; } + + void add_set (const hb_set_t *set) + { + hb_codepoint_t i = HB_SET_VALUE_INVALID; + while (hb_set_next (set, &i)) add (i); + } + /* Create an identity map. */ bool identity (unsigned int size) { @@ -131,13 +151,16 @@ struct hb_inc_bimap_t : hb_bimap_t for (hb_codepoint_t rhs = 0; rhs < count; rhs++) work[rhs] = back_map[rhs]; - + work.qsort (cmp_id); - + clear (); for (hb_codepoint_t rhs = 0; rhs < count; rhs++) set (work[rhs], rhs); } + + protected: + unsigned int next_value; }; #endif /* HB_BIMAP_HH */ diff --git a/src/hb-blob.cc b/src/hb-blob.cc index 9ed26bd2fa3b434680e54c2f4798a57f85bc2f04..71b1b1fc4f86f0688c0eee207041c669b6aa2295 100644 --- a/src/hb-blob.cc +++ b/src/hb-blob.cc @@ -25,18 +25,6 @@ * Red Hat Author(s): Behdad Esfahbod */ - -/* https://github.com/harfbuzz/harfbuzz/issues/1308 - * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html - * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html - */ -#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-macros" -#define _POSIX_C_SOURCE 200809L -#pragma GCC diagnostic pop -#endif - #include "hb.hh" #include "hb-blob.hh" @@ -47,10 +35,6 @@ #include #endif /* HAVE_SYS_MMAN_H */ -#include -#include -#include - /** * SECTION: hb-blob @@ -71,7 +55,7 @@ * @length: Length of @data in bytes. * @mode: Memory mode for @data. * @user_data: Data parameter to pass to @destroy. - * @destroy: Callback to call when @data is not needed anymore. + * @destroy: (nullable): Callback to call when @data is not needed anymore. * * Creates a new "blob" object wrapping @data. The @mode parameter is used * to negotiate ownership and lifecycle of @data. @@ -129,7 +113,7 @@ _hb_blob_destroy (void *data) * @length: Length of sub-blob. * * Returns a blob that represents a range of bytes in @parent. The new - * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it + * blob is always created with #HB_MEMORY_MODE_READONLY, meaning that it * will never modify data in the parent blob. The parent data is not * expected to be modified, and will result in undefined behavior if it * is. @@ -169,7 +153,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent, * * Makes a writable copy of @blob. * - * Return value: New blob, or nullptr if allocation failed. + * Return value: The new blob, or nullptr if allocation failed * * Since: 1.8.0 **/ @@ -195,14 +179,14 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob) * * See TODO:link object types for more information. * - * Return value: (transfer full): the empty blob. + * Return value: (transfer full): The empty blob. * * Since: 0.9.2 **/ hb_blob_t * hb_blob_get_empty () { - return const_cast (&Null(hb_blob_t)); + return const_cast (&Null (hb_blob_t)); } /** @@ -247,13 +231,15 @@ hb_blob_destroy (hb_blob_t *blob) /** * hb_blob_set_user_data: (skip) - * @blob: a blob. - * @key: key for data to set. - * @data: data to set. - * @destroy: callback to call when @data is not needed anymore. - * @replace: whether to replace an existing data with the same key. + * @blob: An #hb_blob_t + * @key: The user-data key to set + * @data: A pointer to the user data to set + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * - * Return value: + * Attaches a user-data key/data pair to the specified blob. + * + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ @@ -269,12 +255,13 @@ hb_blob_set_user_data (hb_blob_t *blob, /** * hb_blob_get_user_data: (skip) - * @blob: a blob. - * @key: key for data to get. - * + * @blob: a blob + * @key: The user-data key to query * + * Fetches the user data associated with the specified key, + * attached to the specified font-functions structure. * - * Return value: (transfer none): + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.2 **/ @@ -288,9 +275,9 @@ hb_blob_get_user_data (hb_blob_t *blob, /** * hb_blob_make_immutable: - * @blob: a blob. - * + * @blob: a blob * + * Makes a blob immutable. * * Since: 0.9.2 **/ @@ -307,9 +294,9 @@ hb_blob_make_immutable (hb_blob_t *blob) * hb_blob_is_immutable: * @blob: a blob. * + * Tests whether a blob is immutable. * - * - * Return value: TODO + * Return value: %true if @blob is immutable, %false otherwise * * Since: 0.9.2 **/ @@ -324,9 +311,9 @@ hb_blob_is_immutable (hb_blob_t *blob) * hb_blob_get_length: * @blob: a blob. * + * Fetches the length of a blob's data. * - * - * Return value: the length of blob data in bytes. + * Return value: the length of @blob data in bytes. * * Since: 0.9.2 **/ @@ -339,11 +326,11 @@ hb_blob_get_length (hb_blob_t *blob) /** * hb_blob_get_data: * @blob: a blob. - * @length: (out): - * + * @length: (out): The length in bytes of the data retrieved * + * Fetches the data from a blob. * - * Returns: (transfer none) (array length=length): + * Returns: (transfer none) (array length=length): the byte data of @blob. * * Since: 0.9.2 **/ @@ -375,16 +362,14 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length) char * hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) { - if (!blob->try_make_writable ()) { - if (length) - *length = 0; - + if (hb_object_is_immutable (blob) || + !blob->try_make_writable ()) + { + if (length) *length = 0; return nullptr; } - if (length) - *length = blob->length; - + if (length) *length = blob->length; return const_cast (blob->data); } @@ -450,8 +435,8 @@ hb_blob_t::try_make_writable_inplace () bool hb_blob_t::try_make_writable () { - if (hb_object_is_immutable (this)) - return false; + if (unlikely (!length)) + mode = HB_MEMORY_MODE_WRITABLE; if (this->mode == HB_MEMORY_MODE_WRITABLE) return true; @@ -489,6 +474,9 @@ hb_blob_t::try_make_writable () #ifndef HB_NO_OPEN #ifdef HAVE_MMAP +# if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__) +# include +# endif # include # include # include @@ -533,11 +521,47 @@ _hb_mapped_file_destroy (void *file_) } #endif +#ifdef _PATH_RSRCFORKSPEC +static int +_open_resource_fork (const char *file_name, hb_mapped_file_t *file) +{ + size_t name_len = strlen (file_name); + size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC); + + char *rsrc_name = (char *) malloc (len); + if (unlikely (!rsrc_name)) return -1; + + strncpy (rsrc_name, file_name, name_len); + strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC, + sizeof (_PATH_RSRCFORKSPEC) - 1); + + int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0); + free (rsrc_name); + + if (fd != -1) + { + struct stat st; + if (fstat (fd, &st) != -1) + file->length = (unsigned long) st.st_size; + else + { + close (fd); + fd = -1; + } + } + + return fd; +} +#endif + /** * hb_blob_create_from_file: - * @file_name: font filename. + * @file_name: A font filename + * + * Creates a new blob containing the data from the + * specified binary font file. * - * Returns: A hb_blob_t pointer with the content of the file + * Returns: An #hb_blob_t pointer with the content of the file * * Since: 1.7.7 **/ @@ -557,6 +581,19 @@ hb_blob_create_from_file (const char *file_name) if (unlikely (fstat (fd, &st) == -1)) goto fail; file->length = (unsigned long) st.st_size; + +#ifdef _PATH_RSRCFORKSPEC + if (unlikely (file->length == 0)) + { + int rfd = _open_resource_fork (file_name, file); + if (rfd != -1) + { + close (fd); + fd = rfd; + } + } +#endif + file->contents = (char *) mmap (nullptr, file->length, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); @@ -580,9 +617,9 @@ fail_without_close: HANDLE fd; unsigned int size = strlen (file_name) + 1; wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size); - if (unlikely (wchar_file_name == nullptr)) goto fail_without_close; + if (unlikely (!wchar_file_name)) goto fail_without_close; mbstowcs (wchar_file_name, file_name, size); -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) { CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); @@ -592,7 +629,7 @@ fail_without_close: ceparams.lpSecurityAttributes = nullptr; ceparams.hTemplateFile = nullptr; fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, - OPEN_EXISTING, &ceparams); + OPEN_EXISTING, &ceparams); } #else fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, @@ -603,7 +640,7 @@ fail_without_close: if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) { LARGE_INTEGER length; GetFileSizeEx (fd, &length); @@ -614,14 +651,14 @@ fail_without_close: file->length = (unsigned long) GetFileSize (fd, nullptr); file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); #endif - if (unlikely (file->mapping == nullptr)) goto fail; + if (unlikely (!file->mapping)) goto fail; -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); #else file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); #endif - if (unlikely (file->contents == nullptr)) goto fail; + if (unlikely (!file->contents)) goto fail; CloseHandle (fd); return hb_blob_create (file->contents, file->length, @@ -639,10 +676,10 @@ fail_without_close: It's used as a fallback for systems without mmap or to read from pipes */ unsigned long len = 0, allocated = BUFSIZ * 16; char *data = (char *) malloc (allocated); - if (unlikely (data == nullptr)) return hb_blob_get_empty (); + if (unlikely (!data)) return hb_blob_get_empty (); FILE *fp = fopen (file_name, "rb"); - if (unlikely (fp == nullptr)) goto fread_fail_without_close; + if (unlikely (!fp)) goto fread_fail_without_close; while (!feof (fp)) { @@ -653,7 +690,7 @@ fail_without_close: can cover files like that but lets limit our fallback reader */ if (unlikely (allocated > (2 << 28))) goto fread_fail; char *new_data = (char *) realloc (data, allocated); - if (unlikely (new_data == nullptr)) goto fread_fail; + if (unlikely (!new_data)) goto fread_fail; data = new_data; } @@ -667,9 +704,10 @@ fail_without_close: len += addition; } + fclose (fp); return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data, - (hb_destroy_func_t) free); + (hb_destroy_func_t) free); fread_fail: fclose (fp); diff --git a/src/hb-blob.h b/src/hb-blob.h index f80e9af2d9e7e329f738542124bc2746aad6601d..86f12788d20be1be112a4bd8a2af1f5c508db4ac 100644 --- a/src/hb-blob.h +++ b/src/hb-blob.h @@ -24,7 +24,7 @@ * Red Hat Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -36,25 +36,36 @@ HB_BEGIN_DECLS -/* - * Note re various memory-modes: +/** + * hb_memory_mode_t: + * @HB_MEMORY_MODE_DUPLICATE: HarfBuzz immediately makes a copy of the data. + * @HB_MEMORY_MODE_READONLY: HarfBuzz client will never modify the data, + * and HarfBuzz will never modify the data. + * @HB_MEMORY_MODE_WRITABLE: HarfBuzz client made a copy of the data solely + * for HarfBuzz, so HarfBuzz may modify the data. + * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE: See above + * + * Data type holding the memory modes available to + * client programs. + * + * Regarding these various memory-modes: * * - In no case shall the HarfBuzz client modify memory * that is passed to HarfBuzz in a blob. If there is - * any such possibility, MODE_DUPLICATE should be used + * any such possibility, @HB_MEMORY_MODE_DUPLICATE should be used * such that HarfBuzz makes a copy immediately, * - * - Use MODE_READONLY otherwise, unless you really really + * - Use @HB_MEMORY_MODE_READONLY otherwise, unless you really really * really know what you are doing, * - * - MODE_WRITABLE is appropriate if you really made a + * - @HB_MEMORY_MODE_WRITABLE is appropriate if you really made a * copy of data solely for the purpose of passing to * HarfBuzz and doing that just once (no reuse!), * - * - If the font is mmap()ed, it's ok to use - * READONLY_MAY_MAKE_WRITABLE, however, using that mode - * correctly is very tricky. Use MODE_READONLY instead. - */ + * - If the font is mmap()ed, it's okay to use + * @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode + * correctly is very tricky. Use @HB_MEMORY_MODE_READONLY instead. + **/ typedef enum { HB_MEMORY_MODE_DUPLICATE, HB_MEMORY_MODE_READONLY, @@ -62,6 +73,14 @@ typedef enum { HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE } hb_memory_mode_t; +/** + * hb_blob_t: + * + * Data type for blobs. A blob wraps a chunk of binary + * data and facilitates its lifecycle management between + * a client program and HarfBuzz. + * + **/ typedef struct hb_blob_t hb_blob_t; HB_EXTERN hb_blob_t * diff --git a/src/hb-blob.hh b/src/hb-blob.hh index cff492fa05a13e51ee9b65d48f33424cd25f2152..b03dfc138097ec4d4d9a5c0a1846f7603d4e27e2 100644 --- a/src/hb-blob.hh +++ b/src/hb-blob.hh @@ -54,13 +54,9 @@ struct hb_blob_t HB_INTERNAL bool try_make_writable_inplace (); HB_INTERNAL bool try_make_writable_inplace_unix (); + hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); } template - const Type* as () const - { - return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast (data); - } - hb_bytes_t as_bytes () const - { return hb_bytes_t (data, length); } + const Type* as () const { return as_bytes ().as (); } public: hb_object_header_t header; @@ -94,6 +90,7 @@ struct hb_blob_ptr_t unsigned int get_length () const { return b.get ()->length; } void destroy () { hb_blob_destroy (b.get ()); b = nullptr; } + private: hb_nonnull_ptr_t b; }; diff --git a/src/hb-buffer-deserialize-json.hh b/src/hb-buffer-deserialize-json.hh index 1f9e2e91db89ec50521df4921388f797b7ca664f..01db2954985844da7296335c0c32207a8b79c2a4 100644 --- a/src/hb-buffer-deserialize-json.hh +++ b/src/hb-buffer-deserialize-json.hh @@ -1,30 +1,29 @@ - #line 1 "hb-buffer-deserialize-json.rl" /* - * Copyright © 2013 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ +* Copyright © 2013 Google, Inc. +* +* This is part of HarfBuzz, a text shaping library. +* +* Permission is hereby granted, without written agreement and without +* license or royalty fees, to use, copy, modify, and distribute this +* software and its documentation for any purpose, provided that the +* above copyright notice and the following two paragraphs appear in +* all copies of this software. +* +* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +* +* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +* +* Google Author(s): Behdad Esfahbod +*/ #ifndef HB_BUFFER_DESERIALIZE_JSON_HH #define HB_BUFFER_DESERIALIZE_JSON_HH @@ -32,612 +31,577 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-json.hh" +#line 35 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { - 0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, - 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, - 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, - 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, - 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, - 65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0 + 1u, 0u, 0u, 18u, 0u, 2u, 10u, 15u, + 16u, 17u, 2u, 2u, 0u, 7u, 0u, 6u, + 5u, 6u, 0u, 19u, 0u, 19u, 0u, 19u, + 2u, 2u, 0u, 7u, 0u, 6u, 5u, 6u, + 0u, 19u, 0u, 19u, 14u, 14u, 2u, 2u, + 0u, 7u, 0u, 6u, 0u, 19u, 0u, 19u, + 16u, 17u, 2u, 2u, 0u, 7u, 0u, 6u, + 5u, 6u, 0u, 19u, 0u, 19u, 2u, 2u, + 0u, 7u, 0u, 6u, 5u, 6u, 0u, 19u, + 0u, 19u, 2u, 2u, 0u, 7u, 0u, 6u, + 2u, 8u, 0u, 19u, 2u, 8u, 0u, 19u, + 0u, 19u, 2u, 2u, 0u, 7u, 0u, 6u, + 0u, 19u, 0u, 9u, 0u, 18u, 1u, 0u, + 0u }; -static const char _deserialize_json_key_spans[] = { - 0, 115, 26, 7, 2, 1, 50, 49, - 10, 117, 117, 117, 1, 50, 49, 10, - 117, 117, 1, 1, 50, 49, 117, 117, - 2, 1, 50, 49, 10, 117, 117, 1, - 50, 49, 10, 117, 117, 1, 50, 49, - 58, 89, 117, 117, 85, 115, 0 +static const signed char _deserialize_json_char_class[] = { + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 4, 1, 1, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 8, 9, 1, 1, 1, + 10, 1, 11, 12, 1, 1, 13, 1, + 1, 1, 1, 14, 1, 1, 1, 1, + 1, 1, 1, 1, 15, 1, 1, 16, + 17, 1, 18, 1, 19, 0 }; static const short _deserialize_json_index_offsets[] = { - 0, 0, 116, 143, 151, 154, 156, 207, - 257, 268, 386, 504, 622, 624, 675, 725, - 736, 854, 972, 974, 976, 1027, 1077, 1195, - 1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666, - 1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069, - 2119, 2178, 2268, 2386, 2504, 2590, 2706 + 0, 0, 19, 22, 28, 30, 31, 39, + 46, 48, 68, 88, 108, 109, 117, 124, + 126, 146, 166, 167, 168, 176, 183, 203, + 223, 225, 226, 234, 241, 243, 263, 283, + 284, 292, 299, 301, 321, 341, 342, 350, + 357, 364, 384, 391, 411, 431, 432, 440, + 447, 467, 477, 496, 0 +}; + +static const signed char _deserialize_json_indicies[] = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 3, 0, 4, 5, 6, + 7, 8, 0, 9, 10, 11, 12, 12, + 0, 0, 0, 0, 0, 0, 13, 13, + 0, 0, 0, 14, 15, 16, 18, 19, + 20, 0, 0, 21, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 22, 23, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 24, + 20, 0, 0, 21, 0, 19, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 22, 25, 25, 0, 0, + 0, 0, 0, 0, 26, 26, 0, 0, + 0, 27, 28, 29, 31, 32, 33, 0, + 0, 34, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 35, 33, 0, 0, 34, 0, 32, + 32, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 35, 36, 37, + 37, 0, 0, 0, 0, 0, 0, 38, + 38, 0, 0, 0, 0, 39, 40, 42, + 0, 0, 43, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 44, 42, 0, 0, 43, 0, + 45, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 44, 46, + 47, 48, 48, 0, 0, 0, 0, 0, + 0, 49, 49, 0, 0, 0, 50, 51, + 52, 54, 55, 56, 0, 0, 57, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 58, 56, + 0, 0, 57, 0, 55, 55, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 58, 59, 59, 0, 0, 0, + 0, 0, 0, 60, 60, 0, 0, 0, + 61, 62, 63, 65, 66, 67, 0, 0, + 68, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 69, 67, 0, 0, 68, 0, 66, 66, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 69, 70, 70, 0, + 0, 0, 0, 0, 0, 71, 71, 0, + 72, 0, 0, 73, 74, 76, 75, 75, + 75, 75, 75, 77, 79, 0, 0, 80, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 81, + 75, 0, 0, 0, 0, 0, 75, 83, + 0, 0, 84, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 85, 83, 0, 0, 84, 0, + 87, 87, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 85, 88, + 88, 0, 0, 0, 0, 0, 0, 89, + 89, 0, 0, 0, 0, 90, 91, 83, + 0, 0, 84, 0, 93, 93, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 85, 94, 0, 0, 95, 0, + 0, 0, 0, 0, 96, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0 }; -static const char _deserialize_json_indicies[] = { - 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 1, 3, 3, 3, - 3, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 1, 4, 1, - 5, 1, 6, 7, 1, 1, 8, 1, - 9, 10, 1, 11, 1, 11, 11, 11, - 11, 11, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 11, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 12, 1, - 12, 12, 12, 12, 12, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 12, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 13, 1, 1, 14, - 15, 15, 15, 15, 15, 15, 15, 15, - 15, 1, 16, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 1, 18, 18, 18, - 18, 18, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 18, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 19, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 20, 1, 21, 21, 21, 21, 21, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 21, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 22, - 1, 18, 18, 18, 18, 18, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 18, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 19, 1, 1, 1, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 20, 1, 23, - 1, 23, 23, 23, 23, 23, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 23, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 24, 1, 24, 24, 24, 24, - 24, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 24, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 25, 1, 1, 26, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 1, 28, 29, - 29, 29, 29, 29, 29, 29, 29, 29, - 1, 30, 30, 30, 30, 30, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 30, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 31, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 32, 1, 30, - 30, 30, 30, 30, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 30, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 31, 1, 1, 1, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 32, 1, 33, 1, 34, - 1, 34, 34, 34, 34, 34, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 34, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 35, 1, 35, 35, 35, 35, - 35, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 35, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 36, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 1, 38, 38, - 38, 38, 38, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 38, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 39, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 40, 1, 38, 38, 38, 38, - 38, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 38, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 39, - 1, 1, 1, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 40, 1, 42, 43, 1, 44, 1, 44, - 44, 44, 44, 44, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 44, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 45, 1, 45, 45, 45, 45, 45, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 46, 1, - 1, 47, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 1, 49, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 1, 51, - 51, 51, 51, 51, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 51, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 52, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 53, 1, 51, 51, 51, - 51, 51, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 51, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 52, 1, 1, 1, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 53, 1, 54, 1, 54, 54, 54, - 54, 54, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 54, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 55, 1, - 55, 55, 55, 55, 55, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 55, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 56, 1, 1, 57, - 58, 58, 58, 58, 58, 58, 58, 58, - 58, 1, 59, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 1, 61, 61, 61, - 61, 61, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 61, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 62, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 63, 1, 61, 61, 61, 61, 61, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 61, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 62, 1, - 1, 1, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 63, - 1, 64, 1, 64, 64, 64, 64, 64, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 64, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 65, 1, 65, 65, - 65, 65, 65, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 65, 1, 66, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 67, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 1, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 1, 1, 1, 1, 1, 1, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 1, 70, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 71, 71, - 1, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 1, 1, 1, 1, 1, - 1, 1, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 1, 1, 1, 1, - 71, 1, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 1, 72, 72, 72, - 72, 72, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 72, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 73, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 74, 1, 72, 72, 72, 72, 72, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 72, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 73, 1, - 1, 1, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 74, - 1, 76, 76, 76, 76, 76, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 76, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 77, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 78, 1, 0, - 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 1, 0 +static const signed char _deserialize_json_index_defaults[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 75, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 }; -static const char _deserialize_json_trans_targs[] = { - 1, 0, 2, 2, 3, 4, 18, 24, - 37, 5, 12, 6, 7, 8, 9, 11, - 9, 11, 10, 2, 44, 10, 44, 13, - 14, 15, 16, 17, 16, 17, 10, 2, - 44, 19, 20, 21, 22, 23, 10, 2, - 44, 23, 25, 31, 26, 27, 28, 29, - 30, 29, 30, 10, 2, 44, 32, 33, - 34, 35, 36, 35, 36, 10, 2, 44, - 38, 39, 40, 42, 43, 41, 10, 41, - 10, 2, 44, 43, 44, 45, 46 +static const signed char _deserialize_json_cond_targs[] = { + 0, 1, 2, 2, 3, 4, 18, 24, + 37, 45, 5, 12, 6, 7, 8, 9, + 11, 8, 9, 11, 10, 2, 49, 10, + 49, 13, 14, 15, 16, 17, 15, 16, + 17, 10, 2, 49, 19, 20, 21, 22, + 23, 22, 10, 2, 49, 23, 25, 31, + 26, 27, 28, 29, 30, 28, 29, 30, + 10, 2, 49, 32, 33, 34, 35, 36, + 34, 35, 36, 10, 2, 49, 38, 39, + 40, 43, 44, 40, 41, 42, 41, 10, + 2, 49, 43, 10, 2, 49, 44, 44, + 46, 47, 43, 48, 48, 48, 49, 50, + 51, 0 }; -static const char _deserialize_json_trans_actions[] = { - 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 2, 2, - 0, 0, 3, 3, 4, 0, 5, 0, - 0, 2, 2, 2, 0, 0, 6, 6, - 7, 0, 0, 0, 2, 2, 8, 8, - 9, 0, 0, 0, 0, 0, 2, 2, - 2, 0, 0, 10, 10, 11, 0, 0, - 2, 2, 2, 0, 0, 12, 12, 13, - 0, 0, 0, 2, 2, 2, 14, 0, - 15, 15, 16, 0, 0, 0, 0 +static const signed char _deserialize_json_cond_actions[] = { + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 0, 3, 3, 4, 0, + 5, 0, 0, 2, 2, 2, 0, 0, + 0, 6, 6, 7, 0, 0, 0, 2, + 2, 0, 8, 8, 9, 0, 0, 0, + 0, 0, 2, 2, 2, 0, 0, 0, + 10, 10, 11, 0, 0, 2, 2, 2, + 0, 0, 0, 12, 12, 13, 0, 0, + 2, 14, 14, 0, 15, 0, 0, 16, + 16, 17, 0, 18, 18, 19, 0, 15, + 0, 0, 20, 20, 0, 21, 0, 0, + 0, 0 }; static const int deserialize_json_start = 1; -static const int deserialize_json_first_final = 44; +static const int deserialize_json_first_final = 49; static const int deserialize_json_error = 0; static const int deserialize_json_en_main = 1; -#line 97 "hb-buffer-deserialize-json.rl" +#line 108 "hb-buffer-deserialize-json.rl" static hb_bool_t -_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer, - const char *buf, - unsigned int buf_len, - const char **end_ptr, - hb_font_t *font) +_hb_buffer_deserialize_json (hb_buffer_t *buffer, +const char *buf, +unsigned int buf_len, +const char **end_ptr, +hb_font_t *font) { - const char *p = buf, *pe = buf + buf_len; - - /* Ensure we have positions. */ - (void) hb_buffer_get_glyph_positions (buffer, nullptr); - - while (p < pe && ISSPACE (*p)) - p++; - if (p < pe && *p == (buffer->len ? ',' : '[')) - { - *end_ptr = ++p; - } - - const char *tok = nullptr; - int cs; - hb_glyph_info_t info = {0}; - hb_glyph_position_t pos = {0}; - -#line 466 "hb-buffer-deserialize-json.hh" + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, nullptr); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? ',' : '[')) + { + *end_ptr = ++p; + } + + const char *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + hb_glyph_position_t pos = {0}; + +#line 223 "hb-buffer-deserialize-json.hh" { - cs = deserialize_json_start; + cs = (int)deserialize_json_start; } - -#line 471 "hb-buffer-deserialize-json.hh" + +#line 228 "hb-buffer-deserialize-json.hh" { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _deserialize_json_trans_keys + (cs<<1); - _inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs]; - - _slen = _deserialize_json_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && - (*p) <= _keys[1] ? - (*p) - _keys[0] : _slen ]; - - cs = _deserialize_json_trans_targs[_trans]; - - if ( _deserialize_json_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _deserialize_json_trans_actions[_trans] ) { - case 1: + unsigned int _trans = 0; + const unsigned char * _keys; + const signed char * _inds; + int _ic; + _resume: {} + if ( p == pe ) + goto _out; + _keys = ( _deserialize_json_trans_keys + ((cs<<1))); + _inds = ( _deserialize_json_indicies + (_deserialize_json_index_offsets[cs])); + + if ( ( (*( p))) <= 125 && ( (*( p))) >= 9 ) { + _ic = (int)_deserialize_json_char_class[(int)( (*( p))) - 9]; + if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) ) + _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) )); + else + _trans = (unsigned int)_deserialize_json_index_defaults[cs]; + } + else { + _trans = (unsigned int)_deserialize_json_index_defaults[cs]; + } + + cs = (int)_deserialize_json_cond_targs[_trans]; + + if ( _deserialize_json_cond_actions[_trans] != 0 ) { + + switch ( _deserialize_json_cond_actions[_trans] ) { + case 1: { + { #line 38 "hb-buffer-deserialize-json.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} - break; - case 5: + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 264 "hb-buffer-deserialize-json.hh" + + + break; + } + case 5: { + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 2: + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 280 "hb-buffer-deserialize-json.hh" + + + break; + } + case 2: { + { #line 51 "hb-buffer-deserialize-json.rl" - { - tok = p; -} - break; - case 14: + + tok = p; + } + +#line 292 "hb-buffer-deserialize-json.hh" + + + break; + } + case 15: { + { #line 55 "hb-buffer-deserialize-json.rl" - { - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 15: -#line 62 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.codepoint)) return false; } - break; - case 8: -#line 63 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } - break; - case 10: -#line 64 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } - break; - case 12: -#line 65 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } - break; - case 3: + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 302 "hb-buffer-deserialize-json.hh" + + + break; + } + case 21: { + { +#line 56 "hb-buffer-deserialize-json.rl" + if (unlikely (!buffer->ensure_unicode ())) return false; } + +#line 312 "hb-buffer-deserialize-json.hh" + + + break; + } + case 16: { + { +#line 58 "hb-buffer-deserialize-json.rl" + + /* TODO Unescape \" and \\ if found. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 328 "hb-buffer-deserialize-json.hh" + + + break; + } + case 18: { + { #line 66 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } - break; - case 6: + if (!parse_uint (tok, p, &info.codepoint)) return false; } + +#line 338 "hb-buffer-deserialize-json.hh" + + + break; + } + case 8: { + { #line 67 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } - break; - case 16: -#line 62 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.codepoint)) return false; } + if (!parse_uint (tok, p, &info.cluster )) return false; } + +#line 348 "hb-buffer-deserialize-json.hh" + + + break; + } + case 10: { + { +#line 68 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.x_offset )) return false; } + +#line 358 "hb-buffer-deserialize-json.hh" + + + break; + } + case 12: { + { +#line 69 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.y_offset )) return false; } + +#line 368 "hb-buffer-deserialize-json.hh" + + + break; + } + case 3: { + { +#line 70 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.x_advance)) return false; } + +#line 378 "hb-buffer-deserialize-json.hh" + + + break; + } + case 6: { + { +#line 71 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.y_advance)) return false; } + +#line 388 "hb-buffer-deserialize-json.hh" + + + break; + } + case 14: { + { +#line 51 "hb-buffer-deserialize-json.rl" + + tok = p; + } + +#line 400 "hb-buffer-deserialize-json.hh" + + { +#line 55 "hb-buffer-deserialize-json.rl" + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 406 "hb-buffer-deserialize-json.hh" + + + break; + } + case 20: { + { +#line 51 "hb-buffer-deserialize-json.rl" + + tok = p; + } + +#line 418 "hb-buffer-deserialize-json.hh" + + { +#line 56 "hb-buffer-deserialize-json.rl" + if (unlikely (!buffer->ensure_unicode ())) return false; } + +#line 424 "hb-buffer-deserialize-json.hh" + + + break; + } + case 17: { + { +#line 58 "hb-buffer-deserialize-json.rl" + + /* TODO Unescape \" and \\ if found. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 440 "hb-buffer-deserialize-json.hh" + + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 9: -#line 63 "hb-buffer-deserialize-json.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 452 "hb-buffer-deserialize-json.hh" + + + break; + } + case 19: { + { +#line 66 "hb-buffer-deserialize-json.rl" + if (!parse_uint (tok, p, &info.codepoint)) return false; } + +#line 462 "hb-buffer-deserialize-json.hh" + + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 64 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 474 "hb-buffer-deserialize-json.hh" + + + break; + } + case 9: { + { +#line 67 "hb-buffer-deserialize-json.rl" + if (!parse_uint (tok, p, &info.cluster )) return false; } + +#line 484 "hb-buffer-deserialize-json.hh" + + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 13: -#line 65 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 496 "hb-buffer-deserialize-json.hh" + + + break; + } + case 11: { + { +#line 68 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.x_offset )) return false; } + +#line 506 "hb-buffer-deserialize-json.hh" + + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 4: -#line 66 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 518 "hb-buffer-deserialize-json.hh" + + + break; + } + case 13: { + { +#line 69 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.y_offset )) return false; } + +#line 528 "hb-buffer-deserialize-json.hh" + + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 7: -#line 67 "hb-buffer-deserialize-json.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 540 "hb-buffer-deserialize-json.hh" + + + break; + } + case 4: { + { +#line 70 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.x_advance)) return false; } + +#line 550 "hb-buffer-deserialize-json.hh" + + { #line 43 "hb-buffer-deserialize-json.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 624 "hb-buffer-deserialize-json.hh" - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - _out: {} + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 562 "hb-buffer-deserialize-json.hh" + + + break; + } + case 7: { + { +#line 71 "hb-buffer-deserialize-json.rl" + if (!parse_int (tok, p, &pos.y_advance)) return false; } + +#line 572 "hb-buffer-deserialize-json.hh" + + { +#line 43 "hb-buffer-deserialize-json.rl" + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 584 "hb-buffer-deserialize-json.hh" + + + break; + } + } + + } + + if ( cs != 0 ) { + p += 1; + goto _resume; + } + _out: {} } - -#line 125 "hb-buffer-deserialize-json.rl" - - - *end_ptr = p; - - return p == pe && *(p-1) != ']'; + +#line 136 "hb-buffer-deserialize-json.rl" + + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; } #endif /* HB_BUFFER_DESERIALIZE_JSON_HH */ diff --git a/src/hb-buffer-deserialize-json.rl b/src/hb-buffer-deserialize-json.rl index f3abb027b2092525e5d1438e3006238ad2413f0e..382423f6c7da8310a31677e97fe46a7ad159546c 100644 --- a/src/hb-buffer-deserialize-json.rl +++ b/src/hb-buffer-deserialize-json.rl @@ -52,14 +52,18 @@ action tok { tok = p; } -action parse_glyph { +action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; } +action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false; } + +action parse_glyph_name { + /* TODO Unescape \" and \\ if found. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) return false; } -action parse_gid { if (!parse_uint (tok, p, &info.codepoint)) return false; } +action parse_codepoint { if (!parse_uint (tok, p, &info.codepoint)) return false; } action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; } action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; } @@ -72,20 +76,27 @@ num = '-'? unum; comma = space* ',' space*; colon = space* ':' space*; -glyph_id = unum; -glyph_name = alpha (alnum|'_'|'.'|'-')*; +codepoint = unum; +glyph_name = '"' ([^\\"] | '\\' [\\"])* '"'; -glyph_string = '"' (glyph_name >tok %parse_glyph) '"'; -glyph_number = (glyph_id >tok %parse_gid); +parse_glyph_name = (glyph_name >tok %parse_glyph_name); +parse_codepoint = (codepoint >tok %parse_codepoint); -glyph = "\"g\"" colon (glyph_string | glyph_number); +glyph = "\"g\"" colon (parse_glyph_name | parse_codepoint); +unicode = "\"u\"" colon parse_codepoint; cluster = "\"cl\"" colon (unum >tok %parse_cluster); xoffset = "\"dx\"" colon (num >tok %parse_x_offset); yoffset = "\"dy\"" colon (num >tok %parse_y_offset); xadvance= "\"ax\"" colon (num >tok %parse_x_advance); yadvance= "\"ay\"" colon (num >tok %parse_y_advance); -element = glyph | cluster | xoffset | yoffset | xadvance | yadvance; +element = glyph @ensure_glyphs + | unicode @ensure_unicode + | cluster + | xoffset + | yoffset + | xadvance + | yadvance; item = ( '{' space* element (comma element)* space* '}') >clear_item @@ -97,7 +108,7 @@ main := space* item (comma item)* space* (','|']')?; }%% static hb_bool_t -_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer, +_hb_buffer_deserialize_json (hb_buffer_t *buffer, const char *buf, unsigned int buf_len, const char **end_ptr, diff --git a/src/hb-buffer-deserialize-text.hh b/src/hb-buffer-deserialize-text.hh index 67f0a1252f834752d3e887e2137c02348e70ec38..fb36f5601595c4e6f58f099afa41a9d2745965d6 100644 --- a/src/hb-buffer-deserialize-text.hh +++ b/src/hb-buffer-deserialize-text.hh @@ -1,30 +1,29 @@ - #line 1 "hb-buffer-deserialize-text.rl" /* - * Copyright © 2013 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ +* Copyright © 2013 Google, Inc. +* +* This is part of HarfBuzz, a text shaping library. +* +* Permission is hereby granted, without written agreement and without +* license or royalty fees, to use, copy, modify, and distribute this +* software and its documentation for any purpose, provided that the +* above copyright notice and the following two paragraphs appear in +* all copies of this software. +* +* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +* +* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +* +* Google Author(s): Behdad Esfahbod +*/ #ifndef HB_BUFFER_DESERIALIZE_TEXT_HH #define HB_BUFFER_DESERIALIZE_TEXT_HH @@ -32,540 +31,734 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-text.hh" +#line 35 "hb-buffer-deserialize-text.hh" static const unsigned char _deserialize_text_trans_keys[] = { - 0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, - 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, - 9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 0 + 1u, 0u, 0u, 13u, 12u, 12u, 2u, 2u, + 5u, 11u, 0u, 12u, 5u, 6u, 4u, 6u, + 5u, 6u, 5u, 6u, 4u, 6u, 5u, 6u, + 3u, 3u, 4u, 6u, 5u, 6u, 3u, 6u, + 2u, 16u, 4u, 6u, 5u, 6u, 0u, 16u, + 0u, 16u, 1u, 0u, 0u, 12u, 0u, 16u, + 0u, 16u, 0u, 16u, 0u, 16u, 0u, 16u, + 0u, 16u, 0u, 16u, 0u, 16u, 0u, 16u, + 0u, 16u, 0u, 16u, 0u, 16u, 0u, 16u, + 0u, 16u, 0u }; -static const char _deserialize_text_key_spans[] = { - 0, 114, 13, 10, 13, 10, 10, 13, - 10, 1, 13, 10, 14, 116, 116, 0, - 114, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116 +static const signed char _deserialize_text_char_class[] = { + 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 3, 4, 1, 1, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 1, 1, 7, 8, 9, 1, 10, + 11, 11, 11, 11, 11, 11, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 12, 1, 1, 1, + 1, 1, 13, 14, 15, 1, 1, 1, + 11, 11, 11, 11, 11, 11, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 16, 0 }; static const short _deserialize_text_index_offsets[] = { - 0, 0, 115, 129, 140, 154, 165, 176, - 190, 201, 203, 217, 228, 243, 360, 477, - 478, 593, 710, 827, 944, 1061, 1178, 1295, - 1412, 1529, 1646 + 0, 0, 14, 15, 16, 23, 36, 38, + 41, 43, 45, 48, 50, 51, 54, 56, + 60, 75, 78, 80, 97, 114, 114, 127, + 144, 161, 178, 195, 212, 229, 246, 263, + 280, 297, 314, 331, 348, 0 +}; + +static const signed char _deserialize_text_indicies[] = { + 1, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 3, 4, 6, + 7, 7, 0, 0, 0, 0, 7, 8, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 10, 11, 13, 14, + 15, 17, 18, 20, 21, 23, 24, 25, + 27, 28, 29, 31, 32, 33, 35, 36, + 29, 0, 28, 28, 38, 38, 0, 0, + 0, 0, 38, 0, 38, 0, 0, 0, + 38, 38, 38, 40, 41, 42, 44, 45, + 47, 0, 0, 0, 0, 48, 48, 0, + 49, 50, 0, 48, 0, 0, 0, 0, + 51, 52, 0, 0, 0, 0, 0, 0, + 0, 0, 53, 0, 0, 0, 0, 0, + 0, 54, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 56, + 0, 0, 0, 0, 0, 0, 0, 0, + 57, 0, 0, 0, 0, 0, 0, 58, + 56, 0, 0, 0, 0, 60, 60, 0, + 0, 57, 0, 0, 0, 0, 0, 0, + 58, 63, 62, 64, 0, 62, 62, 62, + 62, 65, 62, 66, 62, 62, 62, 67, + 68, 69, 71, 38, 72, 0, 38, 38, + 38, 38, 73, 38, 74, 38, 38, 38, + 37, 75, 76, 78, 0, 0, 79, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 81, 82, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 53, 83, 84, 62, 64, + 0, 62, 62, 62, 62, 65, 62, 66, + 62, 62, 62, 67, 68, 69, 86, 0, + 87, 0, 0, 0, 0, 0, 0, 0, + 88, 0, 0, 0, 0, 57, 89, 91, + 0, 92, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 93, 94, + 91, 0, 92, 0, 0, 36, 36, 0, + 0, 0, 0, 0, 0, 0, 0, 93, + 94, 86, 0, 87, 0, 0, 97, 97, + 0, 0, 0, 88, 0, 0, 0, 0, + 57, 89, 99, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 100, 101, 99, 0, 0, 0, 0, + 45, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 100, 101, 78, 0, 0, 79, + 0, 18, 18, 0, 0, 0, 0, 0, + 0, 0, 0, 80, 81, 0 }; -static const char _deserialize_text_indicies[] = { - 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 1, 1, 1, 1, 1, 1, - 1, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 1, 1, 1, 1, 1, - 1, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 1, 5, 1, 1, 6, - 7, 7, 7, 7, 7, 7, 7, 7, - 7, 1, 8, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 1, 10, 1, 1, - 11, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 1, 13, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 1, 15, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 1, 17, 1, 1, 18, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 1, 20, - 21, 21, 21, 21, 21, 21, 21, 21, - 21, 1, 22, 1, 23, 1, 1, 24, - 25, 25, 25, 25, 25, 25, 25, 25, - 25, 1, 26, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 1, 22, 1, 1, - 1, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 1, 28, 28, 28, 28, - 28, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 28, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 29, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 30, 1, 1, 31, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 32, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 33, - 1, 34, 34, 34, 34, 34, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 34, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 35, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 36, 1, 1, 0, - 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 1, 1, 1, 1, 1, 1, 1, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 1, 1, 1, 1, 1, 1, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, - 4, 1, 28, 28, 28, 28, 28, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 28, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 29, 1, 1, 1, - 1, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 1, 1, 1, 30, 1, - 1, 31, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 32, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 33, 1, 38, - 38, 38, 38, 38, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 38, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 39, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 40, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 41, 1, 42, 42, 42, 42, - 42, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 42, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 43, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 44, - 1, 42, 42, 42, 42, 42, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 42, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 43, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 44, 1, 38, 38, - 38, 38, 38, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 38, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 39, 1, 1, 1, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 40, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 41, 1, 45, 45, 45, 45, 45, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 45, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 46, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 47, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 48, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 49, 1, - 50, 50, 50, 50, 50, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 50, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 51, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 52, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 53, 1, 50, 50, 50, - 50, 50, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 50, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 51, - 1, 1, 1, 1, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 52, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 53, 1, 45, 45, 45, 45, 45, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 45, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 46, 1, 1, 1, - 1, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 1, 1, 1, 1, 1, - 1, 47, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 48, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 49, 1, 28, - 28, 28, 28, 28, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 28, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 29, 1, 55, 55, 1, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 1, 1, 1, 30, 1, 1, 31, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 1, 1, 32, 1, 55, 1, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, - 55, 1, 33, 1, 0 +static const signed char _deserialize_text_index_defaults[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 62, 38, 0, 0, 62, 0, 0, + 0, 0, 0, 0, 0, 0 }; -static const char _deserialize_text_trans_targs[] = { - 1, 0, 13, 17, 26, 3, 18, 21, - 18, 21, 5, 19, 20, 19, 20, 22, - 25, 8, 9, 12, 9, 12, 10, 11, - 23, 24, 23, 24, 14, 2, 6, 7, - 15, 16, 14, 15, 16, 17, 14, 4, - 15, 16, 14, 15, 16, 14, 2, 7, - 15, 16, 14, 2, 15, 16, 25, 26 +static const signed char _deserialize_text_cond_targs[] = { + 0, 1, 2, 25, 3, 3, 4, 19, + 5, 6, 23, 24, 7, 8, 27, 36, + 8, 27, 36, 9, 30, 33, 10, 11, + 12, 15, 11, 12, 15, 13, 13, 14, + 31, 32, 14, 31, 32, 16, 26, 17, + 18, 34, 35, 18, 34, 35, 19, 20, + 19, 6, 21, 22, 20, 21, 22, 23, + 20, 21, 22, 24, 24, 25, 26, 26, + 7, 9, 10, 16, 21, 29, 26, 26, + 7, 9, 10, 21, 29, 27, 28, 17, + 21, 29, 28, 29, 29, 30, 28, 7, + 10, 29, 31, 28, 7, 21, 29, 32, + 33, 33, 34, 28, 21, 29, 35, 36, + 0 }; -static const char _deserialize_text_trans_actions[] = { - 0, 0, 1, 1, 1, 2, 2, 2, - 0, 0, 2, 2, 2, 0, 0, 2, - 2, 2, 2, 2, 0, 0, 3, 2, - 2, 2, 0, 0, 4, 5, 5, 5, - 4, 4, 0, 0, 0, 0, 6, 7, - 6, 6, 8, 8, 8, 9, 10, 10, - 9, 9, 11, 12, 11, 11, 0, 0 +static const signed char _deserialize_text_cond_actions[] = { + 0, 0, 0, 0, 1, 0, 0, 2, + 0, 0, 2, 2, 0, 3, 4, 4, + 0, 5, 5, 0, 4, 4, 0, 3, + 3, 3, 0, 0, 0, 6, 0, 3, + 4, 4, 0, 5, 5, 0, 5, 0, + 3, 4, 4, 0, 5, 5, 7, 7, + 8, 9, 7, 7, 0, 0, 0, 10, + 10, 10, 10, 10, 8, 11, 12, 13, + 14, 14, 14, 15, 11, 11, 16, 17, + 18, 18, 18, 16, 16, 19, 19, 20, + 19, 19, 0, 0, 13, 10, 10, 21, + 21, 10, 22, 22, 23, 22, 22, 22, + 10, 5, 24, 24, 24, 24, 24, 19, + 0 }; -static const char _deserialize_text_eof_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 0, 0, - 0, 4, 6, 8, 8, 6, 9, 11, - 11, 9, 4 +static const signed char _deserialize_text_eof_trans[] = { + 1, 2, 3, 6, 7, 9, 10, 13, + 17, 20, 23, 27, 28, 31, 35, 29, + 38, 40, 44, 47, 53, 54, 55, 56, + 60, 62, 71, 78, 83, 70, 86, 91, + 96, 97, 99, 103, 104, 0 }; static const int deserialize_text_start = 1; -static const int deserialize_text_first_final = 13; +static const int deserialize_text_first_final = 19; static const int deserialize_text_error = 0; static const int deserialize_text_en_main = 1; -#line 91 "hb-buffer-deserialize-text.rl" +#line 114 "hb-buffer-deserialize-text.rl" static hb_bool_t -_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer, - const char *buf, - unsigned int buf_len, - const char **end_ptr, - hb_font_t *font) +_hb_buffer_deserialize_text (hb_buffer_t *buffer, +const char *buf, +unsigned int buf_len, +const char **end_ptr, +hb_font_t *font) { - const char *p = buf, *pe = buf + buf_len; - - /* Ensure we have positions. */ - (void) hb_buffer_get_glyph_positions (buffer, nullptr); - - while (p < pe && ISSPACE (*p)) - p++; - if (p < pe && *p == (buffer->len ? '|' : '[')) - { - *end_ptr = ++p; - } - - const char *eof = pe, *tok = nullptr; - int cs; - hb_glyph_info_t info = {0}; - hb_glyph_position_t pos = {0}; - -#line 343 "hb-buffer-deserialize-text.hh" + const char *p = buf, *pe = buf + buf_len; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, nullptr); + + while (p < pe && ISSPACE (*p)) + p++; + + const char *eof = pe, *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + hb_glyph_position_t pos = {0}; + +#line 204 "hb-buffer-deserialize-text.hh" { - cs = deserialize_text_start; + cs = (int)deserialize_text_start; } - -#line 348 "hb-buffer-deserialize-text.hh" + +#line 209 "hb-buffer-deserialize-text.hh" { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _deserialize_text_trans_keys + (cs<<1); - _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs]; - - _slen = _deserialize_text_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && - (*p) <= _keys[1] ? - (*p) - _keys[0] : _slen ]; - - cs = _deserialize_text_trans_targs[_trans]; - - if ( _deserialize_text_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _deserialize_text_trans_actions[_trans] ) { - case 2: + unsigned int _trans = 0; + const unsigned char * _keys; + const signed char * _inds; + int _ic; + _resume: {} + if ( p == pe && p != eof ) + goto _out; + if ( p == eof ) { + if ( _deserialize_text_eof_trans[cs] > 0 ) { + _trans = (unsigned int)_deserialize_text_eof_trans[cs] - 1; + } + } + else { + _keys = ( _deserialize_text_trans_keys + ((cs<<1))); + _inds = ( _deserialize_text_indicies + (_deserialize_text_index_offsets[cs])); + + if ( ( (*( p))) <= 124 && ( (*( p))) >= 9 ) { + _ic = (int)_deserialize_text_char_class[(int)( (*( p))) - 9]; + if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) ) + _trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) )); + else + _trans = (unsigned int)_deserialize_text_index_defaults[cs]; + } + else { + _trans = (unsigned int)_deserialize_text_index_defaults[cs]; + } + + } + cs = (int)_deserialize_text_cond_targs[_trans]; + + if ( _deserialize_text_cond_actions[_trans] != 0 ) { + + switch ( _deserialize_text_cond_actions[_trans] ) { + case 1: { + { +#line 38 "hb-buffer-deserialize-text.rl" + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 252 "hb-buffer-deserialize-text.hh" + + + break; + } + case 3: { + { #line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 5: + + tok = p; + } + +#line 264 "hb-buffer-deserialize-text.hh" + + + break; + } + case 5: { + { #line 55 "hb-buffer-deserialize-text.rl" - { - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 10: -#line 62 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } - break; - case 3: -#line 63 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } - break; - case 12: -#line 64 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } - break; - case 7: -#line 65 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } - break; - case 1: + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 274 "hb-buffer-deserialize-text.hh" + + + break; + } + case 8: { + { +#line 56 "hb-buffer-deserialize-text.rl" + if (unlikely (!buffer->ensure_unicode ())) return false; } + +#line 284 "hb-buffer-deserialize-text.hh" + + + break; + } + case 18: { + { +#line 58 "hb-buffer-deserialize-text.rl" + + /* TODO Unescape delimeters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 300 "hb-buffer-deserialize-text.hh" + + + break; + } + case 9: { + { +#line 66 "hb-buffer-deserialize-text.rl" + if (!parse_hex (tok, p, &info.codepoint )) return false; } + +#line 310 "hb-buffer-deserialize-text.hh" + + + break; + } + case 21: { + { +#line 68 "hb-buffer-deserialize-text.rl" + if (!parse_uint (tok, p, &info.cluster )) return false; } + +#line 320 "hb-buffer-deserialize-text.hh" + + + break; + } + case 6: { + { +#line 69 "hb-buffer-deserialize-text.rl" + if (!parse_int (tok, p, &pos.x_offset )) return false; } + +#line 330 "hb-buffer-deserialize-text.hh" + + + break; + } + case 23: { + { +#line 70 "hb-buffer-deserialize-text.rl" + if (!parse_int (tok, p, &pos.y_offset )) return false; } + +#line 340 "hb-buffer-deserialize-text.hh" + + + break; + } + case 20: { + { +#line 71 "hb-buffer-deserialize-text.rl" + if (!parse_int (tok, p, &pos.x_advance)) return false; } + +#line 350 "hb-buffer-deserialize-text.hh" + + + break; + } + case 15: { + { #line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 363 "hb-buffer-deserialize-text.hh" + + { #line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 4: + + tok = p; + } + +#line 371 "hb-buffer-deserialize-text.hh" + + + break; + } + case 4: { + { +#line 51 "hb-buffer-deserialize-text.rl" + + tok = p; + } + +#line 383 "hb-buffer-deserialize-text.hh" + + { #line 55 "hb-buffer-deserialize-text.rl" - { - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 9: -#line 62 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 389 "hb-buffer-deserialize-text.hh" + + + break; + } + case 2: { + { +#line 51 "hb-buffer-deserialize-text.rl" + + tok = p; + } + +#line 401 "hb-buffer-deserialize-text.hh" + + { +#line 56 "hb-buffer-deserialize-text.rl" + if (unlikely (!buffer->ensure_unicode ())) return false; } + +#line 407 "hb-buffer-deserialize-text.hh" + + + break; + } + case 16: { + { +#line 58 "hb-buffer-deserialize-text.rl" + + /* TODO Unescape delimeters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 423 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 64 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 435 "hb-buffer-deserialize-text.hh" + + + break; + } + case 7: { + { +#line 66 "hb-buffer-deserialize-text.rl" + if (!parse_hex (tok, p, &info.codepoint )) return false; } + +#line 445 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 6: -#line 65 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 457 "hb-buffer-deserialize-text.hh" + + + break; + } + case 10: { + { +#line 68 "hb-buffer-deserialize-text.rl" + if (!parse_uint (tok, p, &info.cluster )) return false; } + +#line 467 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 8: -#line 66 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 479 "hb-buffer-deserialize-text.hh" + + + break; + } + case 22: { + { +#line 70 "hb-buffer-deserialize-text.rl" + if (!parse_int (tok, p, &pos.y_offset )) return false; } + +#line 489 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 480 "hb-buffer-deserialize-text.hh" - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - switch ( _deserialize_text_eof_actions[cs] ) { - case 4: -#line 55 "hb-buffer-deserialize-text.rl" - { - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 501 "hb-buffer-deserialize-text.hh" + + + break; + } + case 19: { + { +#line 71 "hb-buffer-deserialize-text.rl" + if (!parse_int (tok, p, &pos.x_advance)) return false; } + +#line 511 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 9: -#line 62 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 523 "hb-buffer-deserialize-text.hh" + + + break; + } + case 24: { + { +#line 72 "hb-buffer-deserialize-text.rl" + if (!parse_int (tok, p, &pos.y_advance)) return false; } + +#line 533 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 64 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 545 "hb-buffer-deserialize-text.hh" + + + break; + } + case 12: { + { +#line 38 "hb-buffer-deserialize-text.rl" + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 558 "hb-buffer-deserialize-text.hh" + + { +#line 51 "hb-buffer-deserialize-text.rl" + + tok = p; + } + +#line 566 "hb-buffer-deserialize-text.hh" + + { +#line 55 "hb-buffer-deserialize-text.rl" + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 572 "hb-buffer-deserialize-text.hh" + + + break; + } + case 14: { + { +#line 38 "hb-buffer-deserialize-text.rl" + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 585 "hb-buffer-deserialize-text.hh" + + { +#line 51 "hb-buffer-deserialize-text.rl" + + tok = p; + } + +#line 593 "hb-buffer-deserialize-text.hh" + + { +#line 58 "hb-buffer-deserialize-text.rl" + + /* TODO Unescape delimeters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 605 "hb-buffer-deserialize-text.hh" + + + break; + } + case 17: { + { +#line 58 "hb-buffer-deserialize-text.rl" + + /* TODO Unescape delimeters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 621 "hb-buffer-deserialize-text.hh" + + { +#line 55 "hb-buffer-deserialize-text.rl" + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 627 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 6: -#line 65 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 639 "hb-buffer-deserialize-text.hh" + + + break; + } + case 11: { + { +#line 38 "hb-buffer-deserialize-text.rl" + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 652 "hb-buffer-deserialize-text.hh" + + { +#line 51 "hb-buffer-deserialize-text.rl" + + tok = p; + } + +#line 660 "hb-buffer-deserialize-text.hh" + + { +#line 58 "hb-buffer-deserialize-text.rl" + + /* TODO Unescape delimeters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 672 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 8: -#line 66 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 684 "hb-buffer-deserialize-text.hh" + + + break; + } + case 13: { + { +#line 38 "hb-buffer-deserialize-text.rl" + + memset (&info, 0, sizeof (info)); + memset (&pos , 0, sizeof (pos )); + } + +#line 697 "hb-buffer-deserialize-text.hh" + + { +#line 51 "hb-buffer-deserialize-text.rl" + + tok = p; + } + +#line 705 "hb-buffer-deserialize-text.hh" + + { +#line 58 "hb-buffer-deserialize-text.rl" + + /* TODO Unescape delimeters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; + } + +#line 717 "hb-buffer-deserialize-text.hh" + + { +#line 55 "hb-buffer-deserialize-text.rl" + if (unlikely (!buffer->ensure_glyphs ())) return false; } + +#line 723 "hb-buffer-deserialize-text.hh" + + { #line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 557 "hb-buffer-deserialize-text.hh" - } - } - - _out: {} + + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; + } + +#line 735 "hb-buffer-deserialize-text.hh" + + + break; + } + } + + } + + if ( p == eof ) { + if ( cs >= 19 ) + goto _out; + } + else { + if ( cs != 0 ) { + p += 1; + goto _resume; + } + } + _out: {} } - -#line 119 "hb-buffer-deserialize-text.rl" - - - *end_ptr = p; - - return p == pe && *(p-1) != ']'; + +#line 138 "hb-buffer-deserialize-text.rl" + + + *end_ptr = p; + + return p == pe && *(p-1) != ']'; } #endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/src/hb-buffer-deserialize-text.rl b/src/hb-buffer-deserialize-text.rl index 6268a6c5039d85b9061e6a0f33486cc8c9f0a309..a2170288ecb256502253f7439f758210b1d0a10b 100644 --- a/src/hb-buffer-deserialize-text.rl +++ b/src/hb-buffer-deserialize-text.rl @@ -52,30 +52,37 @@ action tok { tok = p; } +action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; } +action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false; } + action parse_glyph { + /* TODO Unescape delimeters. */ if (!hb_font_glyph_from_string (font, tok, p - tok, &info.codepoint)) return false; } +action parse_hexdigits {if (!parse_hex (tok, p, &info.codepoint )) return false; } + action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; } action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; } action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; } action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; } -unum = '0' | [1-9] digit*; +unum = '0' | [1-9] digit*; num = '-'? unum; glyph_id = unum; -glyph_name = alpha (alnum|'_'|'.'|'-')*; +glyph_name = ([^\\\]=@+,|] | '\\' [\\\]=@+,|]) *; glyph = (glyph_id | glyph_name) >tok %parse_glyph; cluster = '=' (unum >tok %parse_cluster); offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset ); advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?; -item = + +glyph_item = ( glyph cluster? @@ -83,15 +90,31 @@ item = advances? ) >clear_item + @ensure_glyphs + %add_item + ; + +unicode = 'U' '+' xdigit+ >tok %parse_hexdigits; + +unicode_item = + ( + unicode + cluster? + ) + >clear_item + @ensure_unicode %add_item ; -main := space* item (space* '|' space* item)* space* ('|'|']')?; +glyphs = glyph_item (space* '|' space* glyph_item)* space* ('|'|']')?; +unicodes = unicode_item (space* '|' space* unicode_item)* space* ('|'|'>')?; + +main := space* ( ('[' glyphs) | ('<' unicodes) ); }%% static hb_bool_t -_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer, +_hb_buffer_deserialize_text (hb_buffer_t *buffer, const char *buf, unsigned int buf_len, const char **end_ptr, @@ -104,10 +127,6 @@ _hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer, while (p < pe && ISSPACE (*p)) p++; - if (p < pe && *p == (buffer->len ? '|' : '[')) - { - *end_ptr = ++p; - } const char *eof = pe, *tok = nullptr; int cs; diff --git a/src/hb-buffer-serialize.cc b/src/hb-buffer-serialize.cc index 77d997c90faf55b69e0150554495277207f56a74..6539b89640a142016904681849214480b950e97b 100644 --- a/src/hb-buffer-serialize.cc +++ b/src/hb-buffer-serialize.cc @@ -91,26 +91,26 @@ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) { switch ((unsigned) format) { - case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; - case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; + case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; default: - case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr; + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr; } } static unsigned int _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_flags_t flags) + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) { hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? - nullptr : hb_buffer_get_glyph_positions (buffer, nullptr); + nullptr : hb_buffer_get_glyph_positions (buffer, nullptr); *buf_consumed = 0; hb_position_t x = 0, y = 0; @@ -125,6 +125,8 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, if (i) *p++ = ','; + else + *p++ = '['; *p++ = '{'; @@ -134,8 +136,9 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, char g[128]; hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g)); *p++ = '"'; - for (char *q = g; *q; q++) { - if (*q == '"') + for (char *q = g; *q; q++) + { + if (unlikely (*q == '"' || *q == '\\')) *p++ = '\\'; *p++ = *q; } @@ -151,16 +154,16 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", - x+pos[i].x_offset, y+pos[i].y_offset)); + x+pos[i].x_offset, y+pos[i].y_offset)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", - pos[i].x_advance, pos[i].y_advance)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", + pos[i].x_advance, pos[i].y_advance)); } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) { if (info[i].mask & HB_GLYPH_FLAG_DEFINED) - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED)); } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) @@ -168,12 +171,14 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, hb_glyph_extents_t extents; hb_font_get_glyph_extents(font, info[i].codepoint, &extents); p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", - extents.x_bearing, extents.y_bearing)); + extents.x_bearing, extents.y_bearing)); p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", - extents.width, extents.height)); + extents.width, extents.height)); } *p++ = '}'; + if (i == end-1) + *p++ = ']'; unsigned int l = p - b; if (buf_size > l) @@ -196,19 +201,72 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, return end - start; } +static unsigned int +_hb_buffer_serialize_unicode_json (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); + + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + if (i) + *p++ = ','; + else + *p++ = '['; + + *p++ = '{'; + + APPEND ("\"u\":"); + + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); + } + + *p++ = '}'; + + if (i == end-1) + *p++ = ']'; + + unsigned int l = p - b; + if (buf_size > l) + { + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + + } + + return end - start; +} + static unsigned int _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_flags_t flags) + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_flags_t flags) { hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ? - nullptr : hb_buffer_get_glyph_positions (buffer, nullptr); + nullptr : hb_buffer_get_glyph_positions (buffer, nullptr); *buf_consumed = 0; hb_position_t x = 0, y = 0; @@ -221,9 +279,12 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, if (i) *p++ = '|'; + else + *p++ = '['; if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES)) { + /* TODO Escape delimiters we use. */ hb_font_glyph_to_string (font, info[i].codepoint, p, 128); p += strlen (p); } @@ -237,21 +298,21 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { if (x+pos[i].x_offset || y+pos[i].y_offset) - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) { - *p++ = '+'; - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); - if (pos[i].y_advance) - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); + *p++ = '+'; + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); + if (pos[i].y_advance) + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); } } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) { if (info[i].mask & HB_GLYPH_FLAG_DEFINED) - p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED)); } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) @@ -261,6 +322,10 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); } + if (i == end-1) { + *p++ = ']'; + } + unsigned int l = p - b; if (buf_size > l) { @@ -282,6 +347,51 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, return end - start; } + +static unsigned int +_hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_flags_t flags) +{ + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); + *buf_consumed = 0; + for (unsigned int i = start; i < end; i++) + { + char b[1024]; + char *p = b; + + if (i) + *p++ = '|'; + else + *p++ = '<'; + + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "U+%04X", info[i].codepoint)); + + if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); + } + + if (i == end-1) + *p++ = '>'; + + unsigned int l = p - b; + if (buf_size > l) + { + memcpy (buf, b, l); + buf += l; + buf_size -= l; + *buf_consumed += l; + *buf = '\0'; + } else + return i - start; + } + return end - start; +} + /** * hb_buffer_serialize_glyphs: * @buffer: an #hb_buffer_t buffer. @@ -290,8 +400,8 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to * write serialized buffer into. * @buf_size: the size of @buf. - * @buf_consumed: (out) (allow-none): if not %NULL, will be set to the number of byes written into @buf. - * @font: (allow-none): the #hb_font_t used to shape this buffer, needed to + * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf. + * @font: (nullable): the #hb_font_t used to shape this buffer, needed to * read glyph names and extents. If %NULL, and empty font will be used. * @format: the #hb_buffer_serialize_format_t to use for formatting the output. * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties @@ -308,6 +418,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, * ``` * [uni0651=0@518,0+0|uni0628=0+1897] * ``` + * * - The serialized glyphs are delimited with `[` and `]`. * - Glyphs are separated with `|` * - Each glyph starts with glyph name, or glyph index if @@ -316,12 +427,28 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, * - If #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set, the #hb_glyph_position_t in the format: * - If both #hb_glyph_position_t.x_offset and #hb_glyph_position_t.y_offset are not 0, `@x_offset,y_offset`. Then, * - `+x_advance`, then `,y_advance` if #hb_glyph_position_t.y_advance is not 0. Then, - * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the - * #hb_glyph_extents_t in the format - * `<x_bearing,y_bearing,width,height>` + * - If #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set, the #hb_glyph_extents_t in the format `` * * ## json - * TODO. + * A machine-readable, structured format. + * The serialized glyphs will look something like: + * + * ``` + * [{"g":"uni0651","cl":0,"dx":518,"dy":0,"ax":0,"ay":0}, + * {"g":"uni0628","cl":0,"dx":0,"dy":0,"ax":1897,"ay":0}] + * ``` + * + * Each glyph is a JSON object, with the following properties: + * - `g`: the glyph name or glyph index if + * #HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES flag is set. + * - `cl`: #hb_glyph_info_t.cluster if + * #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set. + * - `dx`,`dy`,`ax`,`ay`: #hb_glyph_position_t.x_offset, #hb_glyph_position_t.y_offset, + * #hb_glyph_position_t.x_advance and #hb_glyph_position_t.y_advance + * respectively, if #HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS is not set. + * - `xb`,`yb`,`w`,`h`: #hb_glyph_extents_t.x_bearing, #hb_glyph_extents_t.y_bearing, + * #hb_glyph_extents_t.width and #hb_glyph_extents_t.height respectively if + * #HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS is set. * * Return value: * The number of serialized items. @@ -330,16 +457,17 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, **/ unsigned int hb_buffer_serialize_glyphs (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_format_t format, - hb_buffer_serialize_flags_t flags) + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) { - assert (start <= end && end <= buffer->len); + end = hb_clamp (end, start, buffer->len); + start = hb_min (start, end); unsigned int sconsumed; if (!buf_consumed) @@ -348,8 +476,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, if (buf_size) *buf = '\0'; - assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || - buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + buffer->assert_glyphs (); if (!buffer->have_positions) flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS; @@ -364,13 +491,106 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return _hb_buffer_serialize_glyphs_text (buffer, start, end, - buf, buf_size, buf_consumed, - font, flags); + buf, buf_size, buf_consumed, + font, flags); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_serialize_glyphs_json (buffer, start, end, - buf, buf_size, buf_consumed, - font, flags); + buf, buf_size, buf_consumed, + font, flags); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return 0; + + } +} + +/** + * hb_buffer_serialize_unicode: + * @buffer: an #hb_buffer_t buffer. + * @start: the first item in @buffer to serialize. + * @end: the last item in @buffer to serialize. + * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to + * write serialized buffer into. + * @buf_size: the size of @buf. + * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf. + * @format: the #hb_buffer_serialize_format_t to use for formatting the output. + * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties + * to serialize. + * + * Serializes @buffer into a textual representation of its content, + * when the buffer contains Unicode codepoints (i.e., before shaping). This is + * useful for showing the contents of the buffer, for example during debugging. + * There are currently two supported serialization formats: + * + * ## text + * A human-readable, plain text format. + * The serialized codepoints will look something like: + * + * ``` + *   + * ``` + * + * - Glyphs are separated with `|` + * - Unicode codepoints are expressed as zero-padded four (or more) + * digit hexadecimal numbers preceded by `U+` + * - If #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set, the cluster + * will be indicated with a `=` then #hb_glyph_info_t.cluster. + * + * ## json + * A machine-readable, structured format. + * The serialized codepoints will be a list of objects with the following + * properties: + * - `u`: the Unicode codepoint as a decimal integer + * - `cl`: #hb_glyph_info_t.cluster if + * #HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS is not set. + * + * For example: + * + * ``` + * [{u:1617,cl:0},{u:1576,cl:1}] + * ``` + * + * Return value: + * The number of serialized items. + * + * Since: 2.7.3 + **/ +unsigned int +hb_buffer_serialize_unicode (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) +{ + end = hb_clamp (end, start, buffer->len); + start = hb_min (start, end); + + unsigned int sconsumed; + if (!buf_consumed) + buf_consumed = &sconsumed; + *buf_consumed = 0; + if (buf_size) + *buf = '\0'; + + buffer->assert_unicode (); + + if (unlikely (start == end)) + return 0; + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_serialize_unicode_text (buffer, start, end, + buf, buf_size, buf_consumed, flags); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_serialize_unicode_json (buffer, start, end, + buf, buf_size, buf_consumed, flags); default: case HB_BUFFER_SERIALIZE_FORMAT_INVALID: @@ -379,43 +599,121 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, } } +static unsigned int +_hb_buffer_serialize_invalid (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) +{ + assert (!buffer->len); -static hb_bool_t + unsigned int sconsumed; + if (!buf_consumed) + buf_consumed = &sconsumed; + if (buf_size < 3) + return 0; + if (format == HB_BUFFER_SERIALIZE_FORMAT_JSON) { + *buf++ = '['; + *buf++ = ']'; + *buf = '\0'; + } else if (format == HB_BUFFER_SERIALIZE_FORMAT_TEXT) { + *buf++ = '!'; + *buf++ = '!'; + *buf = '\0'; + } + *buf_consumed = 2; + return 0; +} + +/** + * hb_buffer_serialize: + * @buffer: an #hb_buffer_t buffer. + * @start: the first item in @buffer to serialize. + * @end: the last item in @buffer to serialize. + * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to + * write serialized buffer into. + * @buf_size: the size of @buf. + * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of byes written into @buf. + * @font: (nullable): the #hb_font_t used to shape this buffer, needed to + * read glyph names and extents. If %NULL, and empty font will be used. + * @format: the #hb_buffer_serialize_format_t to use for formatting the output. + * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties + * to serialize. + * + * Serializes @buffer into a textual representation of its content, whether + * Unicode codepoints or glyph identifiers and positioning information. This is + * useful for showing the contents of the buffer, for example during debugging. + * See the documentation of hb_buffer_serialize_unicode() and + * hb_buffer_serialize_glyphs() for a description of the output format. + * + * Return value: + * The number of serialized items. + * + * Since: 2.7.3 + **/ +unsigned int +hb_buffer_serialize (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags) +{ + switch (buffer->content_type) + { + + case HB_BUFFER_CONTENT_TYPE_GLYPHS: + return hb_buffer_serialize_glyphs (buffer, start, end, buf, buf_size, + buf_consumed, font, format, flags); + + case HB_BUFFER_CONTENT_TYPE_UNICODE: + return hb_buffer_serialize_unicode (buffer, start, end, buf, buf_size, + buf_consumed, format, flags); + + case HB_BUFFER_CONTENT_TYPE_INVALID: + default: + return _hb_buffer_serialize_invalid (buffer, start, end, buf, buf_size, + buf_consumed, format, flags); + } +} + +static bool +parse_int (const char *pp, const char *end, int32_t *pv) +{ + int v; + const char *p = pp; + if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */))) + return false; + + *pv = v; + return true; +} + +static bool parse_uint (const char *pp, const char *end, uint32_t *pv) { - char buf[32]; - unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); - strncpy (buf, pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - uint32_t v; - - errno = 0; - v = strtol (p, &pend, 10); - if (errno || p == pend || pend - p != end - pp) + unsigned int v; + const char *p = pp; + if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */))) return false; *pv = v; return true; } -static hb_bool_t -parse_int (const char *pp, const char *end, int32_t *pv) +static bool +parse_hex (const char *pp, const char *end, uint32_t *pv) { - char buf[32]; - unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); - strncpy (buf, pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - int32_t v; - - errno = 0; - v = strtol (p, &pend, 10); - if (errno || p == pend || pend - p != end - pp) + unsigned int v; + const char *p = pp; + if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, 16))) return false; *pv = v; @@ -428,33 +726,41 @@ parse_int (const char *pp, const char *end, int32_t *pv) /** * hb_buffer_deserialize_glyphs: * @buffer: an #hb_buffer_t buffer. - * @buf: (array length=buf_len): - * @buf_len: - * @end_ptr: (out): - * @font: - * @format: + * @buf: (array length=buf_len): string to deserialize + * @buf_len: the size of @buf, or -1 if it is %NULL-terminated + * @end_ptr: (out) (optional): output pointer to the character after last + * consumed one. + * @font: (nullable): font for getting glyph IDs + * @format: the #hb_buffer_serialize_format_t of the input @buf * + * Deserializes glyphs @buffer from textual representation in the format + * produced by hb_buffer_serialize_glyphs(). * - * - * Return value: + * Return value: %true if @buf is not fully consumed, %false otherwise. * * Since: 0.9.7 **/ hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, - const char *buf, - int buf_len, /* -1 means nul-terminated */ - const char **end_ptr, /* May be NULL */ - hb_font_t *font, /* May be NULL */ - hb_buffer_serialize_format_t format) + const char *buf, + int buf_len, /* -1 means nul-terminated */ + const char **end_ptr, /* May be NULL */ + hb_font_t *font, /* May be NULL */ + hb_buffer_serialize_format_t format) { const char *end; if (!end_ptr) end_ptr = &end; *end_ptr = buf; - assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || - buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + buffer->assert_glyphs (); + + if (unlikely (hb_object_is_immutable (buffer))) + { + if (end_ptr) + *end_ptr = buf; + return false; + } if (buf_len == -1) buf_len = strlen (buf); @@ -473,14 +779,84 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_glyphs_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text (buffer, + buf, buf_len, end_ptr, + font); + + case HB_BUFFER_SERIALIZE_FORMAT_JSON: + return _hb_buffer_deserialize_json (buffer, + buf, buf_len, end_ptr, + font); + + default: + case HB_BUFFER_SERIALIZE_FORMAT_INVALID: + return false; + + } +} + + +/** + * hb_buffer_deserialize_unicode: + * @buffer: an #hb_buffer_t buffer. + * @buf: (array length=buf_len): string to deserialize + * @buf_len: the size of @buf, or -1 if it is %NULL-terminated + * @end_ptr: (out) (optional): output pointer to the character after last + * consumed one. + * @format: the #hb_buffer_serialize_format_t of the input @buf + * + * Deserializes Unicode @buffer from textual representation in the format + * produced by hb_buffer_serialize_unicode(). + * + * Return value: %true if @buf is not fully consumed, %false otherwise. + * + * Since: 2.7.3 + **/ +hb_bool_t +hb_buffer_deserialize_unicode (hb_buffer_t *buffer, + const char *buf, + int buf_len, /* -1 means nul-terminated */ + const char **end_ptr, /* May be NULL */ + hb_buffer_serialize_format_t format) +{ + const char *end; + if (!end_ptr) + end_ptr = &end; + *end_ptr = buf; + + buffer->assert_unicode (); + + if (unlikely (hb_object_is_immutable (buffer))) + { + if (end_ptr) + *end_ptr = buf; + return false; + } + + if (buf_len == -1) + buf_len = strlen (buf); + + if (!buf_len) + { + *end_ptr = buf; + return false; + } + + hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE); + + hb_font_t* font = hb_font_get_empty (); + + switch (format) + { + case HB_BUFFER_SERIALIZE_FORMAT_TEXT: + return _hb_buffer_deserialize_text (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: - return _hb_buffer_deserialize_glyphs_json (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_json (buffer, + buf, buf_len, end_ptr, + font); default: case HB_BUFFER_SERIALIZE_FORMAT_INVALID: diff --git a/src/hb-buffer.cc b/src/hb-buffer.cc index db1978e6df46e95ab5ed34838dbc0d35fdadc933..8cad6ab8e6519d4ac3351fdc696fc7dc623b5cc3 100644 --- a/src/hb-buffer.cc +++ b/src/hb-buffer.cc @@ -37,8 +37,9 @@ * @short_description: Input and output buffers * @include: hb.h * - * Buffers serve dual role in HarfBuzz; they hold the input characters that are - * passed to hb_shape(), and after shaping they hold the output glyphs. + * Buffers serve a dual role in HarfBuzz; before shaping, they hold + * the input characters that are passed to hb_shape(), and after + * shaping they hold the output glyphs. **/ @@ -50,7 +51,7 @@ * Checks the equality of two #hb_segment_properties_t's. * * Return value: - * %true if all properties of @a equal those of @b, false otherwise. + * %true if all properties of @a equal those of @b, %false otherwise. * * Since: 0.9.7 **/ @@ -217,9 +218,6 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size) void hb_buffer_t::reset () { - if (unlikely (hb_object_is_immutable (this))) - return; - hb_unicode_funcs_destroy (unicode); unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ()); flags = HB_BUFFER_FLAG_DEFAULT; @@ -232,9 +230,6 @@ hb_buffer_t::reset () void hb_buffer_t::clear () { - if (unlikely (hb_object_is_immutable (this))) - return; - hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; props = default_props; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; @@ -289,9 +284,6 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info) void hb_buffer_t::remove_output () { - if (unlikely (hb_object_is_immutable (this))) - return; - have_output = false; have_positions = false; @@ -302,9 +294,6 @@ hb_buffer_t::remove_output () void hb_buffer_t::clear_output () { - if (unlikely (hb_object_is_immutable (this))) - return; - have_output = true; have_positions = false; @@ -315,16 +304,13 @@ hb_buffer_t::clear_output () void hb_buffer_t::clear_positions () { - if (unlikely (hb_object_is_immutable (this))) - return; - have_output = false; have_positions = true; out_len = 0; out_info = info; - memset (pos, 0, sizeof (pos[0]) * len); + hb_memset (pos, 0, sizeof (pos[0]) * len); } void @@ -332,15 +318,19 @@ hb_buffer_t::swap_buffers () { if (unlikely (!successful)) return; + assert (idx <= len); + if (unlikely (!next_glyphs (len - idx))) return; + assert (have_output); have_output = false; if (out_info != info) { - hb_glyph_info_t *tmp_string; - tmp_string = info; + hb_glyph_info_t *tmp; + tmp = info; info = out_info; - out_info = tmp_string; + out_info = tmp; + pos = (hb_glyph_position_t *) out_info; } @@ -352,31 +342,6 @@ hb_buffer_t::swap_buffers () idx = 0; } - -void -hb_buffer_t::replace_glyphs (unsigned int num_in, - unsigned int num_out, - const uint32_t *glyph_data) -{ - if (unlikely (!make_room_for (num_in, num_out))) return; - - assert (idx + num_in <= len); - - merge_clusters (idx, idx + num_in); - - hb_glyph_info_t orig_info = info[idx]; - hb_glyph_info_t *pinfo = &out_info[out_len]; - for (unsigned int i = 0; i < num_out; i++) - { - *pinfo = orig_info; - pinfo->codepoint = glyph_data[i]; - pinfo++; - } - - idx += num_in; - out_len += num_out; -} - bool hb_buffer_t::move_to (unsigned int i) { @@ -438,13 +403,6 @@ hb_buffer_t::set_masks (hb_mask_t value, if (!mask) return; - if (cluster_start == 0 && cluster_end == (unsigned int)-1) { - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - info[i].mask = (info[i].mask & not_mask) | value; - return; - } - unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) @@ -455,27 +413,13 @@ void hb_buffer_t::reverse_range (unsigned int start, unsigned int end) { - unsigned int i, j; - if (end - start < 2) return; - for (i = start, j = end - 1; i < j; i++, j--) { - hb_glyph_info_t t; - - t = info[i]; - info[i] = info[j]; - info[j] = t; - } + hb_array_t (info, len).reverse (start, end); if (have_positions) { - for (i = start, j = end - 1; i < j; i++, j--) { - hb_glyph_position_t t; - - t = pos[i]; - pos[i] = pos[j]; - pos[j] = t; - } + hb_array_t (pos, len).reverse (start, end); } } @@ -612,7 +556,7 @@ done: void hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end) { - unsigned int cluster = (unsigned int) -1; + unsigned int cluster = UINT_MAX; cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster); _unsafe_to_break_set_mask (info, start, end, cluster); } @@ -628,7 +572,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en assert (start <= out_len); assert (idx <= end); - unsigned int cluster = (unsigned int) -1; + unsigned int cluster = UINT_MAX; cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster); cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster); _unsafe_to_break_set_mask (out_info, start, out_len, cluster); @@ -638,8 +582,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en void hb_buffer_t::guess_segment_properties () { - assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || - (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + assert_unicode (); /* If script is set to INVALID, guess from buffer contents */ if (props.script == HB_SCRIPT_INVALID) { @@ -648,8 +591,8 @@ hb_buffer_t::guess_segment_properties () if (likely (script != HB_SCRIPT_COMMON && script != HB_SCRIPT_INHERITED && script != HB_SCRIPT_UNKNOWN)) { - props.script = script; - break; + props.script = script; + break; } } } @@ -727,21 +670,21 @@ hb_buffer_create () /** * hb_buffer_get_empty: * + * Fetches an empty #hb_buffer_t. * - * - * Return value: (transfer full): + * Return value: (transfer full): The empty buffer * * Since: 0.9.2 **/ hb_buffer_t * hb_buffer_get_empty () { - return const_cast (&Null(hb_buffer_t)); + return const_cast (&Null (hb_buffer_t)); } /** * hb_buffer_reference: (skip) - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Increases the reference count on @buffer by one. This prevents @buffer from * being destroyed until a matching call to hb_buffer_destroy() is made. @@ -759,7 +702,7 @@ hb_buffer_reference (hb_buffer_t *buffer) /** * hb_buffer_destroy: (skip) - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Deallocate the @buffer. * Decreases the reference count on @buffer by one. If the result is zero, then @@ -776,23 +719,25 @@ hb_buffer_destroy (hb_buffer_t *buffer) free (buffer->info); free (buffer->pos); +#ifndef HB_NO_BUFFER_MESSAGE if (buffer->message_destroy) buffer->message_destroy (buffer->message_data); +#endif free (buffer); } /** * hb_buffer_set_user_data: (skip) - * @buffer: an #hb_buffer_t. - * @key: - * @data: - * @destroy: - * @replace: - * + * @buffer: An #hb_buffer_t + * @key: The user-data key + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * + * Attaches a user-data key/data pair to the specified buffer. * - * Return value: + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ @@ -808,12 +753,13 @@ hb_buffer_set_user_data (hb_buffer_t *buffer, /** * hb_buffer_get_user_data: (skip) - * @buffer: an #hb_buffer_t. - * @key: + * @buffer: An #hb_buffer_t + * @key: The user-data key to query * + * Fetches the user data associated with the specified key, + * attached to the specified buffer. * - * - * Return value: + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.2 **/ @@ -827,11 +773,11 @@ hb_buffer_get_user_data (hb_buffer_t *buffer, /** * hb_buffer_set_content_type: - * @buffer: an #hb_buffer_t. - * @content_type: the type of buffer contents to set + * @buffer: An #hb_buffer_t + * @content_type: The type of buffer contents to set * - * Sets the type of @buffer contents, buffers are either empty, contain - * characters (before shaping) or glyphs (the result of shaping). + * Sets the type of @buffer contents. Buffers are either empty, contain + * characters (before shaping), or contain glyphs (the result of shaping). * * Since: 0.9.5 **/ @@ -844,12 +790,13 @@ hb_buffer_set_content_type (hb_buffer_t *buffer, /** * hb_buffer_get_content_type: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * - * see hb_buffer_set_content_type(). + * Fetches the type of @buffer contents. Buffers are either empty, contain + * characters (before shaping), or contain glyphs (the result of shaping). * * Return value: - * The type of @buffer contents. + * The type of @buffer contents * * Since: 0.9.5 **/ @@ -862,10 +809,11 @@ hb_buffer_get_content_type (hb_buffer_t *buffer) /** * hb_buffer_set_unicode_funcs: - * @buffer: an #hb_buffer_t. - * @unicode_funcs: - * + * @buffer: An #hb_buffer_t + * @unicode_funcs: The Unicode-functions structure * + * Sets the Unicode-functions structure of a buffer to + * @unicode_funcs. * * Since: 0.9.2 **/ @@ -886,11 +834,11 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, /** * hb_buffer_get_unicode_funcs: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * + * Fetches the Unicode-functions structure of a buffer. * - * - * Return value: + * Return value: The Unicode-functions structure * * Since: 0.9.2 **/ @@ -902,7 +850,7 @@ hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) /** * hb_buffer_set_direction: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * @direction: the #hb_direction_t of the @buffer * * Set the text flow direction of the buffer. No shaping can happen without @@ -928,7 +876,7 @@ hb_buffer_set_direction (hb_buffer_t *buffer, /** * hb_buffer_get_direction: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * See hb_buffer_set_direction() * @@ -945,8 +893,8 @@ hb_buffer_get_direction (hb_buffer_t *buffer) /** * hb_buffer_set_script: - * @buffer: an #hb_buffer_t. - * @script: an #hb_script_t to set. + * @buffer: An #hb_buffer_t + * @script: An #hb_script_t to set. * * Sets the script of @buffer to @script. * @@ -956,7 +904,7 @@ hb_buffer_get_direction (hb_buffer_t *buffer) * * You can pass one of the predefined #hb_script_t values, or use * hb_script_from_string() or hb_script_from_iso15924_tag() to get the - * corresponding script from an ISO 15924 script tag. + * corresponding script from an ISO 15924 script tag. * * Since: 0.9.2 **/ @@ -972,12 +920,12 @@ hb_buffer_set_script (hb_buffer_t *buffer, /** * hb_buffer_get_script: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * - * See hb_buffer_set_script(). + * Fetches the script of @buffer. * * Return value: - * The #hb_script_t of the @buffer. + * The #hb_script_t of the @buffer * * Since: 0.9.2 **/ @@ -989,8 +937,8 @@ hb_buffer_get_script (hb_buffer_t *buffer) /** * hb_buffer_set_language: - * @buffer: an #hb_buffer_t. - * @language: an hb_language_t to set. + * @buffer: An #hb_buffer_t + * @language: An hb_language_t to set * * Sets the language of @buffer to @language. * @@ -999,7 +947,7 @@ hb_buffer_get_script (hb_buffer_t *buffer) * are orthogonal to the scripts, and though they are related, they are * different concepts and should not be confused with each other. * - * Use hb_language_from_string() to convert from BCP 47 language tags to + * Use hb_language_from_string() to convert from BCP 47 language tags to * #hb_language_t. * * Since: 0.9.2 @@ -1016,7 +964,7 @@ hb_buffer_set_language (hb_buffer_t *buffer, /** * hb_buffer_get_language: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * See hb_buffer_set_language(). * @@ -1033,8 +981,8 @@ hb_buffer_get_language (hb_buffer_t *buffer) /** * hb_buffer_set_segment_properties: - * @buffer: an #hb_buffer_t. - * @props: an #hb_segment_properties_t to use. + * @buffer: An #hb_buffer_t + * @props: An #hb_segment_properties_t to use * * Sets the segment properties of the buffer, a shortcut for calling * hb_buffer_set_direction(), hb_buffer_set_script() and @@ -1054,8 +1002,8 @@ hb_buffer_set_segment_properties (hb_buffer_t *buffer, /** * hb_buffer_get_segment_properties: - * @buffer: an #hb_buffer_t. - * @props: (out): the output #hb_segment_properties_t. + * @buffer: An #hb_buffer_t + * @props: (out): The output #hb_segment_properties_t * * Sets @props to the #hb_segment_properties_t of @buffer. * @@ -1071,8 +1019,8 @@ hb_buffer_get_segment_properties (hb_buffer_t *buffer, /** * hb_buffer_set_flags: - * @buffer: an #hb_buffer_t. - * @flags: the buffer flags to set. + * @buffer: An #hb_buffer_t + * @flags: The buffer flags to set * * Sets @buffer flags to @flags. See #hb_buffer_flags_t. * @@ -1090,12 +1038,12 @@ hb_buffer_set_flags (hb_buffer_t *buffer, /** * hb_buffer_get_flags: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * - * See hb_buffer_set_flags(). + * Fetches the #hb_buffer_flags_t of @buffer. * * Return value: - * The @buffer flags. + * The @buffer flags * * Since: 0.9.7 **/ @@ -1107,16 +1055,18 @@ hb_buffer_get_flags (hb_buffer_t *buffer) /** * hb_buffer_set_cluster_level: - * @buffer: an #hb_buffer_t. - * @cluster_level: - * + * @buffer: An #hb_buffer_t + * @cluster_level: The cluster level to set on the buffer * + * Sets the cluster level of a buffer. The #hb_buffer_cluster_level_t + * dictates one aspect of how HarfBuzz will treat non-base characters + * during shaping. * * Since: 0.9.42 **/ void -hb_buffer_set_cluster_level (hb_buffer_t *buffer, - hb_buffer_cluster_level_t cluster_level) +hb_buffer_set_cluster_level (hb_buffer_t *buffer, + hb_buffer_cluster_level_t cluster_level) { if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1126,11 +1076,13 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer, /** * hb_buffer_get_cluster_level: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * + * Fetches the cluster level of a buffer. The #hb_buffer_cluster_level_t + * dictates one aspect of how HarfBuzz will treat non-base characters + * during shaping. * - * - * Return value: + * Return value: The cluster level of @buffer * * Since: 0.9.42 **/ @@ -1143,13 +1095,13 @@ hb_buffer_get_cluster_level (hb_buffer_t *buffer) /** * hb_buffer_set_replacement_codepoint: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * @replacement: the replacement #hb_codepoint_t * * Sets the #hb_codepoint_t that replaces invalid entries for a given encoding * when adding text to @buffer. * - * Default is %HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT. + * Default is #HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT. * * Since: 0.9.31 **/ @@ -1165,12 +1117,13 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer, /** * hb_buffer_get_replacement_codepoint: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * - * See hb_buffer_set_replacement_codepoint(). + * Fetches the #hb_codepoint_t that replaces invalid entries for a given encoding + * when adding text to @buffer. * * Return value: - * The @buffer replacement #hb_codepoint_t. + * The @buffer replacement #hb_codepoint_t * * Since: 0.9.31 **/ @@ -1183,7 +1136,7 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer) /** * hb_buffer_set_invisible_glyph: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * @invisible: the invisible #hb_codepoint_t * * Sets the #hb_codepoint_t that replaces invisible characters in @@ -1205,12 +1158,12 @@ hb_buffer_set_invisible_glyph (hb_buffer_t *buffer, /** * hb_buffer_get_invisible_glyph: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * See hb_buffer_set_invisible_glyph(). * * Return value: - * The @buffer invisible #hb_codepoint_t. + * The @buffer invisible #hb_codepoint_t * * Since: 2.0.0 **/ @@ -1223,7 +1176,7 @@ hb_buffer_get_invisible_glyph (hb_buffer_t *buffer) /** * hb_buffer_reset: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Resets the buffer to its initial status, as if it was just newly created * with hb_buffer_create(). @@ -1233,12 +1186,15 @@ hb_buffer_get_invisible_glyph (hb_buffer_t *buffer) void hb_buffer_reset (hb_buffer_t *buffer) { + if (unlikely (hb_object_is_immutable (buffer))) + return; + buffer->reset (); } /** * hb_buffer_clear_contents: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Similar to hb_buffer_reset(), but does not clear the Unicode functions and * the replacement code point. @@ -1248,18 +1204,21 @@ hb_buffer_reset (hb_buffer_t *buffer) void hb_buffer_clear_contents (hb_buffer_t *buffer) { + if (unlikely (hb_object_is_immutable (buffer))) + return; + buffer->clear (); } /** * hb_buffer_pre_allocate: - * @buffer: an #hb_buffer_t. - * @size: number of items to pre allocate. + * @buffer: An #hb_buffer_t + * @size: Number of items to pre allocate. * * Pre allocates memory for @buffer to fit at least @size number of items. * * Return value: - * %true if @buffer memory allocation succeeded, %false otherwise. + * %true if @buffer memory allocation succeeded, %false otherwise * * Since: 0.9.2 **/ @@ -1271,7 +1230,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) /** * hb_buffer_allocation_successful: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Check if allocating memory for the buffer succeeded. * @@ -1288,9 +1247,9 @@ hb_buffer_allocation_successful (hb_buffer_t *buffer) /** * hb_buffer_add: - * @buffer: an #hb_buffer_t. - * @codepoint: a Unicode code point. - * @cluster: the cluster value of @codepoint. + * @buffer: An #hb_buffer_t + * @codepoint: A Unicode code point. + * @cluster: The cluster value of @codepoint. * * Appends a character with the Unicode value of @codepoint to @buffer, and * gives it the initial cluster value of @cluster. Clusters can be any thing @@ -1314,8 +1273,8 @@ hb_buffer_add (hb_buffer_t *buffer, /** * hb_buffer_set_length: - * @buffer: an #hb_buffer_t. - * @length: the new length of @buffer. + * @buffer: An #hb_buffer_t + * @length: The new length of @buffer * * Similar to hb_buffer_pre_allocate(), but clears any new items added at the * end. @@ -1332,7 +1291,7 @@ hb_buffer_set_length (hb_buffer_t *buffer, if (unlikely (hb_object_is_immutable (buffer))) return length == 0; - if (!buffer->ensure (length)) + if (unlikely (!buffer->ensure (length))) return false; /* Wipe the new space */ @@ -1356,7 +1315,7 @@ hb_buffer_set_length (hb_buffer_t *buffer, /** * hb_buffer_get_length: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Returns the number of items in the buffer. * @@ -1374,8 +1333,8 @@ hb_buffer_get_length (hb_buffer_t *buffer) /** * hb_buffer_get_glyph_infos: - * @buffer: an #hb_buffer_t. - * @length: (out): output array length. + * @buffer: An #hb_buffer_t + * @length: (out): The output-array length. * * Returns @buffer glyph information array. Returned pointer * is valid as long as @buffer contents are not modified. @@ -1388,7 +1347,7 @@ hb_buffer_get_length (hb_buffer_t *buffer) **/ hb_glyph_info_t * hb_buffer_get_glyph_infos (hb_buffer_t *buffer, - unsigned int *length) + unsigned int *length) { if (length) *length = buffer->len; @@ -1398,8 +1357,8 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer, /** * hb_buffer_get_glyph_positions: - * @buffer: an #hb_buffer_t. - * @length: (out): output length. + * @buffer: An #hb_buffer_t + * @length: (out): The output length * * Returns @buffer glyph position array. Returned pointer * is valid as long as @buffer contents are not modified. @@ -1412,7 +1371,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer, **/ hb_glyph_position_t * hb_buffer_get_glyph_positions (hb_buffer_t *buffer, - unsigned int *length) + unsigned int *length) { if (!buffer->have_positions) buffer->clear_positions (); @@ -1423,14 +1382,33 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer, return (hb_glyph_position_t *) buffer->pos; } +/** + * hb_buffer_has_positions: + * @buffer: an #hb_buffer_t. + * + * Returns whether @buffer has glyph position data. + * A buffer gains position data when hb_buffer_get_glyph_positions() is called on it, + * and cleared of position data when hb_buffer_clear_contents() is called. + * + * Return value: + * %true if the @buffer has position array, %false otherwise. + * + * Since: 2.7.3 + **/ +HB_EXTERN hb_bool_t +hb_buffer_has_positions (hb_buffer_t *buffer) +{ + return buffer->have_positions; +} + /** * hb_glyph_info_get_glyph_flags: - * @info: a #hb_glyph_info_t. + * @info: a #hb_glyph_info_t * * Returns glyph flags encoded within a #hb_glyph_info_t. * * Return value: - * The #hb_glyph_flags_t encoded within @info. + * The #hb_glyph_flags_t encoded within @info * * Since: 1.5.0 **/ @@ -1442,7 +1420,7 @@ hb_glyph_flags_t /** * hb_buffer_reverse: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Reverses buffer contents. * @@ -1456,11 +1434,11 @@ hb_buffer_reverse (hb_buffer_t *buffer) /** * hb_buffer_reverse_range: - * @buffer: an #hb_buffer_t. - * @start: start index. - * @end: end index. + * @buffer: An #hb_buffer_t + * @start: start index + * @end: end index * - * Reverses buffer contents between start to end. + * Reverses buffer contents between @start and @end. * * Since: 0.9.41 **/ @@ -1473,7 +1451,7 @@ hb_buffer_reverse_range (hb_buffer_t *buffer, /** * hb_buffer_reverse_clusters: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Reverses buffer clusters. That is, the buffer contents are * reversed, then each cluster (consecutive items having the @@ -1489,24 +1467,24 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer) /** * hb_buffer_guess_segment_properties: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Sets unset buffer segment properties based on buffer Unicode * contents. If buffer is not empty, it must have content type - * %HB_BUFFER_CONTENT_TYPE_UNICODE. + * #HB_BUFFER_CONTENT_TYPE_UNICODE. * - * If buffer script is not set (ie. is %HB_SCRIPT_INVALID), it + * If buffer script is not set (ie. is #HB_SCRIPT_INVALID), it * will be set to the Unicode script of the first character in - * the buffer that has a script other than %HB_SCRIPT_COMMON, - * %HB_SCRIPT_INHERITED, and %HB_SCRIPT_UNKNOWN. + * the buffer that has a script other than #HB_SCRIPT_COMMON, + * #HB_SCRIPT_INHERITED, and #HB_SCRIPT_UNKNOWN. * - * Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID), + * Next, if buffer direction is not set (ie. is #HB_DIRECTION_INVALID), * it will be set to the natural horizontal direction of the * buffer script as returned by hb_script_get_horizontal_direction(). - * If hb_script_get_horizontal_direction() returns %HB_DIRECTION_INVALID, - * then %HB_DIRECTION_LTR is used. + * If hb_script_get_horizontal_direction() returns #HB_DIRECTION_INVALID, + * then #HB_DIRECTION_LTR is used. * - * Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID), + * Finally, if buffer language is not set (ie. is #HB_LANGUAGE_INVALID), * it will be set to the process's default language as returned by * hb_language_get_default(). This may change in the future by * taking buffer script into consideration when choosing a language. @@ -1532,8 +1510,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer, typedef typename utf_t::codepoint_t T; const hb_codepoint_t replacement = buffer->replacement; - assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || - (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + buffer->assert_unicode (); if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1544,7 +1521,10 @@ hb_buffer_add_utf (hb_buffer_t *buffer, if (item_length == -1) item_length = text_length - item_offset; - buffer->ensure (buffer->len + item_length * sizeof (T) / 4); + if (unlikely (item_length < 0 || + item_length > INT_MAX / 8 || + !buffer->ensure (buffer->len + item_length * sizeof (T) / 4))) + return; /* If buffer is empty and pre-context provided, install it. * This check is written this way, to make sure people can @@ -1592,12 +1572,12 @@ hb_buffer_add_utf (hb_buffer_t *buffer, /** * hb_buffer_add_utf8: - * @buffer: an #hb_buffer_t. - * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8 + * @buffer: An #hb_buffer_t + * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8 * characters to append. - * @text_length: the length of the @text, or -1 if it is %NULL terminated. - * @item_offset: the offset of the first character to add to the @buffer. - * @item_length: the number of characters to add to the @buffer, or -1 for the + * @text_length: The length of the @text, or -1 if it is %NULL terminated. + * @item_offset: The offset of the first character to add to the @buffer. + * @item_length: The number of characters to add to the @buffer, or -1 for the * end of @text (assuming it is %NULL terminated). * * See hb_buffer_add_codepoints(). @@ -1619,12 +1599,12 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer, /** * hb_buffer_add_utf16: - * @buffer: an #hb_buffer_t. - * @text: (array length=text_length): an array of UTF-16 characters to append. - * @text_length: the length of the @text, or -1 if it is %NULL terminated. - * @item_offset: the offset of the first character to add to the @buffer. - * @item_length: the number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated). + * @buffer: An #hb_buffer_t + * @text: (array length=text_length): An array of UTF-16 characters to append + * @text_length: The length of the @text, or -1 if it is %NULL terminated + * @item_offset: The offset of the first character to add to the @buffer + * @item_length: The number of characters to add to the @buffer, or -1 for the + * end of @text (assuming it is %NULL terminated) * * See hb_buffer_add_codepoints(). * @@ -1645,12 +1625,12 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer, /** * hb_buffer_add_utf32: - * @buffer: an #hb_buffer_t. - * @text: (array length=text_length): an array of UTF-32 characters to append. - * @text_length: the length of the @text, or -1 if it is %NULL terminated. - * @item_offset: the offset of the first character to add to the @buffer. - * @item_length: the number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated). + * @buffer: An #hb_buffer_t + * @text: (array length=text_length): An array of UTF-32 characters to append + * @text_length: The length of the @text, or -1 if it is %NULL terminated + * @item_offset: The offset of the first character to add to the @buffer + * @item_length: The number of characters to add to the @buffer, or -1 for the + * end of @text (assuming it is %NULL terminated) * * See hb_buffer_add_codepoints(). * @@ -1671,13 +1651,13 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer, /** * hb_buffer_add_latin1: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8 - * characters to append. - * @text_length: the length of the @text, or -1 if it is %NULL terminated. - * @item_offset: the offset of the first character to add to the @buffer. + * characters to append + * @text_length: the length of the @text, or -1 if it is %NULL terminated + * @item_offset: the offset of the first character to add to the @buffer * @item_length: the number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated). + * end of @text (assuming it is %NULL terminated) * * Similar to hb_buffer_add_codepoints(), but allows only access to first 256 * Unicode code points that can fit in 8-bit strings. @@ -1733,10 +1713,10 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, /** * hb_buffer_append: - * @buffer: an #hb_buffer_t. - * @source: source #hb_buffer_t. + * @buffer: An #hb_buffer_t + * @source: source #hb_buffer_t * @start: start index into source buffer to copy. Use 0 to copy from start of buffer. - * @end: end index into source buffer to copy. Use (unsigned int) -1 to copy to end of buffer. + * @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer. * * Append (part of) contents of another buffer to this buffer. * @@ -1761,11 +1741,6 @@ hb_buffer_append (hb_buffer_t *buffer, if (start == end) return; - if (!buffer->len) - buffer->content_type = source->content_type; - if (!buffer->have_positions && source->have_positions) - buffer->clear_positions (); - if (buffer->len + (end - start) < buffer->len) /* Overflows. */ { buffer->successful = false; @@ -1777,6 +1752,11 @@ hb_buffer_append (hb_buffer_t *buffer, if (unlikely (!buffer->successful)) return; + if (!orig_len) + buffer->content_type = source->content_type; + if (!buffer->have_positions && source->have_positions) + buffer->clear_positions (); + memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); @@ -1840,7 +1820,7 @@ normalize_glyphs_cluster (hb_buffer_t *buffer, /** * hb_buffer_normalize_glyphs: - * @buffer: an #hb_buffer_t. + * @buffer: An #hb_buffer_t * * Reorders a glyph buffer to have canonical in-cluster glyph order / position. * The resulting clusters should behave identical to pre-reordering clusters. @@ -1853,23 +1833,13 @@ void hb_buffer_normalize_glyphs (hb_buffer_t *buffer) { assert (buffer->have_positions); - assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS || - (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); - bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); + buffer->assert_glyphs (); - unsigned int count = buffer->len; - if (unlikely (!count)) return; - hb_glyph_info_t *info = buffer->info; + bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); - unsigned int start = 0; - unsigned int end; - for (end = start + 1; end < count; end++) - if (info[start].cluster != info[end].cluster) { - normalize_glyphs_cluster (buffer, start, end, backward); - start = end; - } - normalize_glyphs_cluster (buffer, start, end, backward); + foreach_cluster (buffer, start, end) + normalize_glyphs_cluster (buffer, start, end, backward); } void @@ -1905,8 +1875,8 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1. * @position_fuzz: allowed absolute difference in position values. * - * If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT - * and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most + * If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT + * and #HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most * callers if just comparing two buffers is needed. * * Since: 1.5.0 @@ -1936,9 +1906,9 @@ hb_buffer_diff (hb_buffer_t *buffer, for (i = 0; i < count; i++) { if (contains && info[i].codepoint == dottedcircle_glyph) - result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT; + result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT; if (contains && info[i].codepoint == 0) - result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT; + result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT; } result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH; return hb_buffer_diff_flags_t (result); @@ -1973,12 +1943,12 @@ hb_buffer_diff (hb_buffer_t *buffer, for (unsigned int i = 0; i < count; i++) { if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz || - (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz || - (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz || - (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz) + (unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz || + (unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz || + (unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz) { - result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH; - break; + result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH; + break; } buf_pos++; ref_pos++; @@ -1996,12 +1966,12 @@ hb_buffer_diff (hb_buffer_t *buffer, #ifndef HB_NO_BUFFER_MESSAGE /** * hb_buffer_set_message_func: - * @buffer: an #hb_buffer_t. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @buffer: An #hb_buffer_t + * @func: (closure user_data) (destroy destroy) (scope notified): Callback function + * @user_data: (nullable): Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_buffer_message_func_t. * * Since: 1.1.3 **/ diff --git a/src/hb-buffer.h b/src/hb-buffer.h index ac1d4525a836e4c804b3a5bffc4577eacea47170..865ccb2273b220c62f6608003d59f654ab92b663 100644 --- a/src/hb-buffer.h +++ b/src/hb-buffer.h @@ -27,7 +27,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -59,8 +59,7 @@ HB_BEGIN_DECLS * The #hb_glyph_info_t is the structure that holds information about the * glyphs and their relation to input text. */ -typedef struct hb_glyph_info_t -{ +typedef struct hb_glyph_info_t { hb_codepoint_t codepoint; /*< private >*/ hb_mask_t mask; @@ -91,6 +90,8 @@ typedef struct hb_glyph_info_t * breaking point only. * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags. * + * Flags for #hb_glyph_info_t. + * * Since: 1.5.0 */ typedef enum { /*< flags >*/ @@ -151,6 +152,11 @@ typedef struct hb_segment_properties_t { void *reserved2; } hb_segment_properties_t; +/** + * HB_SEGMENT_PROPERTIES_DEFAULT: + * + * The default #hb_segment_properties_t of of freshly created #hb_buffer_t. + */ #define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \ HB_SCRIPT_INVALID, \ HB_LANGUAGE_INVALID, \ @@ -204,6 +210,8 @@ hb_buffer_get_user_data (hb_buffer_t *buffer, * @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer. * @HB_BUFFER_CONTENT_TYPE_UNICODE: The buffer contains input characters (before shaping). * @HB_BUFFER_CONTENT_TYPE_GLYPHS: The buffer contains output glyphs (after shaping). + * + * The type of #hb_buffer_t contents. */ typedef enum { HB_BUFFER_CONTENT_TYPE_INVALID = 0, @@ -289,6 +297,8 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer); * not be inserted in the rendering of incorrect * character sequences (such at <0905 093E>). Since: 2.4 * + * Flags for #hb_buffer_t. + * * Since: 0.9.20 */ typedef enum { /*< flags >*/ @@ -315,6 +325,23 @@ hb_buffer_get_flags (hb_buffer_t *buffer); * @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values. * @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level, * equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES. + * + * Data type for holding HarfBuzz's clustering behavior options. The cluster level + * dictates one aspect of how HarfBuzz will treat non-base characters + * during shaping. + * + * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES, non-base + * characters are merged into the cluster of the base character that precedes them. + * + * In @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS, non-base characters are initially + * assigned their own cluster values, which are not merged into preceding base + * clusters. This allows HarfBuzz to perform additional operations like reorder + * sequences of adjacent marks. + * + * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES is the default, because it maintains + * backward compatibility with older versions of HarfBuzz. New client programs that + * do not need to maintain such backward compatibility are recommended to use + * @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS instead of the default. * * Since: 0.9.42 */ @@ -365,7 +392,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer); HB_EXTERN hb_bool_t hb_buffer_pre_allocate (hb_buffer_t *buffer, - unsigned int size); + unsigned int size); HB_EXTERN hb_bool_t @@ -441,11 +468,14 @@ hb_buffer_get_length (hb_buffer_t *buffer); HB_EXTERN hb_glyph_info_t * hb_buffer_get_glyph_infos (hb_buffer_t *buffer, - unsigned int *length); + unsigned int *length); HB_EXTERN hb_glyph_position_t * hb_buffer_get_glyph_positions (hb_buffer_t *buffer, - unsigned int *length); + unsigned int *length); + +HB_EXTERN hb_bool_t +hb_buffer_has_positions (hb_buffer_t *buffer); HB_EXTERN void @@ -518,6 +548,27 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, hb_buffer_serialize_format_t format, hb_buffer_serialize_flags_t flags); +HB_EXTERN unsigned int +hb_buffer_serialize_unicode (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); + +HB_EXTERN unsigned int +hb_buffer_serialize (hb_buffer_t *buffer, + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); + HB_EXTERN hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, const char *buf, @@ -526,11 +577,48 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, hb_font_t *font, hb_buffer_serialize_format_t format); +HB_EXTERN hb_bool_t +hb_buffer_deserialize_unicode (hb_buffer_t *buffer, + const char *buf, + int buf_len, + const char **end_ptr, + hb_buffer_serialize_format_t format); + + /* * Compare buffers */ +/** + * hb_buffer_diff_flags_t: + * @HB_BUFFER_DIFF_FLAG_EQUAL: equal buffers. + * @HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH: buffers with different + * #hb_buffer_content_type_t. + * @HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH: buffers with differing length. + * @HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT: `.notdef` glyph is present in the + * reference buffer. + * @HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT: dotted circle glyph is present + * in the reference buffer. + * @HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH: difference in #hb_glyph_info_t.codepoint + * @HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH: difference in #hb_glyph_info_t.cluster + * @HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH: difference in #hb_glyph_flags_t. + * @HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH: difference in #hb_glyph_position_t. + * + * Flags from comparing two #hb_buffer_t's. + * + * Buffer with different #hb_buffer_content_type_t cannot be meaningfully + * compared in any further detail. + * + * For buffers with differing length, the per-glyph comparison is not + * attempted, though we do still scan reference buffer for dotted circle and + * `.notdef` glyphs. + * + * If the buffers have the same length, we compare them glyph-by-glyph and + * report which aspect(s) of the glyph info/position are different. + * + * Since: 1.5.0 + */ typedef enum { /*< flags >*/ HB_BUFFER_DIFF_FLAG_EQUAL = 0x0000, @@ -570,6 +658,23 @@ hb_buffer_diff (hb_buffer_t *buffer, * Debugging. */ +/** + * hb_buffer_message_func_t: + * @buffer: An #hb_buffer_t to work upon + * @font: The #hb_font_t the @buffer is shaped with + * @message: %NULL-terminated message passed to the function + * @user_data: User data pointer passed by the caller + * + * A callback method for #hb_buffer_t. The method gets called with the + * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a + * message describing what step of the shaping process will be performed. + * Returning %false from this method will skip this shaping step and move to + * the next one. + * + * Return value: %true to perform the shaping step, %false to skip it. + * + * Since: 1.1.3 + */ typedef hb_bool_t (*hb_buffer_message_func_t) (hb_buffer_t *buffer, hb_font_t *font, const char *message, diff --git a/src/hb-buffer.hh b/src/hb-buffer.hh index de0655de3e4c55850a775c2615b042d9ae4de715..8b432b5f96f86333a49f7e402963d57245a0261c 100644 --- a/src/hb-buffer.hh +++ b/src/hb-buffer.hh @@ -35,20 +35,20 @@ #ifndef HB_BUFFER_MAX_LEN_FACTOR -#define HB_BUFFER_MAX_LEN_FACTOR 32 +#define HB_BUFFER_MAX_LEN_FACTOR 64 #endif #ifndef HB_BUFFER_MAX_LEN_MIN -#define HB_BUFFER_MAX_LEN_MIN 8192 +#define HB_BUFFER_MAX_LEN_MIN 16384 #endif #ifndef HB_BUFFER_MAX_LEN_DEFAULT #define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ #endif #ifndef HB_BUFFER_MAX_OPS_FACTOR -#define HB_BUFFER_MAX_OPS_FACTOR 64 +#define HB_BUFFER_MAX_OPS_FACTOR 1024 #endif #ifndef HB_BUFFER_MAX_OPS_MIN -#define HB_BUFFER_MAX_OPS_MIN 1024 +#define HB_BUFFER_MAX_OPS_MIN 16384 #endif #ifndef HB_BUFFER_MAX_OPS_DEFAULT #define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ @@ -126,9 +126,9 @@ struct hb_buffer_t /* Debugging API */ #ifndef HB_NO_BUFFER_MESSAGE hb_buffer_message_func_t message_func; -#endif void *message_data; hb_destroy_func_t message_destroy; +#endif /* Internal debugging. */ /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ @@ -139,7 +139,7 @@ struct hb_buffer_t /* Methods */ - bool in_error () const { return !successful; } + HB_NODISCARD bool in_error () const { return !successful; } void allocate_var (unsigned int start, unsigned int count) { @@ -186,7 +186,7 @@ struct hb_buffer_t hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } - bool has_separate_output () const { return info != out_info; } + HB_NODISCARD bool has_separate_output () const { return info != out_info; } HB_INTERNAL void reset (); @@ -210,86 +210,89 @@ struct hb_buffer_t HB_INTERNAL void clear_output (); HB_INTERNAL void clear_positions (); - HB_INTERNAL void replace_glyphs (unsigned int num_in, - unsigned int num_out, - const hb_codepoint_t *glyph_data); - - void replace_glyph (hb_codepoint_t glyph_index) + template + HB_NODISCARD bool replace_glyphs (unsigned int num_in, + unsigned int num_out, + const T *glyph_data) { - if (unlikely (out_info != info || out_len != idx)) { - if (unlikely (!make_room_for (1, 1))) return; - out_info[out_len] = info[idx]; - } - out_info[out_len].codepoint = glyph_index; + if (unlikely (!make_room_for (num_in, num_out))) return false; - idx++; - out_len++; - } - /* Makes a copy of the glyph at idx to output and replace glyph_index */ - hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index) - { - if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t); + assert (idx + num_in <= len); - if (unlikely (idx == len && !out_len)) - return Crap(hb_glyph_info_t); + merge_clusters (idx, idx + num_in); - out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1]; - out_info[out_len].codepoint = glyph_index; + hb_glyph_info_t &orig_info = idx < len ? cur() : prev(); - out_len++; + hb_glyph_info_t *pinfo = &out_info[out_len]; + for (unsigned int i = 0; i < num_out; i++) + { + *pinfo = orig_info; + pinfo->codepoint = glyph_data[i]; + pinfo++; + } - return out_info[out_len - 1]; + idx += num_in; + out_len += num_out; + return true; } - void output_info (const hb_glyph_info_t &glyph_info) + + HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph_index) + { return replace_glyphs (1, 1, &glyph_index); } + + /* Makes a copy of the glyph at idx to output and replace glyph_index */ + HB_NODISCARD bool output_glyph (hb_codepoint_t glyph_index) + { return replace_glyphs (0, 1, &glyph_index); } + + HB_NODISCARD bool output_info (const hb_glyph_info_t &glyph_info) { - if (unlikely (!make_room_for (0, 1))) return; + if (unlikely (!make_room_for (0, 1))) return false; out_info[out_len] = glyph_info; out_len++; + return true; } /* Copies glyph at idx to output but doesn't advance idx */ - void copy_glyph () + HB_NODISCARD bool copy_glyph () { - if (unlikely (!make_room_for (0, 1))) return; - - out_info[out_len] = info[idx]; - - out_len++; + /* Extra copy because cur()'s return can be freed within + * output_info() call if buffer reallocates. */ + return output_info (hb_glyph_info_t (cur())); } + /* Copies glyph at idx to output and advance idx. * If there's no output, just advance idx. */ - void - next_glyph () + HB_NODISCARD bool next_glyph () { if (have_output) { if (out_info != info || out_len != idx) { - if (unlikely (!make_room_for (1, 1))) return; + if (unlikely (!make_room_for (1, 1))) return false; out_info[out_len] = info[idx]; } out_len++; } idx++; + return true; } /* Copies n glyphs at idx to output and advance idx. * If there's no output, just advance idx. */ - void - next_glyphs (unsigned int n) + HB_NODISCARD bool next_glyphs (unsigned int n) { if (have_output) { if (out_info != info || out_len != idx) { - if (unlikely (!make_room_for (n, n))) return; + if (unlikely (!make_room_for (n, n))) return false; memmove (out_info + out_len, info + idx, n * sizeof (out_info[0])); } out_len += n; } idx += n; + return true; } /* Advance idx without copying to output. */ void skip_glyph () { idx++; } @@ -318,7 +321,7 @@ struct hb_buffer_t HB_INTERNAL void delete_glyph (); void unsafe_to_break (unsigned int start, - unsigned int end) + unsigned int end) { if (end - start < 2) return; @@ -329,18 +332,51 @@ struct hb_buffer_t /* Internal methods */ - HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ + HB_NODISCARD HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */ - HB_INTERNAL bool enlarge (unsigned int size); + HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size); - bool ensure (unsigned int size) + HB_NODISCARD bool ensure (unsigned int size) { return likely (!size || size < allocated) ? true : enlarge (size); } - bool ensure_inplace (unsigned int size) + HB_NODISCARD bool ensure_inplace (unsigned int size) { return likely (!size || size < allocated); } - HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out); - HB_INTERNAL bool shift_forward (unsigned int count); + void assert_glyphs () + { + assert ((content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) || + (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID))); + } + void assert_unicode () + { + assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) || + (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID))); + } + HB_NODISCARD bool ensure_glyphs () + { + if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_GLYPHS)) + { + if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID) + return false; + assert (len == 0); + content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; + } + return true; + } + HB_NODISCARD bool ensure_unicode () + { + if (unlikely (content_type != HB_BUFFER_CONTENT_TYPE_UNICODE)) + { + if (content_type != HB_BUFFER_CONTENT_TYPE_INVALID) + return false; + assert (len == 0); + content_type = HB_BUFFER_CONTENT_TYPE_UNICODE; + } + return true; + } + + HB_NODISCARD HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out); + HB_NODISCARD HB_INTERNAL bool shift_forward (unsigned int count); typedef long scratch_buffer_t; HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size); @@ -386,7 +422,7 @@ struct hb_buffer_t inf.cluster = cluster; } - int + unsigned int _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos, unsigned int start, unsigned int end, unsigned int cluster) const @@ -408,8 +444,7 @@ struct hb_buffer_t } } - void unsafe_to_break_all () - { unsafe_to_break_impl (0, len); } + void unsafe_to_break_all () { unsafe_to_break_impl (0, len); } void safe_to_break_all () { for (unsigned int i = 0; i < len; i++) diff --git a/src/hb-cff-interp-common.hh b/src/hb-cff-interp-common.hh index fdc5c683ab4ce41a485e976937177ecf52230b9e..c251e2d0ed1f5bf152be89acf59f15dcf74ed9ac 100644 --- a/src/hb-cff-interp-common.hh +++ b/src/hb-cff-interp-common.hh @@ -220,18 +220,15 @@ struct number_t void init () { set_real (0.0); } void fini () {} - void set_int (int v) { value = (double) v; } - int to_int () const { return (int) value; } + void set_int (int v) { value = v; } + int to_int () const { return value; } void set_fixed (int32_t v) { value = v / 65536.0; } - int32_t to_fixed () const { return (int32_t) (value * 65536.0); } + int32_t to_fixed () const { return value * 65536.0; } void set_real (double v) { value = v; } double to_real () const { return value; } - int ceil () const { return (int) ::ceil (value); } - int floor () const { return (int) ::floor (value); } - bool in_int_range () const { return ((double) (int16_t) to_int () == value); } @@ -248,37 +245,34 @@ struct number_t } protected: - double value; + double value; }; /* byte string */ struct UnsizedByteStr : UnsizedArrayOf { // encode 2-byte int (Dict/CharString) or 4-byte int (Dict) - template - static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value) + template + static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value) { TRACE_SERIALIZE (this); - if (unlikely ((value < minVal || value > maxVal))) - return_trace (false); - HBUINT8 *p = c->allocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); + if (unlikely (!p)) return_trace (false); *p = intOp; - INTTYPE *ip = c->allocate_size (INTTYPE::static_size); - if (unlikely (ip == nullptr)) return_trace (false); - *ip = (unsigned int) value; - - return_trace (true); + T *ip = c->allocate_size (T::static_size); + if (unlikely (!ip)) return_trace (false); + return_trace (c->check_assign (*ip, value, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } - static bool serialize_int4 (hb_serialize_context_t *c, int value) - { return serialize_int (c, OpCode_longintdict, value); } + template + static bool serialize_int4 (hb_serialize_context_t *c, V value) + { return serialize_int (c, OpCode_longintdict, value); } - static bool serialize_int2 (hb_serialize_context_t *c, int value) - { return serialize_int (c, OpCode_shortint, value); } + template + static bool serialize_int2 (hb_serialize_context_t *c, V value) + { return serialize_int (c, OpCode_shortint, value); } /* Defining null_size allows a Null object may be created. Should be safe because: * A descendent struct Dict uses a Null pointer to indicate a missing table, @@ -411,7 +405,7 @@ struct cff_stack_t else { set_error (); - return Crap(ELEM); + return Crap (ELEM); } } @@ -422,7 +416,7 @@ struct cff_stack_t else { set_error (); - return Crap(ELEM); + return Crap (ELEM); } } void pop (unsigned int n) @@ -438,7 +432,7 @@ struct cff_stack_t if (unlikely (count < 0)) { set_error (); - return Null(ELEM); + return Null (ELEM); } return elements[count - 1]; } @@ -545,7 +539,7 @@ struct op_serializer_t TRACE_SERIALIZE (this); HBUINT8 *d = c->allocate_size (opstr.str.length); - if (unlikely (d == nullptr)) return_trace (false); + if (unlikely (!d)) return_trace (false); memcpy (d, &opstr.str[0], opstr.str.length); return_trace (true); } diff --git a/src/hb-cff-interp-cs-common.hh b/src/hb-cff-interp-cs-common.hh index d9ad4d0d69ff72cd3d3d007b4e77e2bd45793f00..52d778ffe2925cb0146424b781212bf1bccbd164 100644 --- a/src/hb-cff-interp-cs-common.hh +++ b/src/hb-cff-interp-cs-common.hh @@ -76,13 +76,13 @@ struct biased_subrs_t void fini () {} - unsigned int get_count () const { return (subrs == nullptr) ? 0 : subrs->count; } + unsigned int get_count () const { return subrs ? subrs->count : 0; } unsigned int get_bias () const { return bias; } byte_str_t operator [] (unsigned int index) const { - if (unlikely ((subrs == nullptr) || index >= subrs->count)) - return Null(byte_str_t); + if (unlikely (!subrs || index >= subrs->count)) + return Null (byte_str_t); else return (*subrs)[index]; } @@ -551,8 +551,13 @@ struct path_procs_t static void rcurveline (ENV &env, PARAM& param) { + unsigned int arg_count = env.argStack.get_count (); + if (unlikely (arg_count < 8)) + return; + unsigned int i = 0; - for (; i + 6 <= env.argStack.get_count (); i += 6) + unsigned int curve_limit = arg_count - 2; + for (; i + 6 <= curve_limit; i += 6) { point_t pt1 = env.get_pt (); pt1.move (env.eval_arg (i), env.eval_arg (i+1)); @@ -562,34 +567,34 @@ struct path_procs_t pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); PATH::curve (env, param, pt1, pt2, pt3); } - for (; i + 2 <= env.argStack.get_count (); i += 2) - { - point_t pt1 = env.get_pt (); - pt1.move (env.eval_arg (i), env.eval_arg (i+1)); - PATH::line (env, param, pt1); - } + + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + PATH::line (env, param, pt1); } static void rlinecurve (ENV &env, PARAM& param) { + unsigned int arg_count = env.argStack.get_count (); + if (unlikely (arg_count < 8)) + return; + unsigned int i = 0; - unsigned int line_limit = (env.argStack.get_count () % 6); + unsigned int line_limit = arg_count - 6; for (; i + 2 <= line_limit; i += 2) { point_t pt1 = env.get_pt (); pt1.move (env.eval_arg (i), env.eval_arg (i+1)); PATH::line (env, param, pt1); } - for (; i + 6 <= env.argStack.get_count (); i += 6) - { - point_t pt1 = env.get_pt (); - pt1.move (env.eval_arg (i), env.eval_arg (i+1)); - point_t pt2 = pt1; - pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); - point_t pt3 = pt2; - pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); - PATH::curve (env, param, pt1, pt2, pt3); - } + + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); + PATH::curve (env, param, pt1, pt2, pt3); } static void vvcurveto (ENV &env, PARAM& param) diff --git a/src/hb-cff-interp-dict-common.hh b/src/hb-cff-interp-dict-common.hh index ea0db13f85b40a60b79141fde673f25f7a09df6f..a520ca3bce50b6f0ae6a28221a3e5b78595c3f63 100644 --- a/src/hb-cff-interp-dict-common.hh +++ b/src/hb-cff-interp-dict-common.hh @@ -27,8 +27,6 @@ #define HB_CFF_INTERP_DICT_COMMON_HH #include "hb-cff-interp-common.hh" -#include -#include namespace CFF { @@ -58,19 +56,6 @@ struct top_dict_values_t : dict_values_t } void fini () { dict_values_t::fini (); } - unsigned int calculate_serialized_op_size (const OPSTR& opstr) const - { - switch (opstr.op) - { - case OpCode_CharStrings: - case OpCode_FDArray: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return opstr.str.length; - } - } - unsigned int charStringsOffset; unsigned int FDArrayOffset; }; @@ -94,130 +79,52 @@ struct dict_opset_t : opset_t } } + /* Turns CFF's BCD format into strtod understandable string */ static double parse_bcd (byte_str_ref_t& str_ref) { - bool neg = false; - double int_part = 0; - uint64_t frac_part = 0; - uint32_t frac_count = 0; - bool exp_neg = false; - uint32_t exp_part = 0; - bool exp_overflow = false; - enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; + if (unlikely (str_ref.in_error ())) return .0; + enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; - const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */ - const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */ - double value = 0.0; + char buf[32]; unsigned char byte = 0; - for (uint32_t i = 0;; i++) + for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) { - char d; - if ((i & 1) == 0) + unsigned nibble; + if (!(i & 1)) { - if (!str_ref.avail ()) - { - str_ref.set_error (); - return 0.0; - } + if (unlikely (!str_ref.avail ())) break; + byte = str_ref[0]; str_ref.inc (); - d = byte >> 4; + nibble = byte >> 4; } else - d = byte & 0x0F; + nibble = byte & 0x0F; - switch (d) + if (unlikely (nibble == RESERVED)) break; + else if (nibble == END) { - case RESERVED: - str_ref.set_error (); - return value; - - case END: - value = (double) (neg ? -int_part : int_part); - if (frac_count > 0) - { - double frac = (frac_part / pow (10.0, (double) frac_count)); - if (neg) frac = -frac; - value += frac; - } - if (unlikely (exp_overflow)) - { - if (value == 0.0) - return value; - if (exp_neg) - return neg ? -DBL_MIN : DBL_MIN; - else - return neg ? -DBL_MAX : DBL_MAX; - } - if (exp_part != 0) - { - if (exp_neg) - value /= pow (10.0, (double) exp_part); - else - value *= pow (10.0, (double) exp_part); - } - return value; - - case NEG: - if (i != 0) - { - str_ref.set_error (); - return 0.0; - } - neg = true; - break; - - case DECIMAL: - if (part != INT_PART) - { - str_ref.set_error (); - return value; - } - part = FRAC_PART; + const char *p = buf; + double pv; + if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */))) break; - - case EXP_NEG: - exp_neg = true; - HB_FALLTHROUGH; - - case EXP_POS: - if (part == EXP_PART) - { - str_ref.set_error (); - return value; - } - part = EXP_PART; - break; - - default: - switch (part) { - default: - case INT_PART: - int_part = (int_part * 10) + d; - break; - - case FRAC_PART: - if (likely (frac_part <= MAX_FRACT / 10)) - { - frac_part = (frac_part * 10) + (unsigned)d; - frac_count++; - } - break; - - case EXP_PART: - if (likely (exp_part * 10 + d <= MAX_EXP)) - { - exp_part = (exp_part * 10) + d; - } - else - exp_overflow = true; - break; - } + return pv; + } + else + { + buf[count] = "0123456789.EE?-?"[nibble]; + if (nibble == EXP_NEG) + { + ++count; + if (unlikely (count == ARRAY_LENGTH (buf))) break; + buf[count] = '-'; + } } } - return value; + str_ref.set_error (); + return .0; } static bool is_hint_op (op_code_t op) diff --git a/src/hb-cff2-interp-cs.hh b/src/hb-cff2-interp-cs.hh index a72100e1aba07c293c38f41a488639e49a7e5b6a..332ece31cd4fde452ebe96717259f1dcd0a50f65 100644 --- a/src/hb-cff2-interp-cs.hh +++ b/src/hb-cff2-interp-cs.hh @@ -52,7 +52,7 @@ struct blend_arg_t : number_t void set_real (double v) { reset_blends (); number_t::set_real (v); } void set_blends (unsigned int numValues_, unsigned int valueIndex_, - unsigned int numBlends, hb_array_t blends_) + unsigned int numBlends, hb_array_t blends_) { numValues = numValues_; valueIndex = valueIndex_; @@ -80,7 +80,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t { template void init (const byte_str_t &str, ACC &acc, unsigned int fd, - const int *coords_=nullptr, unsigned int num_coords_=0) + const int *coords_=nullptr, unsigned int num_coords_=0) { SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); @@ -90,7 +90,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t seen_blend = false; seen_vsindex_ = false; scalars.init (); - do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore)); + do_blend = num_coords && coords && varStore->size; set_ivs (acc.privateDicts[fd].ivs); } @@ -133,10 +133,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t region_count = varStore->varStore.get_region_index_count (get_ivs ()); if (do_blend) { - scalars.resize (region_count); - varStore->varStore.get_scalars (get_ivs (), - (int *)coords, num_coords, - &scalars[0], region_count); + if (unlikely (!scalars.resize (region_count))) + set_error (); + else + varStore->varStore.get_scalars (get_ivs (), coords, num_coords, + &scalars[0], region_count); } seen_blend = true; } diff --git a/src/hb-common.cc b/src/hb-common.cc index 9035755a4e4756260504c1b1638cf752310c344d..7bb878b21701c575a027c92de0d53599cbe73946 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc @@ -27,13 +27,9 @@ */ #include "hb.hh" - #include "hb-machinery.hh" #include -#ifdef HAVE_XLOCALE_H -#include -#endif #ifdef HB_NO_SETLOCALE #define setlocale(Category, Locale) "C" @@ -67,13 +63,12 @@ _hb_options_init () { const char *p = strchr (c, ':'); if (!p) - p = c + strlen (c); + p = c + strlen (c); #define OPTION(name, symbol) \ if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast(p - c)) do { u.opts.symbol = true; } while (0) OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible); - OPTION ("aat", aat); #undef OPTION @@ -91,12 +86,15 @@ _hb_options_init () /** * hb_tag_from_string: - * @str: (array length=len) (element-type uint8_t): - * @len: - * + * @str: (array length=len) (element-type uint8_t): String to convert + * @len: Length of @str, or -1 if it is %NULL-terminated * + * Converts a string into an #hb_tag_t. Valid tags + * are four characters. Shorter input strings will be + * padded with spaces. Longer input strings will be + * truncated. * - * Return value: + * Return value: The #hb_tag_t corresponding to @str * * Since: 0.9.2 **/ @@ -121,10 +119,11 @@ hb_tag_from_string (const char *str, int len) /** * hb_tag_to_string: - * @tag: - * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): - * + * @tag: #hb_tag_t to convert + * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string * + * Converts an #hb_tag_t to a string and returns it in @buf. + * Strings will be four characters long. * * Since: 0.9.5 **/ @@ -149,12 +148,17 @@ const char direction_strings[][4] = { /** * hb_direction_from_string: - * @str: (array length=len) (element-type uint8_t): - * @len: + * @str: (array length=len) (element-type uint8_t): String to convert + * @len: Length of @str, or -1 if it is %NULL-terminated * + * Converts a string to an #hb_direction_t. * + * Matching is loose and applies only to the first letter. For + * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR. * - * Return value: + * Unmatched strings will return #HB_DIRECTION_INVALID. + * + * Return value: The #hb_direction_t matching @str * * Since: 0.9.2 **/ @@ -177,11 +181,11 @@ hb_direction_from_string (const char *str, int len) /** * hb_direction_to_string: - * @direction: + * @direction: The #hb_direction_t to convert * + * Converts an #hb_direction_t to a string. * - * - * Return value: (transfer none): + * Return value: (transfer none): The string corresponding to @direction * * Since: 0.9.2 **/ @@ -337,14 +341,14 @@ retry: /** * hb_language_from_string: * @str: (array length=len) (element-type uint8_t): a string representing - * a BCP 47 language tag + * a BCP 47 language tag * @len: length of the @str, or -1 if it is %NULL-terminated. * - * Converts @str representing a BCP 47 language tag to the corresponding + * Converts @str representing a BCP 47 language tag to the corresponding * #hb_language_t. * * Return value: (transfer none): - * The #hb_language_t corresponding to the BCP 47 language tag. + * The #hb_language_t corresponding to the BCP 47 language tag. * * Since: 0.9.2 **/ @@ -372,9 +376,9 @@ hb_language_from_string (const char *str, int len) /** * hb_language_to_string: - * @language: an #hb_language_t to convert. + * @language: The #hb_language_t to convert * - * See hb_language_from_string(). + * Converts an #hb_language_t to a string. * * Return value: (transfer none): * A %NULL-terminated string representing the @language. Must not be freed by @@ -385,23 +389,25 @@ hb_language_from_string (const char *str, int len) const char * hb_language_to_string (hb_language_t language) { - /* This is actually nullptr-safe! */ + if (unlikely (!language)) return nullptr; + return language->s; } /** * hb_language_get_default: * - * Get default language from current locale. + * Fetch the default language from current locale. * - * Note that the first time this function is called, it calls + * Note that the first time this function is called, it calls * "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying * setlocale function is, in many implementations, NOT threadsafe. To avoid * problems, call this function once before multiple threads can call it. * This function is only used from hb_buffer_guess_segment_properties() by - * HarfBuzz itself. + * HarfBuzz itself. * - * Return value: (transfer none): + * Return value: (transfer none): The default language of the locale as + * an #hb_language_t * * Since: 0.9.2 **/ @@ -425,12 +431,12 @@ hb_language_get_default () /** * hb_script_from_iso15924_tag: - * @tag: an #hb_tag_t representing an ISO 15924 tag. + * @tag: an #hb_tag_t representing an ISO 15924 tag. * - * Converts an ISO 15924 script tag to a corresponding #hb_script_t. + * Converts an ISO 15924 script tag to a corresponding #hb_script_t. * * Return value: - * An #hb_script_t corresponding to the ISO 15924 tag. + * An #hb_script_t corresponding to the ISO 15924 tag. * * Since: 0.9.2 **/ @@ -452,7 +458,12 @@ hb_script_from_iso15924_tag (hb_tag_t tag) case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC; /* Script variants from https://unicode.org/iso15924/ */ + case HB_TAG('A','r','a','n'): return HB_SCRIPT_ARABIC; case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC; + case HB_TAG('G','e','o','k'): return HB_SCRIPT_GEORGIAN; + case HB_TAG('H','a','n','s'): return HB_SCRIPT_HAN; + case HB_TAG('H','a','n','t'): return HB_SCRIPT_HAN; + case HB_TAG('J','a','m','o'): return HB_SCRIPT_HANGUL; case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN; case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN; case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC; @@ -471,15 +482,15 @@ hb_script_from_iso15924_tag (hb_tag_t tag) /** * hb_script_from_string: * @str: (array length=len) (element-type uint8_t): a string representing an - * ISO 15924 tag. + * ISO 15924 tag. * @len: length of the @str, or -1 if it is %NULL-terminated. * - * Converts a string @str representing an ISO 15924 script tag to a + * Converts a string @str representing an ISO 15924 script tag to a * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then * hb_script_from_iso15924_tag(). * * Return value: - * An #hb_script_t corresponding to the ISO 15924 tag. + * An #hb_script_t corresponding to the ISO 15924 tag. * * Since: 0.9.2 **/ @@ -493,10 +504,10 @@ hb_script_from_string (const char *str, int len) * hb_script_to_iso15924_tag: * @script: an #hb_script_t to convert. * - * See hb_script_from_iso15924_tag(). + * Converts an #hb_script_t to a corresponding ISO 15924 script tag. * * Return value: - * An #hb_tag_t representing an ISO 15924 script tag. + * An #hb_tag_t representing an ISO 15924 script tag. * * Since: 0.9.2 **/ @@ -508,11 +519,16 @@ hb_script_to_iso15924_tag (hb_script_t script) /** * hb_script_get_horizontal_direction: - * @script: - * + * @script: The #hb_script_t to query * + * Fetches the #hb_direction_t of a script when it is + * set horizontally. All right-to-left scripts will return + * #HB_DIRECTION_RTL. All left-to-right scripts will return + * #HB_DIRECTION_LTR. Scripts that can be written either + * horizontally or vertically will return #HB_DIRECTION_INVALID. + * Unknown scripts will return #HB_DIRECTION_LTR. * - * Return value: + * Return value: The horizontal #hb_direction_t of @script * * Since: 0.9.2 **/ @@ -578,6 +594,13 @@ hb_script_get_horizontal_direction (hb_script_t script) case HB_SCRIPT_OLD_SOGDIAN: case HB_SCRIPT_SOGDIAN: + /* Unicode-12.0 additions */ + case HB_SCRIPT_ELYMAIC: + + /* Unicode-13.0 additions */ + case HB_SCRIPT_CHORASMIAN: + case HB_SCRIPT_YEZIDI: + return HB_DIRECTION_RTL; @@ -593,38 +616,6 @@ hb_script_get_horizontal_direction (hb_script_t script) } -/* hb_user_data_array_t */ - -bool -hb_user_data_array_t::set (hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, - hb_bool_t replace) -{ - if (!key) - return false; - - if (replace) { - if (!data && !destroy) { - items.remove (key, lock); - return true; - } - } - hb_user_data_item_t item = {key, data, destroy}; - bool ret = !!items.replace_or_insert (item, lock, (bool) replace); - - return ret; -} - -void * -hb_user_data_array_t::get (hb_user_data_key_t *key) -{ - hb_user_data_item_t item = {nullptr, nullptr, nullptr}; - - return items.find (key, &item, lock) ? item.data : nullptr; -} - - /* hb_version */ @@ -642,9 +633,9 @@ hb_user_data_array_t::get (hb_user_data_key_t *key) /** * hb_version: - * @major: (out): Library major version component. - * @minor: (out): Library minor version component. - * @micro: (out): Library micro version component. + * @major: (out): Library major version component + * @minor: (out): Library minor version component + * @micro: (out): Library micro version component * * Returns library version as three integer components. * @@ -665,7 +656,7 @@ hb_version (unsigned int *major, * * Returns library version as a string with three components. * - * Return value: library version string. + * Return value: Library version string * * Since: 0.9.2 **/ @@ -677,13 +668,15 @@ hb_version_string () /** * hb_version_atleast: - * @major: - * @minor: - * @micro: - * + * @major: Library major version component + * @minor: Library minor version component + * @micro: Library micro version component * + * Tests the library version against a minimum value, + * as three integer components. * - * Return value: + * Return value: %true if the library is equal to or greater than + * the test value, %false otherwise * * Since: 0.9.30 **/ @@ -722,131 +715,24 @@ parse_char (const char **pp, const char *end, char c) static bool parse_uint (const char **pp, const char *end, unsigned int *pv) { - char buf[32]; - unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - unsigned int v; - - /* Intentionally use strtol instead of strtoul, such that - * -1 turns into "big number"... */ - errno = 0; - v = strtol (p, &pend, 10); - if (errno || p == pend) - return false; + /* Intentionally use hb_parse_int inside instead of hb_parse_uint, + * such that -1 turns into "big number"... */ + int v; + if (unlikely (!hb_parse_int (pp, end, &v))) return false; *pv = v; - *pp += pend - p; return true; } static bool parse_uint32 (const char **pp, const char *end, uint32_t *pv) { - char buf[32]; - unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - unsigned int v; - - /* Intentionally use strtol instead of strtoul, such that - * -1 turns into "big number"... */ - errno = 0; - v = strtol (p, &pend, 10); - if (errno || p == pend) - return false; - - *pv = v; - *pp += pend - p; - return true; -} - -#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L) -#define USE_XLOCALE 1 -#define HB_LOCALE_T locale_t -#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr) -#define HB_FREE_LOCALE(loc) freelocale (loc) -#elif defined(_MSC_VER) -#define USE_XLOCALE 1 -#define HB_LOCALE_T _locale_t -#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName) -#define HB_FREE_LOCALE(loc) _free_locale (loc) -#define strtod_l(a, b, c) _strtod_l ((a), (b), (c)) -#endif - -#ifdef USE_XLOCALE - -#if HB_USE_ATEXIT -static void free_static_C_locale (); -#endif - -static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t, - hb_C_locale_lazy_loader_t> -{ - static HB_LOCALE_T create () - { - HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C"); - -#if HB_USE_ATEXIT - atexit (free_static_C_locale); -#endif - - return C_locale; - } - static void destroy (HB_LOCALE_T p) - { - HB_FREE_LOCALE (p); - } - static HB_LOCALE_T get_null () - { - return nullptr; - } -} static_C_locale; - -#if HB_USE_ATEXIT -static -void free_static_C_locale () -{ - static_C_locale.free_instance (); -} -#endif - -static HB_LOCALE_T -get_C_locale () -{ - return static_C_locale.get_unconst (); -} -#endif /* USE_XLOCALE */ - -static bool -parse_float (const char **pp, const char *end, float *pv) -{ - char buf[32]; - unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - float v; - - errno = 0; -#ifdef USE_XLOCALE - v = strtod_l (p, &pend, get_C_locale ()); -#else - v = strtod (p, &pend); -#endif - if (errno || p == pend) - return false; + /* Intentionally use hb_parse_int inside instead of hb_parse_uint, + * such that -1 turns into "big number"... */ + int v; + if (unlikely (!hb_parse_int (pp, end, &v))) return false; *pv = v; - *pp += pend - p; return true; } @@ -956,7 +842,7 @@ parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *fea { bool had_equal = parse_char (pp, end, '='); bool had_value = parse_uint32 (pp, end, &feature->value) || - parse_bool (pp, end, &feature->value); + parse_bool (pp, end, &feature->value); /* CSS doesn't use equal-sign between tag and value. * If there was an equal-sign, then there *must* be a value. * A value without an equal-sign is ok, but not required. */ @@ -1019,7 +905,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) * * * Return value: - * %true if @str is successfully parsed, %false otherwise. + * %true if @str is successfully parsed, %false otherwise * * Since: 0.9.5 **/ @@ -1070,14 +956,14 @@ hb_feature_to_string (hb_feature_t *feature, len += 4; while (len && s[len - 1] == ' ') len--; - if (feature->start != 0 || feature->end != (unsigned int) -1) + if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END) { s[len++] = '['; if (feature->start) len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start)); if (feature->end != feature->start + 1) { s[len++] = ':'; - if (feature->end != (unsigned int) -1) + if (feature->end != HB_FEATURE_GLOBAL_END) len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end)); } s[len++] = ']'; @@ -1099,7 +985,11 @@ static bool parse_variation_value (const char **pp, const char *end, hb_variation_t *variation) { parse_char (pp, end, '='); /* Optional. */ - return parse_float (pp, end, &variation->value); + double v; + if (unlikely (!hb_parse_double (pp, end, &v))) return false; + + variation->value = v; + return true; } static bool @@ -1113,6 +1003,21 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation /** * hb_variation_from_string: + * @str: (array length=len) (element-type uint8_t): a string to parse + * @len: length of @str, or -1 if string is %NULL terminated + * @variation: (out): the #hb_variation_t to initialize with the parsed values + * + * Parses a string into a #hb_variation_t. + * + * The format for specifying variation settings follows. All valid CSS + * font-variation-settings values other than 'normal' and 'inherited' are also + * accepted, though, not documented below. + * + * The format is a tag, optionally followed by an equals sign, followed by a + * number. For example `wght=500`, or `slnt=-7.5`. + * + * Return value: + * %true if @str is successfully parsed, %false otherwise * * Since: 1.4.2 */ @@ -1139,6 +1044,13 @@ hb_variation_from_string (const char *str, int len, /** * hb_variation_to_string: + * @variation: an #hb_variation_t to convert + * @buf: (array length=size) (out): output string + * @size: the allocated size of @buf + * + * Converts an #hb_variation_t into a %NULL-terminated string in the format + * understood by hb_variation_from_string(). The client in responsible for + * allocating big enough size for @buf, 128 bytes is more than enough. * * Since: 1.4.2 */ @@ -1165,9 +1077,11 @@ hb_variation_to_string (hb_variation_t *variation, /** * hb_color_get_alpha: - * color: a #hb_color_t we are interested in its channels. + * @color: an #hb_color_t we are interested in its channels. + * + * Fetches the alpha channel of the given @color. * - * Return value: Alpha channel value of the given color + * Return value: Alpha channel value * * Since: 2.1.0 */ @@ -1179,9 +1093,11 @@ uint8_t /** * hb_color_get_red: - * color: a #hb_color_t we are interested in its channels. + * @color: an #hb_color_t we are interested in its channels. + * + * Fetches the red channel of the given @color. * - * Return value: Red channel value of the given color + * Return value: Red channel value * * Since: 2.1.0 */ @@ -1193,9 +1109,11 @@ uint8_t /** * hb_color_get_green: - * color: a #hb_color_t we are interested in its channels. + * @color: an #hb_color_t we are interested in its channels. * - * Return value: Green channel value of the given color + * Fetches the green channel of the given @color. + * + * Return value: Green channel value * * Since: 2.1.0 */ @@ -1207,9 +1125,11 @@ uint8_t /** * hb_color_get_blue: - * color: a #hb_color_t we are interested in its channels. + * @color: an #hb_color_t we are interested in its channels. + * + * Fetches the blue channel of the given @color. * - * Return value: Blue channel value of the given color + * Return value: Blue channel value * * Since: 2.1.0 */ diff --git a/src/hb-common.h b/src/hb-common.h index edd9ffb86a45a3255642ab768c5194c49726a14b..532fd428cbcb50cfc1cffb5d7505d527cefa6605 100644 --- a/src/hb-common.h +++ b/src/hb-common.h @@ -26,7 +26,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -63,6 +63,8 @@ typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#elif defined (__KERNEL__) +# include #else # include #endif @@ -86,11 +88,37 @@ typedef unsigned __int64 uint64_t; HB_BEGIN_DECLS - +/** + * hb_bool_t: + * + * Data type for booleans. + * + **/ typedef int hb_bool_t; +/** + * hb_codepoint_t: + * + * Data type for holding Unicode codepoints. Also + * used to hold glyph IDs. + * + **/ typedef uint32_t hb_codepoint_t; +/** + * hb_position_t: + * + * Data type for holding a single coordinate value. + * Contour points and other multi-dimensional data are + * stored as tuples of #hb_position_t's. + * + **/ typedef int32_t hb_position_t; +/** + * hb_mask_t: + * + * Data type for bitmasks. + * + **/ typedef uint32_t hb_mask_t; typedef union _hb_var_int_t { @@ -105,13 +133,63 @@ typedef union _hb_var_int_t { /* hb_tag_t */ +/** + * hb_tag_t: + * + * Data type for tag identifiers. Tags are four + * byte integers, each byte representing a character. + * + * Tags are used to identify tables, design-variation axes, + * scripts, languages, font features, and baselines with + * human-readable names. + * + **/ typedef uint32_t hb_tag_t; +/** + * HB_TAG: + * @c1: 1st character of the tag + * @c2: 2nd character of the tag + * @c3: 3rd character of the tag + * @c4: 4th character of the tag + * + * Constructs an #hb_tag_t from four character literals. + * + **/ #define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF))) + +/** + * HB_UNTAG: + * @tag: an #hb_tag_t + * + * Extracts four character literals from an #hb_tag_t. + * + * Since: 0.6.0 + * + **/ #define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF) +/** + * HB_TAG_NONE: + * + * Unset #hb_tag_t. + */ #define HB_TAG_NONE HB_TAG(0,0,0,0) +/** + * HB_TAG_MAX: + * + * Maximum possible unsigned #hb_tag_t. + * + * Since: 0.9.26 + */ #define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff) +/** + * HB_TAG_MAX_SIGNED: + * + * Maximum possible signed #hb_tag_t. + * + * Since: 0.9.33 + */ #define HB_TAG_MAX_SIGNED HB_TAG(0x7f,0xff,0xff,0xff) /* len=-1 means str is NUL-terminated. */ @@ -130,6 +208,13 @@ hb_tag_to_string (hb_tag_t tag, char *buf); * @HB_DIRECTION_RTL: Text is set horizontally from right to left. * @HB_DIRECTION_TTB: Text is set vertically from top to bottom. * @HB_DIRECTION_BTT: Text is set vertically from bottom to top. + * + * The direction of a text segment or buffer. + * + * A segment can also be tested for horizontal or vertical + * orientation (irrespective of specific direction) with + * HB_DIRECTION_IS_HORIZONTAL() or HB_DIRECTION_IS_VERTICAL(). + * */ typedef enum { HB_DIRECTION_INVALID = 0, @@ -146,17 +231,71 @@ hb_direction_from_string (const char *str, int len); HB_EXTERN const char * hb_direction_to_string (hb_direction_t direction); +/** + * HB_DIRECTION_IS_VALID: + * @dir: #hb_direction_t to test + * + * Tests whether a text direction is valid. + * + **/ #define HB_DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4) /* Direction must be valid for the following */ +/** + * HB_DIRECTION_IS_HORIZONTAL: + * @dir: #hb_direction_t to test + * + * Tests whether a text direction is horizontal. Requires + * that the direction be valid. + * + **/ #define HB_DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4) +/** + * HB_DIRECTION_IS_VERTICAL: + * @dir: #hb_direction_t to test + * + * Tests whether a text direction is vertical. Requires + * that the direction be valid. + * + **/ #define HB_DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6) +/** + * HB_DIRECTION_IS_FORWARD: + * @dir: #hb_direction_t to test + * + * Tests whether a text direction moves forward (from left to right, or from + * top to bottom). Requires that the direction be valid. + * + **/ #define HB_DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4) +/** + * HB_DIRECTION_IS_BACKWARD: + * @dir: #hb_direction_t to test + * + * Tests whether a text direction moves backward (from right to left, or from + * bottom to top). Requires that the direction be valid. + * + **/ #define HB_DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5) +/** + * HB_DIRECTION_REVERSE: + * @dir: #hb_direction_t to reverse + * + * Reverses a text direction. Requires that the direction + * be valid. + * + **/ #define HB_DIRECTION_REVERSE(dir) ((hb_direction_t) (((unsigned int) (dir)) ^ 1)) /* hb_language_t */ +/** + * hb_language_t: + * + * Data type for languages. Each #hb_language_t corresponds to a BCP 47 + * language tag. + * + */ typedef const struct hb_language_impl_t *hb_language_t; HB_EXTERN hb_language_t @@ -165,208 +304,389 @@ hb_language_from_string (const char *str, int len); HB_EXTERN const char * hb_language_to_string (hb_language_t language); +/** + * HB_LANGUAGE_INVALID: + * + * An unset #hb_language_t. + * + * Since: 0.6.0 + */ #define HB_LANGUAGE_INVALID ((hb_language_t) 0) HB_EXTERN hb_language_t hb_language_get_default (void); -/* hb_script_t */ +/** + * hb_script_t: + * @HB_SCRIPT_COMMON: `Zyyy` + * @HB_SCRIPT_INHERITED: `Zinh` + * @HB_SCRIPT_UNKNOWN: `Zzzz` + * @HB_SCRIPT_ARABIC: `Arab` + * @HB_SCRIPT_ARMENIAN: `Armn` + * @HB_SCRIPT_BENGALI: `Beng` + * @HB_SCRIPT_CYRILLIC: `Cyrl` + * @HB_SCRIPT_DEVANAGARI: `Deva` + * @HB_SCRIPT_GEORGIAN: `Geor` + * @HB_SCRIPT_GREEK: `Grek` + * @HB_SCRIPT_GUJARATI: `Gujr` + * @HB_SCRIPT_GURMUKHI: `Guru` + * @HB_SCRIPT_HANGUL: `Hang` + * @HB_SCRIPT_HAN: `Hani` + * @HB_SCRIPT_HEBREW: `Hebr` + * @HB_SCRIPT_HIRAGANA: `Hira` + * @HB_SCRIPT_KANNADA: `Knda` + * @HB_SCRIPT_KATAKANA: `Kana` + * @HB_SCRIPT_LAO: `Laoo` + * @HB_SCRIPT_LATIN: `Latn` + * @HB_SCRIPT_MALAYALAM: `Mlym` + * @HB_SCRIPT_ORIYA: `Orya` + * @HB_SCRIPT_TAMIL: `Taml` + * @HB_SCRIPT_TELUGU: `Telu` + * @HB_SCRIPT_THAI: `Thai` + * @HB_SCRIPT_TIBETAN: `Tibt` + * @HB_SCRIPT_BOPOMOFO: `Bopo` + * @HB_SCRIPT_BRAILLE: `Brai` + * @HB_SCRIPT_CANADIAN_SYLLABICS: `Cans` + * @HB_SCRIPT_CHEROKEE: `Cher` + * @HB_SCRIPT_ETHIOPIC: `Ethi` + * @HB_SCRIPT_KHMER: `Khmr` + * @HB_SCRIPT_MONGOLIAN: `Mong` + * @HB_SCRIPT_MYANMAR: `Mymr` + * @HB_SCRIPT_OGHAM: `Ogam` + * @HB_SCRIPT_RUNIC: `Runr` + * @HB_SCRIPT_SINHALA: `Sinh` + * @HB_SCRIPT_SYRIAC: `Syrc` + * @HB_SCRIPT_THAANA: `Thaa` + * @HB_SCRIPT_YI: `Yiii` + * @HB_SCRIPT_DESERET: `Dsrt` + * @HB_SCRIPT_GOTHIC: `Goth` + * @HB_SCRIPT_OLD_ITALIC: `Ital` + * @HB_SCRIPT_BUHID: `Buhd` + * @HB_SCRIPT_HANUNOO: `Hano` + * @HB_SCRIPT_TAGALOG: `Tglg` + * @HB_SCRIPT_TAGBANWA: `Tagb` + * @HB_SCRIPT_CYPRIOT: `Cprt` + * @HB_SCRIPT_LIMBU: `Limb` + * @HB_SCRIPT_LINEAR_B: `Linb` + * @HB_SCRIPT_OSMANYA: `Osma` + * @HB_SCRIPT_SHAVIAN: `Shaw` + * @HB_SCRIPT_TAI_LE: `Tale` + * @HB_SCRIPT_UGARITIC: `Ugar` + * @HB_SCRIPT_BUGINESE: `Bugi` + * @HB_SCRIPT_COPTIC: `Copt` + * @HB_SCRIPT_GLAGOLITIC: `Glag` + * @HB_SCRIPT_KHAROSHTHI: `Khar` + * @HB_SCRIPT_NEW_TAI_LUE: `Talu` + * @HB_SCRIPT_OLD_PERSIAN: `Xpeo` + * @HB_SCRIPT_SYLOTI_NAGRI: `Sylo` + * @HB_SCRIPT_TIFINAGH: `Tfng` + * @HB_SCRIPT_BALINESE: `Bali` + * @HB_SCRIPT_CUNEIFORM: `Xsux` + * @HB_SCRIPT_NKO: `Nkoo` + * @HB_SCRIPT_PHAGS_PA: `Phag` + * @HB_SCRIPT_PHOENICIAN: `Phnx` + * @HB_SCRIPT_CARIAN: `Cari` + * @HB_SCRIPT_CHAM: `Cham` + * @HB_SCRIPT_KAYAH_LI: `Kali` + * @HB_SCRIPT_LEPCHA: `Lepc` + * @HB_SCRIPT_LYCIAN: `Lyci` + * @HB_SCRIPT_LYDIAN: `Lydi` + * @HB_SCRIPT_OL_CHIKI: `Olck` + * @HB_SCRIPT_REJANG: `Rjng` + * @HB_SCRIPT_SAURASHTRA: `Saur` + * @HB_SCRIPT_SUNDANESE: `Sund` + * @HB_SCRIPT_VAI: `Vaii` + * @HB_SCRIPT_AVESTAN: `Avst` + * @HB_SCRIPT_BAMUM: `Bamu` + * @HB_SCRIPT_EGYPTIAN_HIEROGLYPHS: `Egyp` + * @HB_SCRIPT_IMPERIAL_ARAMAIC: `Armi` + * @HB_SCRIPT_INSCRIPTIONAL_PAHLAVI: `Phli` + * @HB_SCRIPT_INSCRIPTIONAL_PARTHIAN: `Prti` + * @HB_SCRIPT_JAVANESE: `Java` + * @HB_SCRIPT_KAITHI: `Kthi` + * @HB_SCRIPT_LISU: `Lisu` + * @HB_SCRIPT_MEETEI_MAYEK: `Mtei` + * @HB_SCRIPT_OLD_SOUTH_ARABIAN: `Sarb` + * @HB_SCRIPT_OLD_TURKIC: `Orkh` + * @HB_SCRIPT_SAMARITAN: `Samr` + * @HB_SCRIPT_TAI_THAM: `Lana` + * @HB_SCRIPT_TAI_VIET: `Tavt` + * @HB_SCRIPT_BATAK: `Batk` + * @HB_SCRIPT_BRAHMI: `Brah` + * @HB_SCRIPT_MANDAIC: `Mand` + * @HB_SCRIPT_CHAKMA: `Cakm` + * @HB_SCRIPT_MEROITIC_CURSIVE: `Merc` + * @HB_SCRIPT_MEROITIC_HIEROGLYPHS: `Mero` + * @HB_SCRIPT_MIAO: `Plrd` + * @HB_SCRIPT_SHARADA: `Shrd` + * @HB_SCRIPT_SORA_SOMPENG: `Sora` + * @HB_SCRIPT_TAKRI: `Takr` + * @HB_SCRIPT_BASSA_VAH: `Bass`, Since: 0.9.30 + * @HB_SCRIPT_CAUCASIAN_ALBANIAN: `Aghb`, Since: 0.9.30 + * @HB_SCRIPT_DUPLOYAN: `Dupl`, Since: 0.9.30 + * @HB_SCRIPT_ELBASAN: `Elba`, Since: 0.9.30 + * @HB_SCRIPT_GRANTHA: `Gran`, Since: 0.9.30 + * @HB_SCRIPT_KHOJKI: `Khoj`, Since: 0.9.30 + * @HB_SCRIPT_KHUDAWADI: `Sind`, Since: 0.9.30 + * @HB_SCRIPT_LINEAR_A: `Lina`, Since: 0.9.30 + * @HB_SCRIPT_MAHAJANI: `Mahj`, Since: 0.9.30 + * @HB_SCRIPT_MANICHAEAN: `Mani`, Since: 0.9.30 + * @HB_SCRIPT_MENDE_KIKAKUI: `Mend`, Since: 0.9.30 + * @HB_SCRIPT_MODI: `Modi`, Since: 0.9.30 + * @HB_SCRIPT_MRO: `Mroo`, Since: 0.9.30 + * @HB_SCRIPT_NABATAEAN: `Nbat`, Since: 0.9.30 + * @HB_SCRIPT_OLD_NORTH_ARABIAN: `Narb`, Since: 0.9.30 + * @HB_SCRIPT_OLD_PERMIC: `Perm`, Since: 0.9.30 + * @HB_SCRIPT_PAHAWH_HMONG: `Hmng`, Since: 0.9.30 + * @HB_SCRIPT_PALMYRENE: `Palm`, Since: 0.9.30 + * @HB_SCRIPT_PAU_CIN_HAU: `Pauc`, Since: 0.9.30 + * @HB_SCRIPT_PSALTER_PAHLAVI: `Phlp`, Since: 0.9.30 + * @HB_SCRIPT_SIDDHAM: `Sidd`, Since: 0.9.30 + * @HB_SCRIPT_TIRHUTA: `Tirh`, Since: 0.9.30 + * @HB_SCRIPT_WARANG_CITI: `Wara`, Since: 0.9.30 + * @HB_SCRIPT_AHOM: `Ahom`, Since: 0.9.30 + * @HB_SCRIPT_ANATOLIAN_HIEROGLYPHS: `Hluw`, Since: 0.9.30 + * @HB_SCRIPT_HATRAN: `Hatr`, Since: 0.9.30 + * @HB_SCRIPT_MULTANI: `Mult`, Since: 0.9.30 + * @HB_SCRIPT_OLD_HUNGARIAN: `Hung`, Since: 0.9.30 + * @HB_SCRIPT_SIGNWRITING: `Sgnw`, Since: 0.9.30 + * @HB_SCRIPT_ADLAM: `Adlm`, Since: 1.3.0 + * @HB_SCRIPT_BHAIKSUKI: `Bhks`, Since: 1.3.0 + * @HB_SCRIPT_MARCHEN: `Marc`, Since: 1.3.0 + * @HB_SCRIPT_OSAGE: `Osge`, Since: 1.3.0 + * @HB_SCRIPT_TANGUT: `Tang`, Since: 1.3.0 + * @HB_SCRIPT_NEWA: `Newa`, Since: 1.3.0 + * @HB_SCRIPT_MASARAM_GONDI: `Gonm`, Since: 1.6.0 + * @HB_SCRIPT_NUSHU: `Nshu`, Since: 1.6.0 + * @HB_SCRIPT_SOYOMBO: `Soyo`, Since: 1.6.0 + * @HB_SCRIPT_ZANABAZAR_SQUARE: `Zanb`, Since: 1.6.0 + * @HB_SCRIPT_DOGRA: `Dogr`, Since: 1.8.0 + * @HB_SCRIPT_GUNJALA_GONDI: `Gong`, Since: 1.8.0 + * @HB_SCRIPT_HANIFI_ROHINGYA: `Rohg`, Since: 1.8.0 + * @HB_SCRIPT_MAKASAR: `Maka`, Since: 1.8.0 + * @HB_SCRIPT_MEDEFAIDRIN: `Medf`, Since: 1.8.0 + * @HB_SCRIPT_OLD_SOGDIAN: `Sogo`, Since: 1.8.0 + * @HB_SCRIPT_SOGDIAN: `Sogd`, Since: 1.8.0 + * @HB_SCRIPT_ELYMAIC: `Elym`, Since: 2.4.0 + * @HB_SCRIPT_NANDINAGARI: `Nand`, Since: 2.4.0 + * @HB_SCRIPT_NYIAKENG_PUACHUE_HMONG: `Hmnp`, Since: 2.4.0 + * @HB_SCRIPT_WANCHO: `Wcho`, Since: 2.4.0 + * @HB_SCRIPT_CHORASMIAN: `Chrs`, Since: 2.6.7 + * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7 + * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7 + * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7 + * @HB_SCRIPT_INVALID: No script set + * + * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding + * to the four-letter values defined by [ISO 15924](https://unicode.org/iso15924/). + * + * See also the Script (sc) property of the Unicode Character Database. + * + **/ -/* https://unicode.org/iso15924/ */ /* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */ -/* Unicode Character Database property: Script (sc) */ typedef enum { - /*1.1*/ HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), - /*1.1*/ HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), - /*5.0*/ HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), - - /*1.1*/ HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), - /*1.1*/ HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), - /*1.1*/ HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), - /*1.1*/ HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), - /*1.1*/ HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), - /*1.1*/ HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), - /*1.1*/ HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), - /*1.1*/ HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), - /*1.1*/ HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), - /*1.1*/ HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), - /*1.1*/ HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), - /*1.1*/ HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), - /*1.1*/ HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), - /*1.1*/ HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), - /*1.1*/ HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), - /*1.1*/ HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), - /*1.1*/ HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), - /*1.1*/ HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), - /*1.1*/ HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), - /*1.1*/ HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), - /*1.1*/ HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), - /*1.1*/ HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), - - /*2.0*/ HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), - - /*3.0*/ HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), - /*3.0*/ HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), - /*3.0*/ HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), - /*3.0*/ HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), - /*3.0*/ HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), - /*3.0*/ HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), - /*3.0*/ HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), - /*3.0*/ HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), - /*3.0*/ HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), - /*3.0*/ HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), - /*3.0*/ HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), - /*3.0*/ HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), - /*3.0*/ HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), - /*3.0*/ HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), - - /*3.1*/ HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), - /*3.1*/ HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), - /*3.1*/ HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), - - /*3.2*/ HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), - /*3.2*/ HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), - /*3.2*/ HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), - /*3.2*/ HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), - - /*4.0*/ HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), - /*4.0*/ HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), - /*4.0*/ HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), - /*4.0*/ HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), - /*4.0*/ HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), - /*4.0*/ HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), - /*4.0*/ HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), - - /*4.1*/ HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), - /*4.1*/ HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), - /*4.1*/ HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), - /*4.1*/ HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), - /*4.1*/ HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), - /*4.1*/ HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), - /*4.1*/ HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), - /*4.1*/ HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), - - /*5.0*/ HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), - /*5.0*/ HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), - /*5.0*/ HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), - /*5.0*/ HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), - /*5.0*/ HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), - - /*5.1*/ HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), - /*5.1*/ HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), - /*5.1*/ HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), - /*5.1*/ HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), - /*5.1*/ HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), - /*5.1*/ HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), - /*5.1*/ HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), - /*5.1*/ HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), - /*5.1*/ HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), - /*5.1*/ HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), - /*5.1*/ HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), - - /*5.2*/ HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), - /*5.2*/ HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), - /*5.2*/ HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), - /*5.2*/ HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), - /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), - /*5.2*/ HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), - /*5.2*/ HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), - /*5.2*/ HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), - /*5.2*/ HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), - /*5.2*/ HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), - /*5.2*/ HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), - /*5.2*/ HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), - /*5.2*/ HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), - /*5.2*/ HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), - /*5.2*/ HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), - - /*6.0*/ HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), - /*6.0*/ HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), - /*6.0*/ HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), - - /*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), - /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), - /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), - /*6.1*/ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), - /*6.1*/ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), - /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), - /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), + HB_SCRIPT_COMMON = HB_TAG ('Z','y','y','y'), /*1.1*/ + HB_SCRIPT_INHERITED = HB_TAG ('Z','i','n','h'), /*1.1*/ + HB_SCRIPT_UNKNOWN = HB_TAG ('Z','z','z','z'), /*5.0*/ + + HB_SCRIPT_ARABIC = HB_TAG ('A','r','a','b'), /*1.1*/ + HB_SCRIPT_ARMENIAN = HB_TAG ('A','r','m','n'), /*1.1*/ + HB_SCRIPT_BENGALI = HB_TAG ('B','e','n','g'), /*1.1*/ + HB_SCRIPT_CYRILLIC = HB_TAG ('C','y','r','l'), /*1.1*/ + HB_SCRIPT_DEVANAGARI = HB_TAG ('D','e','v','a'), /*1.1*/ + HB_SCRIPT_GEORGIAN = HB_TAG ('G','e','o','r'), /*1.1*/ + HB_SCRIPT_GREEK = HB_TAG ('G','r','e','k'), /*1.1*/ + HB_SCRIPT_GUJARATI = HB_TAG ('G','u','j','r'), /*1.1*/ + HB_SCRIPT_GURMUKHI = HB_TAG ('G','u','r','u'), /*1.1*/ + HB_SCRIPT_HANGUL = HB_TAG ('H','a','n','g'), /*1.1*/ + HB_SCRIPT_HAN = HB_TAG ('H','a','n','i'), /*1.1*/ + HB_SCRIPT_HEBREW = HB_TAG ('H','e','b','r'), /*1.1*/ + HB_SCRIPT_HIRAGANA = HB_TAG ('H','i','r','a'), /*1.1*/ + HB_SCRIPT_KANNADA = HB_TAG ('K','n','d','a'), /*1.1*/ + HB_SCRIPT_KATAKANA = HB_TAG ('K','a','n','a'), /*1.1*/ + HB_SCRIPT_LAO = HB_TAG ('L','a','o','o'), /*1.1*/ + HB_SCRIPT_LATIN = HB_TAG ('L','a','t','n'), /*1.1*/ + HB_SCRIPT_MALAYALAM = HB_TAG ('M','l','y','m'), /*1.1*/ + HB_SCRIPT_ORIYA = HB_TAG ('O','r','y','a'), /*1.1*/ + HB_SCRIPT_TAMIL = HB_TAG ('T','a','m','l'), /*1.1*/ + HB_SCRIPT_TELUGU = HB_TAG ('T','e','l','u'), /*1.1*/ + HB_SCRIPT_THAI = HB_TAG ('T','h','a','i'), /*1.1*/ + + HB_SCRIPT_TIBETAN = HB_TAG ('T','i','b','t'), /*2.0*/ + + HB_SCRIPT_BOPOMOFO = HB_TAG ('B','o','p','o'), /*3.0*/ + HB_SCRIPT_BRAILLE = HB_TAG ('B','r','a','i'), /*3.0*/ + HB_SCRIPT_CANADIAN_SYLLABICS = HB_TAG ('C','a','n','s'), /*3.0*/ + HB_SCRIPT_CHEROKEE = HB_TAG ('C','h','e','r'), /*3.0*/ + HB_SCRIPT_ETHIOPIC = HB_TAG ('E','t','h','i'), /*3.0*/ + HB_SCRIPT_KHMER = HB_TAG ('K','h','m','r'), /*3.0*/ + HB_SCRIPT_MONGOLIAN = HB_TAG ('M','o','n','g'), /*3.0*/ + HB_SCRIPT_MYANMAR = HB_TAG ('M','y','m','r'), /*3.0*/ + HB_SCRIPT_OGHAM = HB_TAG ('O','g','a','m'), /*3.0*/ + HB_SCRIPT_RUNIC = HB_TAG ('R','u','n','r'), /*3.0*/ + HB_SCRIPT_SINHALA = HB_TAG ('S','i','n','h'), /*3.0*/ + HB_SCRIPT_SYRIAC = HB_TAG ('S','y','r','c'), /*3.0*/ + HB_SCRIPT_THAANA = HB_TAG ('T','h','a','a'), /*3.0*/ + HB_SCRIPT_YI = HB_TAG ('Y','i','i','i'), /*3.0*/ + + HB_SCRIPT_DESERET = HB_TAG ('D','s','r','t'), /*3.1*/ + HB_SCRIPT_GOTHIC = HB_TAG ('G','o','t','h'), /*3.1*/ + HB_SCRIPT_OLD_ITALIC = HB_TAG ('I','t','a','l'), /*3.1*/ + + HB_SCRIPT_BUHID = HB_TAG ('B','u','h','d'), /*3.2*/ + HB_SCRIPT_HANUNOO = HB_TAG ('H','a','n','o'), /*3.2*/ + HB_SCRIPT_TAGALOG = HB_TAG ('T','g','l','g'), /*3.2*/ + HB_SCRIPT_TAGBANWA = HB_TAG ('T','a','g','b'), /*3.2*/ + + HB_SCRIPT_CYPRIOT = HB_TAG ('C','p','r','t'), /*4.0*/ + HB_SCRIPT_LIMBU = HB_TAG ('L','i','m','b'), /*4.0*/ + HB_SCRIPT_LINEAR_B = HB_TAG ('L','i','n','b'), /*4.0*/ + HB_SCRIPT_OSMANYA = HB_TAG ('O','s','m','a'), /*4.0*/ + HB_SCRIPT_SHAVIAN = HB_TAG ('S','h','a','w'), /*4.0*/ + HB_SCRIPT_TAI_LE = HB_TAG ('T','a','l','e'), /*4.0*/ + HB_SCRIPT_UGARITIC = HB_TAG ('U','g','a','r'), /*4.0*/ + + HB_SCRIPT_BUGINESE = HB_TAG ('B','u','g','i'), /*4.1*/ + HB_SCRIPT_COPTIC = HB_TAG ('C','o','p','t'), /*4.1*/ + HB_SCRIPT_GLAGOLITIC = HB_TAG ('G','l','a','g'), /*4.1*/ + HB_SCRIPT_KHAROSHTHI = HB_TAG ('K','h','a','r'), /*4.1*/ + HB_SCRIPT_NEW_TAI_LUE = HB_TAG ('T','a','l','u'), /*4.1*/ + HB_SCRIPT_OLD_PERSIAN = HB_TAG ('X','p','e','o'), /*4.1*/ + HB_SCRIPT_SYLOTI_NAGRI = HB_TAG ('S','y','l','o'), /*4.1*/ + HB_SCRIPT_TIFINAGH = HB_TAG ('T','f','n','g'), /*4.1*/ + + HB_SCRIPT_BALINESE = HB_TAG ('B','a','l','i'), /*5.0*/ + HB_SCRIPT_CUNEIFORM = HB_TAG ('X','s','u','x'), /*5.0*/ + HB_SCRIPT_NKO = HB_TAG ('N','k','o','o'), /*5.0*/ + HB_SCRIPT_PHAGS_PA = HB_TAG ('P','h','a','g'), /*5.0*/ + HB_SCRIPT_PHOENICIAN = HB_TAG ('P','h','n','x'), /*5.0*/ + + HB_SCRIPT_CARIAN = HB_TAG ('C','a','r','i'), /*5.1*/ + HB_SCRIPT_CHAM = HB_TAG ('C','h','a','m'), /*5.1*/ + HB_SCRIPT_KAYAH_LI = HB_TAG ('K','a','l','i'), /*5.1*/ + HB_SCRIPT_LEPCHA = HB_TAG ('L','e','p','c'), /*5.1*/ + HB_SCRIPT_LYCIAN = HB_TAG ('L','y','c','i'), /*5.1*/ + HB_SCRIPT_LYDIAN = HB_TAG ('L','y','d','i'), /*5.1*/ + HB_SCRIPT_OL_CHIKI = HB_TAG ('O','l','c','k'), /*5.1*/ + HB_SCRIPT_REJANG = HB_TAG ('R','j','n','g'), /*5.1*/ + HB_SCRIPT_SAURASHTRA = HB_TAG ('S','a','u','r'), /*5.1*/ + HB_SCRIPT_SUNDANESE = HB_TAG ('S','u','n','d'), /*5.1*/ + HB_SCRIPT_VAI = HB_TAG ('V','a','i','i'), /*5.1*/ + + HB_SCRIPT_AVESTAN = HB_TAG ('A','v','s','t'), /*5.2*/ + HB_SCRIPT_BAMUM = HB_TAG ('B','a','m','u'), /*5.2*/ + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS = HB_TAG ('E','g','y','p'), /*5.2*/ + HB_SCRIPT_IMPERIAL_ARAMAIC = HB_TAG ('A','r','m','i'), /*5.2*/ + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI = HB_TAG ('P','h','l','i'), /*5.2*/ + HB_SCRIPT_INSCRIPTIONAL_PARTHIAN = HB_TAG ('P','r','t','i'), /*5.2*/ + HB_SCRIPT_JAVANESE = HB_TAG ('J','a','v','a'), /*5.2*/ + HB_SCRIPT_KAITHI = HB_TAG ('K','t','h','i'), /*5.2*/ + HB_SCRIPT_LISU = HB_TAG ('L','i','s','u'), /*5.2*/ + HB_SCRIPT_MEETEI_MAYEK = HB_TAG ('M','t','e','i'), /*5.2*/ + HB_SCRIPT_OLD_SOUTH_ARABIAN = HB_TAG ('S','a','r','b'), /*5.2*/ + HB_SCRIPT_OLD_TURKIC = HB_TAG ('O','r','k','h'), /*5.2*/ + HB_SCRIPT_SAMARITAN = HB_TAG ('S','a','m','r'), /*5.2*/ + HB_SCRIPT_TAI_THAM = HB_TAG ('L','a','n','a'), /*5.2*/ + HB_SCRIPT_TAI_VIET = HB_TAG ('T','a','v','t'), /*5.2*/ + + HB_SCRIPT_BATAK = HB_TAG ('B','a','t','k'), /*6.0*/ + HB_SCRIPT_BRAHMI = HB_TAG ('B','r','a','h'), /*6.0*/ + HB_SCRIPT_MANDAIC = HB_TAG ('M','a','n','d'), /*6.0*/ + + HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/ + HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/ + HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/ + HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/ + HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/ + HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/ + HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), /*6.1*/ /* * Since: 0.9.30 */ - /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), - /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), - /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), - /*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), - /*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), - /*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), - /*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), - /*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), - /*7.0*/ HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), - /*7.0*/ HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), - /*7.0*/ HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), - /*7.0*/ HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), - /*7.0*/ HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), - /*7.0*/ HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), - /*7.0*/ HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), - /*7.0*/ HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), - /*7.0*/ HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), - /*7.0*/ HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), - /*7.0*/ HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), - /*7.0*/ HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), - /*7.0*/ HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), - /*7.0*/ HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), - /*7.0*/ HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), - - /*8.0*/ HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), - /*8.0*/ HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), - /*8.0*/ HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), - /*8.0*/ HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), - /*8.0*/ HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), - /*8.0*/ HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), + HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/ + HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/ + HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/ + HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/ + HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/ + HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/ + HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/ + HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'), /*7.0*/ + HB_SCRIPT_MAHAJANI = HB_TAG ('M','a','h','j'), /*7.0*/ + HB_SCRIPT_MANICHAEAN = HB_TAG ('M','a','n','i'), /*7.0*/ + HB_SCRIPT_MENDE_KIKAKUI = HB_TAG ('M','e','n','d'), /*7.0*/ + HB_SCRIPT_MODI = HB_TAG ('M','o','d','i'), /*7.0*/ + HB_SCRIPT_MRO = HB_TAG ('M','r','o','o'), /*7.0*/ + HB_SCRIPT_NABATAEAN = HB_TAG ('N','b','a','t'), /*7.0*/ + HB_SCRIPT_OLD_NORTH_ARABIAN = HB_TAG ('N','a','r','b'), /*7.0*/ + HB_SCRIPT_OLD_PERMIC = HB_TAG ('P','e','r','m'), /*7.0*/ + HB_SCRIPT_PAHAWH_HMONG = HB_TAG ('H','m','n','g'), /*7.0*/ + HB_SCRIPT_PALMYRENE = HB_TAG ('P','a','l','m'), /*7.0*/ + HB_SCRIPT_PAU_CIN_HAU = HB_TAG ('P','a','u','c'), /*7.0*/ + HB_SCRIPT_PSALTER_PAHLAVI = HB_TAG ('P','h','l','p'), /*7.0*/ + HB_SCRIPT_SIDDHAM = HB_TAG ('S','i','d','d'), /*7.0*/ + HB_SCRIPT_TIRHUTA = HB_TAG ('T','i','r','h'), /*7.0*/ + HB_SCRIPT_WARANG_CITI = HB_TAG ('W','a','r','a'), /*7.0*/ + + HB_SCRIPT_AHOM = HB_TAG ('A','h','o','m'), /*8.0*/ + HB_SCRIPT_ANATOLIAN_HIEROGLYPHS = HB_TAG ('H','l','u','w'), /*8.0*/ + HB_SCRIPT_HATRAN = HB_TAG ('H','a','t','r'), /*8.0*/ + HB_SCRIPT_MULTANI = HB_TAG ('M','u','l','t'), /*8.0*/ + HB_SCRIPT_OLD_HUNGARIAN = HB_TAG ('H','u','n','g'), /*8.0*/ + HB_SCRIPT_SIGNWRITING = HB_TAG ('S','g','n','w'), /*8.0*/ /* * Since 1.3.0 */ - /*9.0*/ HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), - /*9.0*/ HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), - /*9.0*/ HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), - /*9.0*/ HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), - /*9.0*/ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), - /*9.0*/ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), + HB_SCRIPT_ADLAM = HB_TAG ('A','d','l','m'), /*9.0*/ + HB_SCRIPT_BHAIKSUKI = HB_TAG ('B','h','k','s'), /*9.0*/ + HB_SCRIPT_MARCHEN = HB_TAG ('M','a','r','c'), /*9.0*/ + HB_SCRIPT_OSAGE = HB_TAG ('O','s','g','e'), /*9.0*/ + HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'), /*9.0*/ + HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'), /*9.0*/ /* * Since 1.6.0 */ - /*10.0*/HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), - /*10.0*/HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), - /*10.0*/HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), - /*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), + HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'), /*10.0*/ + HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'), /*10.0*/ + HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'), /*10.0*/ + HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'), /*10.0*/ /* * Since 1.8.0 */ - /*11.0*/HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), - /*11.0*/HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), - /*11.0*/HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), - /*11.0*/HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), - /*11.0*/HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), - /*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), - /*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), + HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'), /*11.0*/ + HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'), /*11.0*/ + HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'), /*11.0*/ + HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'), /*11.0*/ + HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'), /*11.0*/ + HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/ + HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), /*11.0*/ /* * Since 2.4.0 */ - /*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), - /*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), - /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), - /*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), + HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), /*12.0*/ + HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), /*12.0*/ + HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), /*12.0*/ + HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), /*12.0*/ + + /* + * Since 2.6.7 + */ + HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), /*13.0*/ + HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), /*13.0*/ + HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/ + HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/ /* No script set. */ - HB_SCRIPT_INVALID = HB_TAG_NONE, + HB_SCRIPT_INVALID = HB_TAG_NONE, + + /*< private >*/ /* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t * without risking undefined behavior. We have two, for historical reasons. @@ -400,29 +720,64 @@ hb_script_get_horizontal_direction (hb_script_t script); /* User data */ +/** + * hb_user_data_key_t: + * + * Data structure for holding user-data keys. + * + **/ typedef struct hb_user_data_key_t { /*< private >*/ char unused; } hb_user_data_key_t; +/** + * hb_destroy_func_t: + * @user_data: the data to be destroyed + * + * A virtual method for destroy user-data callbacks. + * + */ typedef void (*hb_destroy_func_t) (void *user_data); /* Font features and variations. */ /** - * HB_FEATURE_GLOBAL_START + * HB_FEATURE_GLOBAL_START: + * + * Special setting for #hb_feature_t.start to apply the feature from the start + * of the buffer. * * Since: 2.0.0 */ #define HB_FEATURE_GLOBAL_START 0 + /** - * HB_FEATURE_GLOBAL_END + * HB_FEATURE_GLOBAL_END: + * + * Special setting for #hb_feature_t.end to apply the feature from to the end + * of the buffer. * * Since: 2.0.0 */ #define HB_FEATURE_GLOBAL_END ((unsigned int) -1) +/** + * hb_feature_t: + * @tag: The #hb_tag_t tag of the feature + * @value: The value of the feature. 0 disables the feature, non-zero (usually + * 1) enables the feature. For features implemented as lookup type 3 (like + * 'salt') the @value is a one based index into the alternates. + * @start: the cluster to start applying this feature setting (inclusive). + * @end: the cluster to end applying this feature setting (exclusive). + * + * The #hb_feature_t is the structure that holds information about requested + * feature application. The feature will be applied with the given value to all + * glyphs which are in clusters between @start (inclusive) and @end (exclusive). + * Setting start to #HB_FEATURE_GLOBAL_START and end to #HB_FEATURE_GLOBAL_END + * specifies that the feature always applies to the entire buffer. + */ typedef struct hb_feature_t { hb_tag_t tag; uint32_t value; @@ -440,7 +795,13 @@ hb_feature_to_string (hb_feature_t *feature, /** * hb_variation_t: + * @tag: The #hb_tag_t tag of the variation-axis name + * @value: The value of the variation axis * + * Data type for holding variation data. Registered OpenType + * variation-axis tags are listed in + * [OpenType Axis Tag Registry](https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg). + * * Since: 1.4.2 */ typedef struct hb_variation_t { @@ -459,12 +820,24 @@ hb_variation_to_string (hb_variation_t *variation, /** * hb_color_t: * - * Data type for holding color values. + * Data type for holding color values. Colors are eight bits per + * channel RGB plus alpha transparency. * * Since: 2.1.0 */ typedef uint32_t hb_color_t; +/** + * HB_COLOR: + * @b: blue channel value + * @g: green channel value + * @r: red channel value + * @a: alpha channel value + * + * Constructs an #hb_color_t from four integers. + * + * Since: 2.1.0 + */ #define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a))) HB_EXTERN uint8_t diff --git a/src/hb-config.hh b/src/hb-config.hh index b6db206a34c25ff52227073959f3069bc3271d2e..111058c8e6ed52af940a6e5c0a2f6211c6f7a3b9 100644 --- a/src/hb-config.hh +++ b/src/hb-config.hh @@ -58,6 +58,8 @@ #define HB_NO_BITMAP #define HB_NO_CFF #define HB_NO_COLOR +#define HB_NO_DRAW +#define HB_NO_ERRNO #define HB_NO_FACE_COLLECT_UNICODES #define HB_NO_GETENV #define HB_NO_HINTING @@ -74,7 +76,7 @@ #define HB_NO_SETLOCALE #define HB_NO_OT_FONT_GLYPH_NAMES #define HB_NO_OT_SHAPE_FRACTIONS -#define HB_NO_STAT +#define HB_NO_STYLE #define HB_NO_SUBSET_LAYOUT #define HB_NO_VAR #endif @@ -84,6 +86,9 @@ #define HB_NO_LEGACY #endif +#ifdef HAVE_CONFIG_OVERRIDE_H +#include "config-override.h" +#endif /* Closure of options. */ @@ -153,9 +158,5 @@ #endif #endif -#ifdef HAVE_CONFIG_OVERRIDE_H -#include "config-override.h" -#endif - #endif /* HB_CONFIG_HH */ diff --git a/src/hb-coretext.cc b/src/hb-coretext.cc index 31aa00a11107edbe1a2f5ae5c5943d0fc28d6bda..461bd20e6571cc14979321adcd999e4db7fa73c7 100644 --- a/src/hb-coretext.cc +++ b/src/hb-coretext.cc @@ -34,7 +34,6 @@ #include "hb-coretext.h" #include "hb-aat-layout.hh" -#include /** @@ -111,7 +110,7 @@ static void release_data (void *info, const void *data, size_t size) { assert (hb_blob_get_length ((hb_blob_t *) info) == size && - hb_blob_get_data ((hb_blob_t *) info, nullptr) == data); + hb_blob_get_data ((hb_blob_t *) info, nullptr) == data); hb_blob_destroy ((hb_blob_t *) info); } @@ -190,7 +189,10 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) * reconfiguring the cascade list causes CoreText crashes. For details, see * crbug.com/549610 */ // 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) { +#pragma GCC diagnostic pop CFStringRef fontName = CTFontCopyPostScriptName (ct_font); bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo; CFRelease (fontName); @@ -233,21 +235,21 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) atsFont = CTFontGetPlatformFont (new_ct_font, NULL); status = ATSFontGetFileReference (atsFont, &fsref); if (status == noErr) - new_url = CFURLCreateFromFSRef (NULL, &fsref); + new_url = CFURLCreateFromFSRef (NULL, &fsref); #else new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute); #endif // Keep reconfigured font if URL cannot be retrieved (seems to be the case // on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606 if (!original_url || !new_url || CFEqual (original_url, new_url)) { - CFRelease (ct_font); - ct_font = new_ct_font; + CFRelease (ct_font); + ct_font = new_ct_font; } else { - CFRelease (new_ct_font); - DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed."); + CFRelease (new_ct_font); + DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed."); } if (new_url) - CFRelease (new_url); + CFRelease (new_url); } else DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed"); @@ -278,13 +280,32 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data) CFRelease ((CGFontRef) data); } +/** + * hb_coretext_face_create: + * @cg_font: The CGFontRef to work upon + * + * Creates an #hb_face_t face object from the specified + * CGFontRef. + * + * Return value: the new #hb_face_t face object + * + * Since: 0.9.10 + */ hb_face_t * hb_coretext_face_create (CGFontRef cg_font) { return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release); } -/* +/** + * hb_coretext_face_get_cg_font: + * @face: The #hb_face_t to work upon + * + * Fetches the CGFontRef associated with an #hb_face_t + * face object + * + * Return value: the CGFontRef found + * * Since: 0.9.10 */ CGFontRef @@ -302,7 +323,7 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) if (unlikely (!face_data)) return nullptr; CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; - CGFloat font_size = font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem; + CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem); CTFontRef ct_font = create_ct_font (cg_font, font_size); if (unlikely (!ct_font)) @@ -327,7 +348,7 @@ retry: const hb_coretext_font_data_t *data = font->data.coretext; if (unlikely (!data)) return nullptr; - if (fabs (CTFontGetSize ((CTFontRef) data) - font->ptem) > .5) + if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > (CGFloat) .5) { /* XXX-MT-bug * Note that evaluating condition above can be dangerous if another thread @@ -351,10 +372,17 @@ retry: return font->data.coretext; } - -/* +/** + * hb_coretext_font_create: + * @ct_font: The CTFontRef to work upon + * + * Creates an #hb_font_t font object from the specified + * CTFontRef. + * + * Return value: the new #hb_font_t font object + * * Since: 1.7.2 - */ + **/ hb_font_t * hb_coretext_font_create (CTFontRef ct_font) { @@ -375,6 +403,17 @@ hb_coretext_font_create (CTFontRef ct_font) return font; } +/** + * hb_coretext_font_get_ct_font: + * @font: #hb_font_t to work upon + * + * Fetches the CTFontRef associated with the specified + * #hb_font_t font object. + * + * Return value: the CTFontRef found + * + * Since: 0.9.10 + */ CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font) { @@ -433,9 +472,9 @@ struct range_record_t { hb_bool_t _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features) + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) { hb_face_t *face = font->face; CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; @@ -475,13 +514,19 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_vector_t feature_events; for (unsigned int i = 0; i < num_features; i++) { + active_feature_t feature; + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag); if (!mapping) - continue; + continue; - active_feature_t feature; feature.rec.feature = mapping->aatFeatureType; feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; +#else + feature.rec.feature = features[i].tag; + feature.rec.setting = features[i].value; +#endif feature.order = i; feature_event_t *event; @@ -519,7 +564,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, if (event->index != last_index) { - /* Save a snapshot of active features and the range. */ + /* Save a snapshot of active features and the range. */ range_record_t *range = range_records.push (); if (active_features.length) @@ -530,6 +575,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, /* active_features.qsort (); */ for (unsigned int j = 0; j < active_features.length; j++) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 CFStringRef keys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey @@ -538,6 +584,17 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) }; +#else + char tag[5] = {HB_UNTAG (active_features[j].rec.feature)}; + CFTypeRef keys[] = { + kCTFontOpenTypeFeatureTag, + kCTFontOpenTypeFeatureValue + }; + CFTypeRef values[] = { + CFStringCreateWithCString (kCFAllocatorDefault, tag, kCFStringEncodingASCII), + CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) + }; +#endif static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), ""); CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, (const void **) keys, @@ -580,9 +637,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, if (event->start) { - active_features.push (event->feature); + active_features.push (event->feature); } else { - active_feature_t *feature = active_features.find (&event->feature); + active_feature_t *feature = active_features.find (&event->feature); if (feature) active_features.remove (feature - active_features.arrayZ); } @@ -605,7 +662,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, scratch_size -= _consumed; \ } while (0) - ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/); + ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, ((void)nullptr) /*nothing*/); unsigned int chars_len = 0; for (unsigned int i = 0; i < buffer->len; i++) { hb_codepoint_t c = buffer->info[i].codepoint; @@ -619,7 +676,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } } - ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/); + ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, ((void)nullptr) /*nothing*/); chars_len = 0; for (unsigned int i = 0; i < buffer->len; i++) { @@ -700,15 +757,15 @@ resize_and_retry: #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090 # define kCTLanguageAttributeName CFSTR ("NSLanguage") #endif - CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault, + CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault, hb_language_to_string (buffer->props.language), kCFStringEncodingUTF8, kCFAllocatorNull); if (unlikely (!lang)) - { + { CFRelease (attr_string); FAIL ("CFStringCreateWithCStringNoCopy failed"); - } + } CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len), kCTLanguageAttributeName, lang); CFRelease (lang); @@ -757,7 +814,7 @@ resize_and_retry: feature.start < chars_len && feature.start < feature.end) { CFRange feature_range = CFRangeMake (feature.start, - hb_min (feature.end, chars_len) - feature.start); + hb_min (feature.end, chars_len) - feature.start); if (feature.value) CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName); else @@ -781,8 +838,8 @@ resize_and_retry: CFRelease (level_number); if (unlikely (!options)) { - CFRelease (attr_string); - FAIL ("CFDictionaryCreate failed"); + CFRelease (attr_string); + FAIL ("CFDictionaryCreate failed"); } CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options); @@ -803,7 +860,7 @@ resize_and_retry: buffer->len = 0; uint32_t status_and = ~0, status_or = 0; - double advances_so_far = 0; + CGFloat advances_so_far = 0; /* For right-to-left runs, CoreText returns the glyphs positioned such that * any trailing whitespace is to the left of (0,0). Adjust coordinate system * to fix for that. Test with any RTL string with trailing spaces. @@ -825,10 +882,10 @@ resize_and_retry: status_or |= run_status; status_and &= run_status; DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status); - double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr); + CGFloat run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr); if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction)) run_advance = -run_advance; - DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance); + DEBUG_MSG (CORETEXT, run, "Run advance: %g", (double) run_advance); /* CoreText does automatic font fallback (AKA "cascading") for characters * not supported by the requested font, and provides no way to turn it off, @@ -893,7 +950,7 @@ resize_and_retry: if (!matched) { CFRange range = CTRunGetStringRange (run); - DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", + DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld", range.location, range.location + range.length); if (!buffer->ensure_inplace (buffer->len + range.length)) goto resize_and_retry; @@ -921,7 +978,7 @@ resize_and_retry: continue; } if (buffer->unicode->is_default_ignorable (ch)) - continue; + continue; info->codepoint = notdef; info->cluster = log_clusters[j]; @@ -966,7 +1023,7 @@ resize_and_retry: scratch = scratch_saved { /* Setup glyphs */ - SCRATCH_SAVE(); + SCRATCH_SAVE(); const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr; if (!glyphs) { ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry); @@ -989,12 +1046,12 @@ resize_and_retry: SCRATCH_RESTORE(); } { - /* Setup positions. + /* Setup positions. * Note that CoreText does not return advances for glyphs. As such, * for all but last glyph, we use the delta position to next glyph as * advance (in the advance direction only), and for last glyph we set * whatever is needed to make the whole run's advance add up. */ - SCRATCH_SAVE(); + SCRATCH_SAVE(); const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr; if (!positions) { ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry); @@ -1007,7 +1064,7 @@ resize_and_retry: hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult; for (unsigned int j = 0; j < num_glyphs; j++) { - double advance; + CGFloat advance; if (likely (j + 1 < num_glyphs)) advance = positions[j + 1].x - positions[j].x; else /* last glyph */ @@ -1023,7 +1080,7 @@ resize_and_retry: hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult; for (unsigned int j = 0; j < num_glyphs; j++) { - double advance; + CGFloat advance; if (likely (j + 1 < num_glyphs)) advance = positions[j + 1].y - positions[j].y; else /* last glyph */ diff --git a/src/hb-coretext.h b/src/hb-coretext.h index 4b0a6f01b6f67c0061e43d1febb68e62ae066b55..e53dbaf2c7f5fdfd7fe0c72d1867422a8e6f53dc 100644 --- a/src/hb-coretext.h +++ b/src/hb-coretext.h @@ -40,8 +40,40 @@ HB_BEGIN_DECLS +/** + * HB_CORETEXT_TAG_MORT: + * + * The #hb_tag_t tag for the `mort` (glyph metamorphosis) table, + * which holds AAT features. + * + * For more information, see + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html + * + **/ #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t') + +/** + * HB_CORETEXT_TAG_MORX: + * + * The #hb_tag_t tag for the `morx` (extended glyph metamorphosis) + * table, which holds AAT features. + * + * For more information, see + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html + * + **/ #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x') + +/** + * HB_CORETEXT_TAG_KERX: + * + * The #hb_tag_t tag for the `kerx` (extended kerning) table, which + * holds AAT kerning information. + * + * For more information, see + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html + * + **/ #define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x') diff --git a/src/hb-debug.hh b/src/hb-debug.hh index e6d06e3102b22d34b2018388673fe3a7262fc557..a92614d01d4d5b0acefefd7a0b3ec949e31cdc7c 100644 --- a/src/hb-debug.hh +++ b/src/hb-debug.hh @@ -46,7 +46,6 @@ struct hb_options_t bool unused : 1; /* In-case sign bit is here. */ bool initialized : 1; bool uniscribe_bug_compatible : 1; - bool aat : 1; }; union hb_options_union_t { @@ -230,7 +229,7 @@ _hb_debug_msg<0> (const char *what HB_UNUSED, ...) {} #define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg (#WHAT, (OBJ), nullptr, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__) -#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg (#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__) +#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg (#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__) #define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__) @@ -296,22 +295,23 @@ struct hb_auto_trace_t if (plevel) --*plevel; } - ret_t ret (ret_t v, - const char *func = "", - unsigned int line = 0) + template + T ret (T&& v, + const char *func = "", + unsigned int line = 0) { if (unlikely (returned)) { fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n"); - return v; + return hb_forward (v); } _hb_debug_msg (what, obj, func, true, plevel ? *plevel : 1, -1, "return %s (line %d)", - hb_printer_t().print (v), line); + hb_printer_t().print (v), line); if (plevel) --*plevel; plevel = nullptr; returned = true; - return v; + return hb_forward (v); } private: @@ -373,10 +373,6 @@ struct hb_no_trace_t { #define HB_DEBUG_FT (HB_DEBUG+0) #endif -#ifndef HB_DEBUG_GET_COVERAGE -#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0) -#endif - #ifndef HB_DEBUG_OBJECT #define HB_DEBUG_OBJECT (HB_DEBUG+0) #endif @@ -413,7 +409,7 @@ struct hb_no_trace_t { #define TRACE_SANITIZE(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - " "); + " ") #else #define TRACE_SANITIZE(this) hb_no_trace_t trace #endif @@ -425,7 +421,7 @@ struct hb_no_trace_t { #define TRACE_SERIALIZE(this) \ hb_auto_trace_t trace \ (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ - " "); + " ") #else #define TRACE_SERIALIZE(this) hb_no_trace_t trace #endif @@ -437,11 +433,15 @@ struct hb_no_trace_t { #define TRACE_SUBSET(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - " "); + " ") #else #define TRACE_SUBSET(this) hb_no_trace_t trace #endif +#ifndef HB_DEBUG_SUBSET_REPACK +#define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0) +#endif + #ifndef HB_DEBUG_DISPATCH #define HB_DEBUG_DISPATCH ( \ HB_DEBUG_APPLY + \ @@ -454,7 +454,7 @@ struct hb_no_trace_t { #define TRACE_DISPATCH(this, format) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "format %d", (int) format); + "format %d", (int) format) #else #define TRACE_DISPATCH(this, format) hb_no_trace_t trace #endif diff --git a/src/hb-deprecated.h b/src/hb-deprecated.h index 43f89a4c4e00cb72e7f491d7fb9f0c458710d98c..5f19125789dc65361cd26f5a8b4d5076c610fd46 100644 --- a/src/hb-deprecated.h +++ b/src/hb-deprecated.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -53,11 +53,50 @@ HB_BEGIN_DECLS #ifndef HB_DISABLE_DEPRECATED +/** + * HB_SCRIPT_CANADIAN_ABORIGINAL: + * + * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead: + * + * Deprecated: 0.9.20 + */ #define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS +/** + * HB_BUFFER_FLAGS_DEFAULT: + * + * Use #HB_BUFFER_FLAG_DEFAULT instead. + * + * Deprecated: 0.9.20 + */ #define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT +/** + * HB_BUFFER_SERIALIZE_FLAGS_DEFAULT: + * + * Use #HB_BUFFER_SERIALIZE_FLAG_DEFAULT instead. + * + * Deprecated: 0.9.20 + */ #define HB_BUFFER_SERIALIZE_FLAGS_DEFAULT HB_BUFFER_SERIALIZE_FLAG_DEFAULT +/** + * hb_font_get_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @unicode: The Unicode code point to query + * @variation_selector: The variation-selector code point to query + * @glyph: (out): The glyph ID retrieved + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the glyph ID for a specified Unicode code point + * font, with an optional variation selector. + * + * Return value: %true if data found, %false otherwise + * Deprecated: 1.2.3 + * + **/ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph, @@ -73,6 +112,11 @@ hb_set_invert (hb_set_t *set); /** * hb_unicode_eastasian_width_func_t: + * @ufuncs: A Unicode-functions structure + * @unicode: The code point to query + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. * * Deprecated: 2.0.0 */ @@ -82,12 +126,12 @@ typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t /** * hb_unicode_funcs_set_eastasian_width_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: a Unicode-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_eastasian_width_func_t. * * Since: 0.9.2 * Deprecated: 2.0.0 @@ -99,6 +143,10 @@ hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_eastasian_width: + * @ufuncs: a Unicode-function structure + * @unicode: The code point to query + * + * Don't use. Not used by HarfBuzz. * * Since: 0.9.2 * Deprecated: 2.0.0 @@ -112,7 +160,7 @@ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, * hb_unicode_decompose_compatibility_func_t: * @ufuncs: a Unicode function structure * @u: codepoint to decompose - * @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into + * @decomposed: address of codepoint array (of length #HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into * @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func() * * Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed. @@ -120,7 +168,7 @@ hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs, * * If @u has no compatibility decomposition, zero should be returned. * - * The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any + * The Unicode standard guarantees that a buffer of length #HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any * compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations * of this function type must ensure that they do not write past the provided array. * @@ -144,10 +192,12 @@ typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_ /** * hb_unicode_funcs_set_decompose_compatibility_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_unicode_decompose_compatibility_func_t. * * * @@ -165,16 +215,25 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, hb_codepoint_t *decomposed); +/** + * hb_font_get_glyph_v_kerning_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the kerning-adjustment value for a glyph-pair in + * the specified font, for vertical text segments. + * + **/ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t; /** * hb_font_funcs_set_glyph_v_kerning_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_font_get_glyph_v_kerning_func_t. * * Since: 0.9.2 * Deprecated: 2.0.0 diff --git a/src/hb-directwrite.cc b/src/hb-directwrite.cc index a079563af482a05f6a5af958ebbe0f550a85df4c..aebe9e054196e160ec93917c87f6c4cc816186ef 100644 --- a/src/hb-directwrite.cc +++ b/src/hb-directwrite.cc @@ -33,6 +33,15 @@ #include "hb-directwrite.h" +/** + * SECTION:hb-directwrite + * @title: hb-directwrite + * @short_description: DirectWrite integration + * @include: hb-directwrite.h + * + * Functions for using HarfBuzz with DirectWrite fonts. + **/ + /* Declare object creator for dynamic support of DWRITE */ typedef HRESULT (* WINAPI t_DWriteCreateFactory)( DWRITE_FACTORY_TYPE factoryType, @@ -614,7 +623,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, * but we never attempt to shape a word longer than 64K characters * in a single gfxShapedWord, so we cannot exceed that limit. */ - uint32_t textLength = buffer->len; + uint32_t textLength = chars_len; TextAnalysis analysis (textString, textLength, nullptr, readingDirection); TextAnalysis::Run *runHead; @@ -625,7 +634,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, HB_STMT_START { \ DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \ return false; \ - } HB_STMT_END; + } HB_STMT_END if (FAILED (hr)) FAIL ("Analyzer failed to generate results."); @@ -635,7 +644,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan, bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); const wchar_t localeName[20] = {0}; - if (buffer->props.language != nullptr) + if (buffer->props.language) mbstowcs ((wchar_t*) localeName, hb_language_to_string (buffer->props.language), 20); @@ -948,6 +957,8 @@ _hb_directwrite_font_release (void *data) * hb_directwrite_face_create: * @font_face: a DirectWrite IDWriteFontFace object. * + * Constructs a new face object from the specified DirectWrite IDWriteFontFace. + * * Return value: #hb_face_t object corresponding to the given input * * Since: 2.4.0 @@ -965,6 +976,8 @@ hb_directwrite_face_create (IDWriteFontFace *font_face) * hb_directwrite_face_get_font_face: * @face: a #hb_face_t object * +* Gets the DirectWrite IDWriteFontFace associated with @face. +* * Return value: DirectWrite IDWriteFontFace object corresponding to the given input * * Since: 2.5.0 diff --git a/src/hb-dispatch.hh b/src/hb-dispatch.hh index be4a90f4f399f2233f1ff08e7f8f2682943f2788..4b2b65a8de439ebc8626457adc5a88cb370556ef 100644 --- a/src/hb-dispatch.hh +++ b/src/hb-dispatch.hh @@ -35,14 +35,15 @@ * Dispatch */ -template +template struct hb_dispatch_context_t { private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ const Context* thiz () const { return static_cast (this); } - Context* thiz () { return static_cast< Context *> (this); } + Context* thiz () { return static_cast< Context *> (this); } public: + const char *get_name () { return "UNKNOWN"; } static constexpr unsigned max_debug_depth = MaxDebugDepth; typedef Return return_t; template @@ -52,6 +53,7 @@ struct hb_dispatch_context_t { return obj.dispatch (thiz (), hb_forward (ds)...); } static return_t no_dispatch_return_value () { return Context::default_return_value (); } static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; } + unsigned debug_depth = 0; }; diff --git a/src/hb-draw.cc b/src/hb-draw.cc new file mode 100644 index 0000000000000000000000000000000000000000..1a5f9c8c6bd142ca386342bbb39f3f1c32e25340 --- /dev/null +++ b/src/hb-draw.cc @@ -0,0 +1,261 @@ +/* + * Copyright © 2019-2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_DRAW +#ifdef HB_EXPERIMENTAL_API + +#include "hb-draw.hh" +#include "hb-ot.h" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" + +/** + * hb_draw_funcs_set_move_to_func: + * @funcs: draw functions object + * @move_to: move-to callback + * + * Sets move-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, + hb_draw_move_to_func_t move_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->move_to = move_to; +} + +/** + * hb_draw_funcs_set_line_to_func: + * @funcs: draw functions object + * @line_to: line-to callback + * + * Sets line-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, + hb_draw_line_to_func_t line_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->line_to = line_to; +} + +/** + * hb_draw_funcs_set_quadratic_to_func: + * @funcs: draw functions object + * @move_to: quadratic-to callback + * + * Sets quadratic-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, + hb_draw_quadratic_to_func_t quadratic_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->quadratic_to = quadratic_to; + funcs->is_quadratic_to_set = true; +} + +/** + * hb_draw_funcs_set_cubic_to_func: + * @funcs: draw functions + * @cubic_to: cubic-to callback + * + * Sets cubic-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, + hb_draw_cubic_to_func_t cubic_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->cubic_to = cubic_to; +} + +/** + * hb_draw_funcs_set_close_path_func: + * @funcs: draw functions object + * @close_path: close-path callback + * + * Sets close-path callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, + hb_draw_close_path_func_t close_path) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->close_path = close_path; +} + +static void +_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} + +static void +_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} + +static void +_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED, + hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED, + hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED, + hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +_close_path_nil (void *user_data HB_UNUSED) {} + +/** + * hb_draw_funcs_create: + * + * Creates a new draw callbacks object. + * + * Since: EXPERIMENTAL + **/ +hb_draw_funcs_t * +hb_draw_funcs_create () +{ + hb_draw_funcs_t *funcs; + if (unlikely (!(funcs = hb_object_create ()))) + return const_cast (&Null (hb_draw_funcs_t)); + + funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil; + funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil; + funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil; + funcs->is_quadratic_to_set = false; + funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil; + funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil; + return funcs; +} + +/** + * hb_draw_funcs_reference: + * @funcs: draw functions + * + * Add to callbacks object refcount. + * + * Returns: The same object. + * Since: EXPERIMENTAL + **/ +hb_draw_funcs_t * +hb_draw_funcs_reference (hb_draw_funcs_t *funcs) +{ + return hb_object_reference (funcs); +} + +/** + * hb_draw_funcs_destroy: + * @funcs: draw functions + * + * Decreases refcount of callbacks object and deletes the object if it reaches + * to zero. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_destroy (hb_draw_funcs_t *funcs) +{ + if (!hb_object_destroy (funcs)) return; + + free (funcs); +} + +/** + * hb_draw_funcs_make_immutable: + * @funcs: draw functions + * + * Makes funcs object immutable. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs) +{ + if (hb_object_is_immutable (funcs)) + return; + + hb_object_make_immutable (funcs); +} + +/** + * hb_draw_funcs_is_immutable: + * @funcs: draw functions + * + * Checks whether funcs is immutable. + * + * Returns: If is immutable. + * Since: EXPERIMENTAL + **/ +hb_bool_t +hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs) +{ + return hb_object_is_immutable (funcs); +} + +/** + * hb_font_draw_glyph: + * @font: a font object + * @glyph: a glyph id + * @funcs: draw callbacks object + * @user_data: parameter you like be passed to the callbacks when are called + * + * Draw a glyph. + * + * Returns: Whether the font had the glyph and the operation completed successfully. + * Since: EXPERIMENTAL + **/ +hb_bool_t +hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, + const hb_draw_funcs_t *funcs, + void *user_data) +{ + if (unlikely (funcs == &Null (hb_draw_funcs_t) || + glyph >= font->face->get_num_glyphs ())) + return false; + + draw_helper_t draw_helper (funcs, user_data); + if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true; +#ifndef HB_NO_CFF + if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true; + if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true; +#endif + + return false; +} + +#endif +#endif diff --git a/src/hb-draw.h b/src/hb-draw.h new file mode 100644 index 0000000000000000000000000000000000000000..bddc87639954a321dbb9a851091389072dc540bd --- /dev/null +++ b/src/hb-draw.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2019-2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +#error "Include instead." +#endif + +#ifndef HB_DRAW_H +#define HB_DRAW_H + +#include "hb.h" + +HB_BEGIN_DECLS + +#ifdef HB_EXPERIMENTAL_API +typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); +typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); +typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y, + void *user_data); +typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y, + void *user_data); +typedef void (*hb_draw_close_path_func_t) (void *user_data); + +/** + * hb_draw_funcs_t: + * + * Glyph draw callbacks. + * + * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we + * translate _quadratic_to calls to _cubic_to if the callback isn't defined. + * + * Since: EXPERIMENTAL + **/ +typedef struct hb_draw_funcs_t hb_draw_funcs_t; + +HB_EXTERN void +hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, + hb_draw_move_to_func_t move_to); + +HB_EXTERN void +hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, + hb_draw_line_to_func_t line_to); + +HB_EXTERN void +hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, + hb_draw_quadratic_to_func_t quadratic_to); + +HB_EXTERN void +hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, + hb_draw_cubic_to_func_t cubic_to); + +HB_EXTERN void +hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, + hb_draw_close_path_func_t close_path); + +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_create (void); + +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_reference (hb_draw_funcs_t *funcs); + +HB_EXTERN void +hb_draw_funcs_destroy (hb_draw_funcs_t *funcs); + +HB_EXTERN void +hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs); + +HB_EXTERN hb_bool_t +hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs); +#endif + +HB_END_DECLS + +#endif /* HB_DRAW_H */ diff --git a/src/hb-draw.hh b/src/hb-draw.hh new file mode 100644 index 0000000000000000000000000000000000000000..2aa0a5b4db47cb8047e56e25724943810979f21c --- /dev/null +++ b/src/hb-draw.hh @@ -0,0 +1,139 @@ +/* + * Copyright © 2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_DRAW_HH +#define HB_DRAW_HH + +#include "hb.hh" + +#ifdef HB_EXPERIMENTAL_API +struct hb_draw_funcs_t +{ + hb_object_header_t header; + + hb_draw_move_to_func_t move_to; + hb_draw_line_to_func_t line_to; + hb_draw_quadratic_to_func_t quadratic_to; + bool is_quadratic_to_set; + hb_draw_cubic_to_func_t cubic_to; + hb_draw_close_path_func_t close_path; +}; + +struct draw_helper_t +{ + draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_) + { + funcs = funcs_; + user_data = user_data_; + path_open = false; + path_start_x = current_x = path_start_y = current_y = 0; + } + ~draw_helper_t () { end_path (); } + + void move_to (hb_position_t x, hb_position_t y) + { + if (path_open) end_path (); + current_x = path_start_x = x; + current_y = path_start_y = y; + } + + void line_to (hb_position_t x, hb_position_t y) + { + if (equal_to_current (x, y)) return; + if (!path_open) start_path (); + funcs->line_to (x, y, user_data); + current_x = x; + current_y = y; + } + + void + quadratic_to (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y) + { + if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y)) + return; + if (!path_open) start_path (); + if (funcs->is_quadratic_to_set) + funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data); + else + funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f), + roundf ((current_y + 2.f * control_y) / 3.f), + roundf ((to_x + 2.f * control_x) / 3.f), + roundf ((to_y + 2.f * control_y) / 3.f), + to_x, to_y, user_data); + current_x = to_x; + current_y = to_y; + } + + void + cubic_to (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y) + { + if (equal_to_current (control1_x, control1_y) && + equal_to_current (control2_x, control2_y) && + equal_to_current (to_x, to_y)) + return; + if (!path_open) start_path (); + funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data); + current_x = to_x; + current_y = to_y; + } + + void end_path () + { + if (path_open) + { + if ((path_start_x != current_x) || (path_start_y != current_y)) + funcs->line_to (path_start_x, path_start_y, user_data); + funcs->close_path (user_data); + } + path_open = false; + path_start_x = current_x = path_start_y = current_y = 0; + } + + protected: + bool equal_to_current (hb_position_t x, hb_position_t y) + { return current_x == x && current_y == y; } + + void start_path () + { + if (path_open) end_path (); + path_open = true; + funcs->move_to (path_start_x, path_start_y, user_data); + } + + hb_position_t path_start_x; + hb_position_t path_start_y; + + hb_position_t current_x; + hb_position_t current_y; + + bool path_open; + const hb_draw_funcs_t *funcs; + void *user_data; +}; +#endif + +#endif /* HB_DRAW_HH */ diff --git a/src/hb-face.cc b/src/hb-face.cc index 1098adb33eb7ecb59f73e6d0c5e609068a17404b..61bd4af7b1de72861f4b6ba583e7ba2666844f5e 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -41,8 +41,10 @@ * @short_description: Font face objects * @include: hb.h * - * Font face is objects represent a single face in a font family. - * More exactly, a font face represents a single face in a binary font file. + * A font face is an object that represents a single face from within a + * font family. + * + * More precisely, a font face represents a single face in a binary font file. * Font faces are typically built from a binary blob and a face index. * Font faces are used to create fonts. **/ @@ -52,7 +54,7 @@ * hb_face_count: * @blob: a blob. * - * Get number of faces in a blob. + * Fetches the number of faces in a blob. * * Return value: Number of faces in @blob * @@ -87,8 +89,8 @@ DEFINE_NULL_INSTANCE (hb_face_t) = nullptr, /* destroy */ 0, /* index */ - HB_ATOMIC_INT_INIT (1000), /* upem */ - HB_ATOMIC_INT_INIT (0), /* num_glyphs */ + 1000, /* upem */ + 0, /* num_glyphs */ /* Zero for the rest is fine. */ }; @@ -96,13 +98,19 @@ DEFINE_NULL_INSTANCE (hb_face_t) = /** * hb_face_create_for_tables: - * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): Table-referencing function + * @user_data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore * + * Variant of hb_face_create(), built for those cases where it is more + * convenient to provide data for individual tables instead of the whole font + * data. With the caveat that hb_face_get_table_tags() does not currently work + * with faces created this way. + * + * Creates a new face object from the specified @user_data and @reference_table_func, + * with the @destroy callback. * - * Return value: (transfer full) + * Return value: (transfer full): The new face object * * Since: 0.9.2 **/ @@ -182,12 +190,15 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void /** * hb_face_create: (Xconstructor) - * @blob: - * @index: + * @blob: #hb_blob_t to work upon + * @index: The index of the face within @blob * + * Constructs a new face object from the specified blob and + * a face index into that blob. This is used for blobs of + * file formats such as Dfont and TTC that can contain more + * than one face. * - * - * Return value: (transfer full): + * Return value: (transfer full): The new face object * * Since: 0.9.2 **/ @@ -200,10 +211,15 @@ hb_face_create (hb_blob_t *blob, if (unlikely (!blob)) blob = hb_blob_get_empty (); - hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob (hb_blob_reference (blob)), index); + blob = hb_sanitize_context_t ().sanitize_blob (hb_blob_reference (blob)); + + hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index); if (unlikely (!closure)) + { + hb_blob_destroy (blob); return hb_face_get_empty (); + } face = hb_face_create_for_tables (_hb_face_for_data_reference_table, closure, @@ -217,26 +233,26 @@ hb_face_create (hb_blob_t *blob, /** * hb_face_get_empty: * + * Fetches the singleton empty face object. * - * - * Return value: (transfer full) + * Return value: (transfer full): The empty face object * * Since: 0.9.2 **/ hb_face_t * hb_face_get_empty () { - return const_cast (&Null(hb_face_t)); + return const_cast (&Null (hb_face_t)); } /** * hb_face_reference: (skip) - * @face: a face. + * @face: A face object * + * Increases the reference count on a face object. * - * - * Return value: + * Return value: The @face object * * Since: 0.9.2 **/ @@ -248,9 +264,11 @@ hb_face_reference (hb_face_t *face) /** * hb_face_destroy: (skip) - * @face: a face. - * - * + * @face: A face object + * + * Decreases the reference count on a face object. When the + * reference count reaches zero, the face is destroyed, + * freeing all memory. * * Since: 0.9.2 **/ @@ -278,15 +296,15 @@ hb_face_destroy (hb_face_t *face) /** * hb_face_set_user_data: (skip) - * @face: a face. - * @key: - * @data: - * @destroy: - * @replace: + * @face: A face object + * @key: The user-data key to set + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * + * Attaches a user-data key/data pair to the given face object. * - * - * Return value: + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ @@ -302,12 +320,13 @@ hb_face_set_user_data (hb_face_t *face, /** * hb_face_get_user_data: (skip) - * @face: a face. - * @key: - * + * @face: A face object + * @key: The user-data key to query * + * Fetches the user data associated with the specified key, + * attached to the specified face object. * - * Return value: (transfer none): + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.2 **/ @@ -320,9 +339,9 @@ hb_face_get_user_data (const hb_face_t *face, /** * hb_face_make_immutable: - * @face: a face. - * + * @face: A face object * + * Makes the given face object immutable. * * Since: 0.9.2 **/ @@ -337,11 +356,11 @@ hb_face_make_immutable (hb_face_t *face) /** * hb_face_is_immutable: - * @face: a face. + * @face: A face object * + * Tests whether the given face object is immutable. * - * - * Return value: + * Return value: %true is @face is immutable, %false otherwise * * Since: 0.9.2 **/ @@ -354,12 +373,13 @@ hb_face_is_immutable (const hb_face_t *face) /** * hb_face_reference_table: - * @face: a face. - * @tag: - * + * @face: A face object + * @tag: The #hb_tag_t of the table to query * + * Fetches a reference to the specified table within + * the specified face. * - * Return value: (transfer full): + * Return value: (transfer full): A pointer to the @tag table within @face * * Since: 0.9.2 **/ @@ -367,16 +387,21 @@ hb_blob_t * hb_face_reference_table (const hb_face_t *face, hb_tag_t tag) { + if (unlikely (tag == HB_TAG_NONE)) + return hb_blob_get_empty (); + return face->reference_table (tag); } /** * hb_face_reference_blob: - * @face: a face. - * + * @face: A face object * + * Fetches a pointer to the binary blob that contains the + * specified face. Returns an empty blob if referencing face data is not + * possible. * - * Return value: (transfer full): + * Return value: (transfer full): A pointer to the blob for @face * * Since: 0.9.2 **/ @@ -388,10 +413,13 @@ hb_face_reference_blob (hb_face_t *face) /** * hb_face_set_index: - * @face: a face. - * @index: + * @face: A face object + * @index: The index to assign * + * Assigns the specified face-index to @face. Fails if the + * face is immutable. * + * Note: face indices within a collection are zero-based. * * Since: 0.9.2 **/ @@ -407,11 +435,13 @@ hb_face_set_index (hb_face_t *face, /** * hb_face_get_index: - * @face: a face. + * @face: A face object * + * Fetches the face-index corresponding to the given face. * + * Note: face indices within a collection are zero-based. * - * Return value: + * Return value: The index of @face. * * Since: 0.9.2 **/ @@ -423,10 +453,10 @@ hb_face_get_index (const hb_face_t *face) /** * hb_face_set_upem: - * @face: a face. - * @upem: - * + * @face: A face object + * @upem: The units-per-em value to assign * + * Sets the units-per-em (upem) for a face object to the specified value. * * Since: 0.9.2 **/ @@ -442,11 +472,11 @@ hb_face_set_upem (hb_face_t *face, /** * hb_face_get_upem: - * @face: a face. - * + * @face: A face object * + * Fetches the units-per-em (upem) value of the specified face object. * - * Return value: + * Return value: The upem value of @face * * Since: 0.9.2 **/ @@ -458,10 +488,10 @@ hb_face_get_upem (const hb_face_t *face) /** * hb_face_set_glyph_count: - * @face: a face. - * @glyph_count: - * + * @face: A face object + * @glyph_count: The glyph-count value to assign * + * Sets the glyph count for a face object to the specified value. * * Since: 0.9.7 **/ @@ -477,11 +507,11 @@ hb_face_set_glyph_count (hb_face_t *face, /** * hb_face_get_glyph_count: - * @face: a face. + * @face: A face object * + * Fetches the glyph-count value of the specified face object. * - * - * Return value: + * Return value: The glyph-count value of @face * * Since: 0.9.7 **/ @@ -493,14 +523,16 @@ hb_face_get_glyph_count (const hb_face_t *face) /** * hb_face_get_table_tags: - * @face: a face. - * @start_offset: index of first tag to return. - * @table_count: input length of @table_tags array, output number of items written. - * @table_tags: array to write tags into. + * @face: A face object + * @start_offset: The index of first table tag to retrieve + * @table_count: (inout): Input = the maximum number of table tags to return; + * Output = the actual number of table tags returned (may be zero) + * @table_tags: (out) (array length=table_count): The array of table tags found * - * Retrieves table tags for a face, if possible. + * Fetches a list of all table tags for a face, if possible. The list returned will + * begin at the offset provided * - * Return value: total number of tables, or 0 if not possible to list. + * Return value: Total number of tables, or zero if it is not possible to list * * Since: 1.6.0 **/ @@ -534,8 +566,11 @@ hb_face_get_table_tags (const hb_face_t *face, #ifndef HB_NO_FACE_COLLECT_UNICODES /** * hb_face_collect_unicodes: - * @face: font face. - * @out: set to add Unicode characters covered by @face to. + * @face: A face object + * @out: The set to add Unicode characters to + * + * Collects all of the Unicode characters covered by @face and adds + * them to the #hb_set_t set @out. * * Since: 1.9.0 */ @@ -543,14 +578,15 @@ void hb_face_collect_unicodes (hb_face_t *face, hb_set_t *out) { - face->table.cmap->collect_unicodes (out); + face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); } /** * hb_face_collect_variation_selectors: - * @face: font face. - * @out: set to add Variation Selector characters covered by @face to. - * + * @face: A face object + * @out: The set to add Variation Selector characters to * + * Collects all Unicode "Variation Selector" characters covered by @face and adds + * them to the #hb_set_t set @out. * * Since: 1.9.0 */ @@ -562,10 +598,12 @@ hb_face_collect_variation_selectors (hb_face_t *face, } /** * hb_face_collect_variation_unicodes: - * @face: font face. - * @out: set to add Unicode characters for @variation_selector covered by @face to. - * + * @face: A face object + * @variation_selector: The Variation Selector to query + * @out: The set to add Unicode characters to * + * Collects all Unicode characters for @variation_selector covered by @face and adds + * them to the #hb_set_t set @out. * * Since: 1.9.0 */ @@ -700,6 +738,9 @@ hb_face_builder_create () /** * hb_face_builder_add_table: + * @face: A face object created with hb_face_builder_create() + * @tag: The #hb_tag_t of the table to add + * @blob: The blob containing the table data to add * * Add table for @tag with data provided by @blob to the face. @face must * be created using hb_face_builder_create(). @@ -713,7 +754,10 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) return false; hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + hb_face_builder_data_t::table_entry_t *entry = data->tables.push (); + if (unlikely (data->tables.in_error())) + return false; entry->tag = tag; entry->blob = hb_blob_reference (blob); diff --git a/src/hb-face.h b/src/hb-face.h index e8ff090d55fa57753dae2b217aca0afbe2ddd8c6..6ef2f8b8861f15eb78ee70635b02cea3aeba4f48 100644 --- a/src/hb-face.h +++ b/src/hb-face.h @@ -24,7 +24,7 @@ * Red Hat Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -46,12 +46,31 @@ hb_face_count (hb_blob_t *blob); * hb_face_t */ +/** + * hb_face_t: + * + * Data type for holding font faces. + * + **/ typedef struct hb_face_t hb_face_t; HB_EXTERN hb_face_t * hb_face_create (hb_blob_t *blob, unsigned int index); +/** + * hb_reference_table_func_t: + * @face: an #hb_face_t to reference table for + * @tag: the tag of the table to reference + * @user_data: User data pointer passed by the caller + * + * Callback function for hb_face_create_for_tables(). + * + * Return value: (transfer full): A pointer to the @tag table within @face + * + * Since: 0.9.2 + */ + typedef hb_blob_t * (*hb_reference_table_func_t) (hb_face_t *face, hb_tag_t tag, void *user_data); /* calls destroy() when not needing user_data anymore */ diff --git a/src/hb-face.hh b/src/hb-face.hh index 68834baeb838b6b59cc8e4dc719146c5ea047b46..765f2728582c4cfdb0eb71d98cdf8ea56b00de17 100644 --- a/src/hb-face.hh +++ b/src/hb-face.hh @@ -81,7 +81,7 @@ struct hb_face_t return blob; } - HB_PURE_FUNC unsigned int get_upem () const + unsigned int get_upem () const { unsigned int ret = upem.get_relaxed (); if (unlikely (!ret)) @@ -94,7 +94,7 @@ struct hb_face_t unsigned int get_num_glyphs () const { unsigned int ret = num_glyphs.get_relaxed (); - if (unlikely (ret == (unsigned int) -1)) + if (unlikely (ret == UINT_MAX)) return load_num_glyphs (); return ret; } diff --git a/src/hb-font.cc b/src/hb-font.cc index 445878bfe40b367019fd56eba6a9221455debf0f..37a0e7fe8542031e28d7e37252d6c073105c781e 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -33,6 +33,9 @@ #include "hb-ot.h" +#include "hb-ot-var-avar-table.hh" +#include "hb-ot-var-fvar-table.hh" + /** * SECTION:hb-font @@ -40,10 +43,20 @@ * @short_description: Font objects * @include: hb.h * - * Font objects represent a font face at a certain size and other - * parameters (pixels per EM, points per EM, variation settings.) - * Fonts are created from font faces, and are used as input to - * hb_shape() among other things. + * Functions for working with font objects. + * + * A font object represents a font face at a specific size and with + * certain other parameters (pixels-per-em, points-per-em, variation + * settings) specified. Font objects are created from font face + * objects, and are used as input to hb_shape(), among other things. + * + * Client programs can optionally pass in their own functions that + * implement the basic, lower-level queries of font objects. This set + * of font functions is defined by the virtual methods in + * #hb_font_funcs_t. + * + * HarfBuzz provides a built-in set of lightweight default + * functions for each method in #hb_font_funcs_t. **/ @@ -52,19 +65,20 @@ */ static hb_bool_t -hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, +hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, hb_font_extents_t *extents, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { memset (extents, 0, sizeof (*extents)); return false; } + static hb_bool_t -hb_font_get_font_h_extents_default (hb_font_t *font, - void *font_data HB_UNUSED, +hb_font_get_font_h_extents_default (hb_font_t *font, + void *font_data HB_UNUSED, hb_font_extents_t *extents, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_font_h_extents (extents); if (ret) { @@ -76,19 +90,20 @@ hb_font_get_font_h_extents_default (hb_font_t *font, } static hb_bool_t -hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, +hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, hb_font_extents_t *extents, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { memset (extents, 0, sizeof (*extents)); return false; } + static hb_bool_t -hb_font_get_font_v_extents_default (hb_font_t *font, - void *font_data HB_UNUSED, +hb_font_get_font_v_extents_default (hb_font_t *font, + void *font_data HB_UNUSED, hb_font_extents_t *extents, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_font_v_extents (extents); if (ret) { @@ -100,21 +115,22 @@ hb_font_get_font_v_extents_default (hb_font_t *font, } static hb_bool_t -hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t unicode HB_UNUSED, +hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { *glyph = 0; return false; } + static hb_bool_t -hb_font_get_nominal_glyph_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t unicode, +hb_font_get_nominal_glyph_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { if (font->has_nominal_glyphs_func_set ()) { @@ -124,15 +140,16 @@ hb_font_get_nominal_glyph_default (hb_font_t *font, } #define hb_font_get_nominal_glyphs_nil hb_font_get_nominal_glyphs_default + static unsigned int -hb_font_get_nominal_glyphs_default (hb_font_t *font, - void *font_data HB_UNUSED, - unsigned int count, +hb_font_get_nominal_glyphs_default (hb_font_t *font, + void *font_data HB_UNUSED, + unsigned int count, const hb_codepoint_t *first_unicode, - unsigned int unicode_stride, - hb_codepoint_t *first_glyph, - unsigned int glyph_stride, - void *user_data HB_UNUSED) + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride, + void *user_data HB_UNUSED) { if (font->has_nominal_glyph_func_set ()) { @@ -153,41 +170,43 @@ hb_font_get_nominal_glyphs_default (hb_font_t *font, } static hb_bool_t -hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t unicode HB_UNUSED, - hb_codepoint_t variation_selector HB_UNUSED, +hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t unicode HB_UNUSED, + hb_codepoint_t variation_selector HB_UNUSED, hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { *glyph = 0; return false; } + static hb_bool_t -hb_font_get_variation_glyph_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t unicode, - hb_codepoint_t variation_selector, +hb_font_get_variation_glyph_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { return font->parent->get_variation_glyph (unicode, variation_selector, glyph); } static hb_position_t -hb_font_get_glyph_h_advance_nil (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_advance_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + void *user_data HB_UNUSED) { return font->x_scale; } + static hb_position_t -hb_font_get_glyph_h_advance_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_advance_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) { if (font->has_glyph_h_advances_func_set ()) { @@ -199,19 +218,20 @@ hb_font_get_glyph_h_advance_default (hb_font_t *font, } static hb_position_t -hb_font_get_glyph_v_advance_nil (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_advance_nil (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + void *user_data HB_UNUSED) { /* TODO use font_extents.ascender+descender */ return font->y_scale; } + static hb_position_t -hb_font_get_glyph_v_advance_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_advance_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) { if (font->has_glyph_v_advances_func_set ()) { @@ -223,15 +243,16 @@ hb_font_get_glyph_v_advance_default (hb_font_t *font, } #define hb_font_get_glyph_h_advances_nil hb_font_get_glyph_h_advances_default + static void -hb_font_get_glyph_h_advances_default (hb_font_t* font, - void* font_data HB_UNUSED, - unsigned int count, +hb_font_get_glyph_h_advances_default (hb_font_t* font, + void* font_data HB_UNUSED, + unsigned int count, const hb_codepoint_t *first_glyph, - unsigned int glyph_stride, - hb_position_t *first_advance, - unsigned int advance_stride, - void *user_data HB_UNUSED) + unsigned int glyph_stride, + hb_position_t *first_advance, + unsigned int advance_stride, + void *user_data HB_UNUSED) { if (font->has_glyph_h_advance_func_set ()) { @@ -256,14 +277,14 @@ hb_font_get_glyph_h_advances_default (hb_font_t* font, #define hb_font_get_glyph_v_advances_nil hb_font_get_glyph_v_advances_default static void -hb_font_get_glyph_v_advances_default (hb_font_t* font, - void* font_data HB_UNUSED, - unsigned int count, +hb_font_get_glyph_v_advances_default (hb_font_t* font, + void* font_data HB_UNUSED, + unsigned int count, const hb_codepoint_t *first_glyph, - unsigned int glyph_stride, - hb_position_t *first_advance, - unsigned int advance_stride, - void *user_data HB_UNUSED) + unsigned int glyph_stride, + hb_position_t *first_advance, + unsigned int advance_stride, + void *user_data HB_UNUSED) { if (font->has_glyph_v_advance_func_set ()) { @@ -287,23 +308,24 @@ hb_font_get_glyph_v_advances_default (hb_font_t* font, } static hb_bool_t -hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { *x = *y = 0; return true; } + static hb_bool_t -hb_font_get_glyph_h_origin_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_origin_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y); if (ret) @@ -312,23 +334,24 @@ hb_font_get_glyph_h_origin_default (hb_font_t *font, } static hb_bool_t -hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { *x = *y = 0; return false; } + static hb_bool_t -hb_font_get_glyph_v_origin_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_origin_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y); if (ret) @@ -337,61 +360,64 @@ hb_font_get_glyph_v_origin_default (hb_font_t *font, } static hb_position_t -hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t left_glyph HB_UNUSED, - hb_codepoint_t right_glyph HB_UNUSED, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph HB_UNUSED, + hb_codepoint_t right_glyph HB_UNUSED, + void *user_data HB_UNUSED) { return 0; } + static hb_position_t -hb_font_get_glyph_h_kerning_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t left_glyph, - hb_codepoint_t right_glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_h_kerning_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) { return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph)); } #ifndef HB_DISABLE_DEPRECATED static hb_position_t -hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t top_glyph HB_UNUSED, - hb_codepoint_t bottom_glyph HB_UNUSED, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph HB_UNUSED, + hb_codepoint_t bottom_glyph HB_UNUSED, + void *user_data HB_UNUSED) { return 0; } + static hb_position_t -hb_font_get_glyph_v_kerning_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t top_glyph, - hb_codepoint_t bottom_glyph, - void *user_data HB_UNUSED) +hb_font_get_glyph_v_kerning_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph, + void *user_data HB_UNUSED) { return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph)); } #endif static hb_bool_t -hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, +hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, hb_glyph_extents_t *extents, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { memset (extents, 0, sizeof (*extents)); return false; } + static hb_bool_t -hb_font_get_glyph_extents_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, +hb_font_get_glyph_extents_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, hb_glyph_extents_t *extents, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents); if (ret) { @@ -402,25 +428,26 @@ hb_font_get_glyph_extents_default (hb_font_t *font, } static hb_bool_t -hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - unsigned int point_index HB_UNUSED, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + unsigned int point_index HB_UNUSED, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { *x = *y = 0; return false; } + static hb_bool_t -hb_font_get_glyph_contour_point_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - unsigned int point_index, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_font_get_glyph_contour_point_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y); if (ret) @@ -429,42 +456,47 @@ hb_font_get_glyph_contour_point_default (hb_font_t *font, } static hb_bool_t -hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph HB_UNUSED, - char *name, unsigned int size, - void *user_data HB_UNUSED) +hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + char *name, + unsigned int size, + void *user_data HB_UNUSED) { if (size) *name = '\0'; return false; } + static hb_bool_t -hb_font_get_glyph_name_default (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - char *name, unsigned int size, - void *user_data HB_UNUSED) +hb_font_get_glyph_name_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + char *name, + unsigned int size, + void *user_data HB_UNUSED) { return font->parent->get_glyph_name (glyph, name, size); } static hb_bool_t -hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - const char *name HB_UNUSED, - int len HB_UNUSED, /* -1 means nul-terminated */ +hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + const char *name HB_UNUSED, + int len HB_UNUSED, /* -1 means nul-terminated */ hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { *glyph = 0; return false; } + static hb_bool_t -hb_font_get_glyph_from_name_default (hb_font_t *font, - void *font_data HB_UNUSED, - const char *name, int len, /* -1 means nul-terminated */ +hb_font_get_glyph_from_name_default (hb_font_t *font, + void *font_data HB_UNUSED, + const char *name, + int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *user_data HB_UNUSED) { return font->parent->get_glyph_from_name (name, len, glyph); } @@ -518,9 +550,9 @@ static const hb_font_funcs_t _hb_font_funcs_default = { /** * hb_font_funcs_create: (Xconstructor) * + * Creates a new #hb_font_funcs_t structure of font functions. * - * - * Return value: (transfer full): + * Return value: (transfer full): The font-functions structure * * Since: 0.9.2 **/ @@ -540,9 +572,9 @@ hb_font_funcs_create () /** * hb_font_funcs_get_empty: * + * Fetches an empty font-functions structure. * - * - * Return value: (transfer full): + * Return value: (transfer full): The font-functions structure * * Since: 0.9.2 **/ @@ -554,11 +586,11 @@ hb_font_funcs_get_empty () /** * hb_font_funcs_reference: (skip) - * @ffuncs: font functions. - * + * @ffuncs: The font-functions structure * + * Increases the reference count on a font-functions structure. * - * Return value: + * Return value: The font-functions structure * * Since: 0.9.2 **/ @@ -570,9 +602,11 @@ hb_font_funcs_reference (hb_font_funcs_t *ffuncs) /** * hb_font_funcs_destroy: (skip) - * @ffuncs: font functions. - * + * @ffuncs: The font-functions structure * + * Decreases the reference count on a font-functions structure. When + * the reference count reaches zero, the font-functions structure is + * destroyed, freeing all memory. * * Since: 0.9.2 **/ @@ -591,15 +625,15 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) /** * hb_font_funcs_set_user_data: (skip) - * @ffuncs: font functions. - * @key: - * @data: - * @destroy: - * @replace: - * + * @ffuncs: The font-functions structure + * @key: The user-data key to set + * @data: A pointer to the user data set + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * + * Attaches a user-data key/data pair to the specified font-functions structure. * - * Return value: + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ @@ -607,7 +641,7 @@ hb_bool_t hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, hb_user_data_key_t *key, void * data, - hb_destroy_func_t destroy, + hb_destroy_func_t destroy /* May be NULL. */, hb_bool_t replace) { return hb_object_set_user_data (ffuncs, key, data, destroy, replace); @@ -615,12 +649,13 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_get_user_data: (skip) - * @ffuncs: font functions. - * @key: - * + * @ffuncs: The font-functions structure + * @key: The user-data key to query * + * Fetches the user data associated with the specified key, + * attached to the specified font-functions structure. * - * Return value: (transfer none): + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.2 **/ @@ -634,9 +669,9 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_make_immutable: - * @ffuncs: font functions. - * + * @ffuncs: The font-functions structure * + * Makes a font-functions structure immutable. * * Since: 0.9.2 **/ @@ -651,11 +686,11 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) /** * hb_font_funcs_is_immutable: - * @ffuncs: font functions. - * + * @ffuncs: The font-functions structure * + * Tests whether a font-functions structure is immutable. * - * Return value: + * Return value: %true if @ffuncs is immutable, %false otherwise * * Since: 0.9.2 **/ @@ -667,22 +702,23 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) #define HB_FONT_FUNC_IMPLEMENT(name) \ - \ + \ void \ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ - hb_font_get_##name##_func_t func, \ - void *user_data, \ - hb_destroy_func_t destroy) \ + hb_font_get_##name##_func_t func, \ + void *user_data, \ + hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (ffuncs)) { \ + if (hb_object_is_immutable (ffuncs)) \ + { \ if (destroy) \ destroy (user_data); \ return; \ } \ - \ + \ if (ffuncs->destroy.name) \ ffuncs->destroy.name (ffuncs->user_data.name); \ - \ + \ if (func) { \ ffuncs->get.f.name = func; \ ffuncs->user_data.name = user_data; \ @@ -714,17 +750,18 @@ hb_font_t::has_func (unsigned int i) /** * hb_font_get_h_extents: - * @font: a font. - * @extents: (out): + * @font: #hb_font_t to work upon + * @extents: (out): The font extents retrieved * + * Fetches the extents for a specified font, for horizontal + * text segments. * - * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 1.1.3 **/ hb_bool_t -hb_font_get_h_extents (hb_font_t *font, +hb_font_get_h_extents (hb_font_t *font, hb_font_extents_t *extents) { return font->get_font_h_extents (extents); @@ -732,17 +769,18 @@ hb_font_get_h_extents (hb_font_t *font, /** * hb_font_get_v_extents: - * @font: a font. - * @extents: (out): - * + * @font: #hb_font_t to work upon + * @extents: (out): The font extents retrieved * + * Fetches the extents for a specified font, for vertical + * text segments. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 1.1.3 **/ hb_bool_t -hb_font_get_v_extents (hb_font_t *font, +hb_font_get_v_extents (hb_font_t *font, hb_font_extents_t *extents) { return font->get_font_v_extents (extents); @@ -750,20 +788,25 @@ hb_font_get_v_extents (hb_font_t *font, /** * hb_font_get_glyph: - * @font: a font. - * @unicode: - * @variation_selector: - * @glyph: (out): + * @font: #hb_font_t to work upon + * @unicode: The Unicode code point to query + * @variation_selector: A variation-selector code point + * @glyph: (out): The glyph ID retrieved * + * Fetches the glyph ID for a Unicode code point in the specified + * font, with an optional variation selector. * + * If @variation_selector is 0, calls hb_font_get_nominal_glyph(); + * otherwise calls hb_font_get_variation_glyph(). * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph (hb_font_t *font, - hb_codepoint_t unicode, hb_codepoint_t variation_selector, +hb_font_get_glyph (hb_font_t *font, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, hb_codepoint_t *glyph) { if (unlikely (variation_selector)) @@ -773,40 +816,77 @@ hb_font_get_glyph (hb_font_t *font, /** * hb_font_get_nominal_glyph: - * @font: a font. - * @unicode: - * @glyph: (out): + * @font: #hb_font_t to work upon + * @unicode: The Unicode code point to query + * @glyph: (out): The glyph ID retrieved * + * Fetches the nominal glyph ID for a Unicode code point in the + * specified font. * + * This version of the function should not be used to fetch glyph IDs + * for code points modified by variation selectors. For variation-selector + * support, user hb_font_get_variation_glyph() or use hb_font_get_glyph(). * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 1.2.3 **/ hb_bool_t -hb_font_get_nominal_glyph (hb_font_t *font, - hb_codepoint_t unicode, +hb_font_get_nominal_glyph (hb_font_t *font, + hb_codepoint_t unicode, hb_codepoint_t *glyph) { return font->get_nominal_glyph (unicode, glyph); } /** - * hb_font_get_variation_glyph: - * @font: a font. - * @unicode: - * @variation_selector: - * @glyph: (out): + * hb_font_get_nominal_glyphs: + * @font: #hb_font_t to work upon + * @count: number of code points to query + * @first_unicode: The first Unicode code point to query + * @unicode_stride: The stride between successive code points + * @first_glyph: (out): The first glyph ID retrieved + * @glyph_stride: The stride between successive glyph IDs * + * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph + * IDs must be returned in a #hb_codepoint_t output parameter. * + * Return value: the number of code points processed * - * Return value: + * Since: 2.6.3 + **/ +unsigned int +hb_font_get_nominal_glyphs (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride) +{ + return font->get_nominal_glyphs (count, + first_unicode, unicode_stride, + first_glyph, glyph_stride); +} + +/** + * hb_font_get_variation_glyph: + * @font: #hb_font_t to work upon + * @unicode: The Unicode code point to query + * @variation_selector: The variation-selector code point to query + * @glyph: (out): The glyph ID retrieved + * + * Fetches the glyph ID for a Unicode code point when followed by + * by the specified variation-selector code point, in the specified + * font. + * + * Return value: %true if data found, %false otherwise * * Since: 1.2.3 **/ hb_bool_t -hb_font_get_variation_glyph (hb_font_t *font, - hb_codepoint_t unicode, hb_codepoint_t variation_selector, +hb_font_get_variation_glyph (hb_font_t *font, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, hb_codepoint_t *glyph) { return font->get_variation_glyph (unicode, variation_selector, glyph); @@ -814,134 +894,157 @@ hb_font_get_variation_glyph (hb_font_t *font, /** * hb_font_get_glyph_h_advance: - * @font: a font. - * @glyph: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query * + * Fetches the advance for a glyph ID in the specified font, + * for horizontal text segments. * - * - * Return value: + * Return value: The advance of @glyph within @font * * Since: 0.9.2 **/ hb_position_t -hb_font_get_glyph_h_advance (hb_font_t *font, - hb_codepoint_t glyph) +hb_font_get_glyph_h_advance (hb_font_t *font, + hb_codepoint_t glyph) { return font->get_glyph_h_advance (glyph); } /** * hb_font_get_glyph_v_advance: - * @font: a font. - * @glyph: - * + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query * + * Fetches the advance for a glyph ID in the specified font, + * for vertical text segments. * - * Return value: + * Return value: The advance of @glyph within @font * * Since: 0.9.2 **/ hb_position_t -hb_font_get_glyph_v_advance (hb_font_t *font, - hb_codepoint_t glyph) +hb_font_get_glyph_v_advance (hb_font_t *font, + hb_codepoint_t glyph) { return font->get_glyph_v_advance (glyph); } /** * hb_font_get_glyph_h_advances: - * @font: a font. - * + * @font: #hb_font_t to work upon + * @count: The number of glyph IDs in the sequence queried + * @first_glyph: The first glyph ID to query + * @glyph_stride: The stride between successive glyph IDs + * @first_advance: (out): The first advance retrieved + * @advance_stride: The stride between successive advances * + * Fetches the advances for a sequence of glyph IDs in the specified + * font, for horizontal text segments. * * Since: 1.8.6 **/ void -hb_font_get_glyph_h_advances (hb_font_t* font, - unsigned int count, +hb_font_get_glyph_h_advances (hb_font_t* font, + unsigned int count, const hb_codepoint_t *first_glyph, - unsigned glyph_stride, - hb_position_t *first_advance, - unsigned advance_stride) + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) { font->get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); } /** * hb_font_get_glyph_v_advances: - * @font: a font. - * + * @font: #hb_font_t to work upon + * @count: The number of glyph IDs in the sequence queried + * @first_glyph: The first glyph ID to query + * @glyph_stride: The stride between successive glyph IDs + * @first_advance: (out): The first advance retrieved + * @advance_stride: (out): The stride between successive advances * + * Fetches the advances for a sequence of glyph IDs in the specified + * font, for vertical text segments. * * Since: 1.8.6 **/ void -hb_font_get_glyph_v_advances (hb_font_t* font, - unsigned int count, +hb_font_get_glyph_v_advances (hb_font_t* font, + unsigned int count, const hb_codepoint_t *first_glyph, - unsigned glyph_stride, - hb_position_t *first_advance, - unsigned advance_stride) + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) { font->get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride); } /** * hb_font_get_glyph_h_origin: - * @font: a font. - * @glyph: - * @x: (out): - * @y: (out): - * + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @x: (out): The X coordinate of the origin + * @y: (out): The Y coordinate of the origin * + * Fetches the (X,Y) coordinates of the origin for a glyph ID + * in the specified font, for horizontal text segments. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_h_origin (hb_font_t *font, - hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_h_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_h_origin (glyph, x, y); } /** * hb_font_get_glyph_v_origin: - * @font: a font. - * @glyph: - * @x: (out): - * @y: (out): - * + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @x: (out): The X coordinate of the origin + * @y: (out): The Y coordinate of the origin * + * Fetches the (X,Y) coordinates of the origin for a glyph ID + * in the specified font, for vertical text segments. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_v_origin (hb_font_t *font, - hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_v_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_v_origin (glyph, x, y); } /** * hb_font_get_glyph_h_kerning: - * @font: a font. - * @left_glyph: - * @right_glyph: + * @font: #hb_font_t to work upon + * @left_glyph: The glyph ID of the left glyph in the glyph pair + * @right_glyph: The glyph ID of the right glyph in the glyph pair * + * Fetches the kerning-adjustment value for a glyph-pair in + * the specified font, for horizontal text segments. * + * It handles legacy kerning only (as returned by the corresponding + * #hb_font_funcs_t function). * - * Return value: + * Return value: The kerning adjustment value * * Since: 0.9.2 **/ hb_position_t -hb_font_get_glyph_h_kerning (hb_font_t *font, - hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph) { return font->get_glyph_h_kerning (left_glyph, right_glyph); } @@ -949,20 +1052,25 @@ hb_font_get_glyph_h_kerning (hb_font_t *font, #ifndef HB_DISABLE_DEPRECATED /** * hb_font_get_glyph_v_kerning: - * @font: a font. - * @top_glyph: - * @bottom_glyph: + * @font: #hb_font_t to work upon + * @top_glyph: The glyph ID of the top glyph in the glyph pair + * @bottom_glyph: The glyph ID of the bottom glyph in the glyph pair * + * Fetches the kerning-adjustment value for a glyph-pair in + * the specified font, for vertical text segments. * + * It handles legacy kerning only (as returned by the corresponding + * #hb_font_funcs_t function). * - * Return value: + * Return value: The kerning adjustment value * * Since: 0.9.2 * Deprecated: 2.0.0 **/ hb_position_t -hb_font_get_glyph_v_kerning (hb_font_t *font, - hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) +hb_font_get_glyph_v_kerning (hb_font_t *font, + hb_codepoint_t top_glyph, + hb_codepoint_t bottom_glyph) { return font->get_glyph_v_kerning (top_glyph, bottom_glyph); } @@ -970,19 +1078,20 @@ hb_font_get_glyph_v_kerning (hb_font_t *font, /** * hb_font_get_glyph_extents: - * @font: a font. - * @glyph: - * @extents: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @extents: (out): The #hb_glyph_extents_t retrieved * + * Fetches the #hb_glyph_extents_t data for a glyph ID + * in the specified font. * - * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_extents (hb_font_t *font, - hb_codepoint_t glyph, +hb_font_get_glyph_extents (hb_font_t *font, + hb_codepoint_t glyph, hb_glyph_extents_t *extents) { return font->get_glyph_extents (glyph, extents); @@ -990,63 +1099,70 @@ hb_font_get_glyph_extents (hb_font_t *font, /** * hb_font_get_glyph_contour_point: - * @font: a font. - * @glyph: - * @point_index: - * @x: (out): - * @y: (out): - * + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @point_index: The contour-point index to query + * @x: (out): The X value retrieved for the contour point + * @y: (out): The Y value retrieved for the contour point * + * Fetches the (x,y) coordinates of a specified contour-point index + * in the specified glyph, within the specified font. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_contour_point (hb_font_t *font, - hb_codepoint_t glyph, unsigned int point_index, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_contour_point (hb_font_t *font, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_contour_point (glyph, point_index, x, y); } /** * hb_font_get_glyph_name: - * @font: a font. - * @glyph: - * @name: (array length=size): - * @size: - * + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @name: (out) (array length=size): Name string retrieved for the glyph ID + * @size: Length of the glyph-name string retrieved * + * Fetches the glyph-name string for a glyph ID in the specified @font. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_name (hb_font_t *font, - hb_codepoint_t glyph, - char *name, unsigned int size) +hb_font_get_glyph_name (hb_font_t *font, + hb_codepoint_t glyph, + char *name, + unsigned int size) { return font->get_glyph_name (glyph, name, size); } /** * hb_font_get_glyph_from_name: - * @font: a font. - * @name: (array length=len): - * @len: - * @glyph: (out): + * @font: #hb_font_t to work upon + * @name: (array length=len): The name string to query + * @len: The length of the name queried + * @glyph: (out): The glyph ID retrieved * + * Fetches the glyph ID that corresponds to a name string in the specified @font. * + * Note: @len == -1 means the name string is null-terminated. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_from_name (hb_font_t *font, - const char *name, int len, /* -1 means nul-terminated */ +hb_font_get_glyph_from_name (hb_font_t *font, + const char *name, + int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph) { return font->get_glyph_from_name (name, len, glyph); @@ -1057,164 +1173,211 @@ hb_font_get_glyph_from_name (hb_font_t *font, /** * hb_font_get_extents_for_direction: - * @font: a font. - * @direction: - * @extents: (out): + * @font: #hb_font_t to work upon + * @direction: The direction of the text segment + * @extents: (out): The #hb_font_extents_t retrieved * + * Fetches the extents for a font in a text segment of the + * specified direction. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 1.1.3 **/ void -hb_font_get_extents_for_direction (hb_font_t *font, - hb_direction_t direction, +hb_font_get_extents_for_direction (hb_font_t *font, + hb_direction_t direction, hb_font_extents_t *extents) { return font->get_extents_for_direction (direction, extents); } /** * hb_font_get_glyph_advance_for_direction: - * @font: a font. - * @glyph: - * @direction: - * @x: (out): - * @y: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @direction: The direction of the text segment + * @x: (out): The horizontal advance retrieved + * @y: (out): The vertical advance retrieved * + * Fetches the advance for a glyph ID from the specified font, + * in a text segment of the specified direction. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 0.9.2 **/ void -hb_font_get_glyph_advance_for_direction (hb_font_t *font, - hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_advance_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_advance_for_direction (glyph, direction, x, y); } /** * hb_font_get_glyph_advances_for_direction: - * @font: a font. - * @direction: + * @font: #hb_font_t to work upon + * @direction: The direction of the text segment + * @count: The number of glyph IDs in the sequence queried + * @first_glyph: The first glyph ID to query + * @glyph_stride: The stride between successive glyph IDs + * @first_advance: (out): The first advance retrieved + * @advance_stride: (out): The stride between successive advances * + * Fetches the advances for a sequence of glyph IDs in the specified + * font, in a text segment of the specified direction. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 1.8.6 **/ HB_EXTERN void -hb_font_get_glyph_advances_for_direction (hb_font_t* font, - hb_direction_t direction, - unsigned int count, +hb_font_get_glyph_advances_for_direction (hb_font_t* font, + hb_direction_t direction, + unsigned int count, const hb_codepoint_t *first_glyph, - unsigned glyph_stride, - hb_position_t *first_advance, - unsigned advance_stride) + unsigned glyph_stride, + hb_position_t *first_advance, + unsigned advance_stride) { font->get_glyph_advances_for_direction (direction, count, first_glyph, glyph_stride, first_advance, advance_stride); } /** * hb_font_get_glyph_origin_for_direction: - * @font: a font. - * @glyph: - * @direction: - * @x: (out): - * @y: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @direction: The direction of the text segment + * @x: (out): The X coordinate retrieved for the origin + * @y: (out): The Y coordinate retrieved for the origin * + * Fetches the (X,Y) coordinates of the origin for a glyph in + * the specified font. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 0.9.2 **/ void -hb_font_get_glyph_origin_for_direction (hb_font_t *font, - hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_origin_for_direction (glyph, direction, x, y); } /** * hb_font_add_glyph_origin_for_direction: - * @font: a font. - * @glyph: - * @direction: - * @x: (out): - * @y: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @direction: The direction of the text segment + * @x: (inout): Input = The original X coordinate + * Output = The X coordinate plus the X-coordinate of the origin + * @y: (inout): Input = The original Y coordinate + * Output = The Y coordinate plus the Y-coordinate of the origin * + * Adds the origin coordinates to an (X,Y) point coordinate, in + * the specified glyph ID in the specified font. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 0.9.2 **/ void -hb_font_add_glyph_origin_for_direction (hb_font_t *font, - hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) +hb_font_add_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, + hb_position_t *y) { return font->add_glyph_origin_for_direction (glyph, direction, x, y); } /** * hb_font_subtract_glyph_origin_for_direction: - * @font: a font. - * @glyph: - * @direction: - * @x: (out): - * @y: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @direction: The direction of the text segment + * @x: (inout): Input = The original X coordinate + * Output = The X coordinate minus the X-coordinate of the origin + * @y: (inout): Input = The original Y coordinate + * Output = The Y coordinate minus the Y-coordinate of the origin * + * Subtracts the origin coordinates from an (X,Y) point coordinate, + * in the specified glyph ID in the specified font. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 0.9.2 **/ void -hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, - hb_codepoint_t glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) +hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, + hb_position_t *x, + hb_position_t *y) { return font->subtract_glyph_origin_for_direction (glyph, direction, x, y); } /** * hb_font_get_glyph_kerning_for_direction: - * @font: a font. - * @first_glyph: - * @second_glyph: - * @direction: - * @x: (out): - * @y: (out): + * @font: #hb_font_t to work upon + * @first_glyph: The glyph ID of the first glyph in the glyph pair to query + * @second_glyph: The glyph ID of the second glyph in the glyph pair to query + * @direction: The direction of the text segment + * @x: (out): The horizontal kerning-adjustment value retrieved + * @y: (out): The vertical kerning-adjustment value retrieved * + * Fetches the kerning-adjustment value for a glyph-pair in the specified font. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * * Since: 0.9.2 **/ void -hb_font_get_glyph_kerning_for_direction (hb_font_t *font, - hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, + hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y); } /** * hb_font_get_glyph_extents_for_origin: - * @font: a font. - * @glyph: - * @direction: - * @extents: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @direction: The direction of the text segment + * @extents: (out): The #hb_glyph_extents_t retrieved * + * Fetches the #hb_glyph_extents_t data for a glyph ID + * in the specified font, with respect to the origin in + * a text segment in the specified direction. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_extents_for_origin (hb_font_t *font, - hb_codepoint_t glyph, - hb_direction_t direction, +hb_font_get_glyph_extents_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + hb_direction_t direction, hb_glyph_extents_t *extents) { return font->get_glyph_extents_for_origin (glyph, direction, extents); @@ -1222,65 +1385,79 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font, /** * hb_font_get_glyph_contour_point_for_origin: - * @font: a font. - * @glyph: - * @point_index: - * @direction: - * @x: (out): - * @y: (out): + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @point_index: The contour-point index to query + * @direction: The direction of the text segment + * @x: (out): The X value retrieved for the contour point + * @y: (out): The Y value retrieved for the contour point * + * Fetches the (X,Y) coordinates of a specified contour-point index + * in the specified glyph ID in the specified font, with respect + * to the origin in a text segment in the specified direction. * + * Calls the appropriate direction-specific variant (horizontal + * or vertical) depending on the value of @direction. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, - hb_codepoint_t glyph, unsigned int point_index, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y) +hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, + hb_codepoint_t glyph, + unsigned int point_index, + hb_direction_t direction, + hb_position_t *x, + hb_position_t *y) { return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y); } -/* Generates gidDDD if glyph has no name. */ /** * hb_font_glyph_to_string: - * @font: a font. - * @glyph: - * @s: (array length=size): - * @size: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID to query + * @s: (out) (array length=size): The string containing the glyph name + * @size: Length of string @s * + * Fetches the name of the specified glyph ID in @font and returns + * it in string @s. * + * If the glyph ID has no name in @font, a string of the form `gidDDD` is + * generated, with `DDD` being the glyph ID. * * Since: 0.9.2 **/ void -hb_font_glyph_to_string (hb_font_t *font, - hb_codepoint_t glyph, - char *s, unsigned int size) +hb_font_glyph_to_string (hb_font_t *font, + hb_codepoint_t glyph, + char *s, + unsigned int size) { font->glyph_to_string (glyph, s, size); } -/* Parses gidDDD and uniUUUU strings automatically. */ /** * hb_font_glyph_from_string: - * @font: a font. - * @s: (array length=len) (element-type uint8_t): - * @len: - * @glyph: (out): + * @font: #hb_font_t to work upon + * @s: (array length=len) (element-type uint8_t): string to query + * @len: The length of the string @s + * @glyph: (out): The glyph ID corresponding to the string requested * + * Fetches the glyph ID from @font that matches the specified string. + * Strings of the format `gidDDD` or `uniUUUU` are parsed automatically. * + * Note: @len == -1 means the string is null-terminated. * - * Return value: + * Return value: %true if data found, %false otherwise * * Since: 0.9.2 **/ hb_bool_t -hb_font_glyph_from_string (hb_font_t *font, - const char *s, int len, /* -1 means nul-terminated */ +hb_font_glyph_from_string (hb_font_t *font, + const char *s, + int len, hb_codepoint_t *glyph) { return font->glyph_from_string (s, len, glyph); @@ -1309,6 +1486,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 0, /* num_coords */ nullptr, /* coords */ + nullptr, /* design_coords */ const_cast (&_hb_Null_hb_font_funcs_t), @@ -1341,9 +1519,9 @@ _hb_font_create (hb_face_t *face) * hb_font_create: (Xconstructor) * @face: a face. * + * Constructs a new font object from the specified face. * - * - * Return value: (transfer full): + * Return value: (transfer full): The new font object * * Since: 0.9.2 **/ @@ -1360,13 +1538,28 @@ hb_font_create (hb_face_t *face) return font; } +static void +_hb_font_adopt_var_coords (hb_font_t *font, + int *coords, /* 2.14 normalized */ + float *design_coords, + unsigned int coords_length) +{ + free (font->coords); + free (font->design_coords); + + font->coords = coords; + font->design_coords = design_coords; + font->num_coords = coords_length; +} + /** * hb_font_create_sub_font: - * @parent: parent font. - * + * @parent: The parent font object * + * Constructs a sub-font font object from the specified @parent font, + * replicating the parent's properties. * - * Return value: (transfer full): + * Return value: (transfer full): The new sub-font font object * * Since: 0.9.2 **/ @@ -1390,15 +1583,22 @@ hb_font_create_sub_font (hb_font_t *parent) font->y_ppem = parent->y_ppem; font->ptem = parent->ptem; - font->num_coords = parent->num_coords; - if (font->num_coords) + unsigned int num_coords = parent->num_coords; + if (num_coords) { - unsigned int size = parent->num_coords * sizeof (parent->coords[0]); - font->coords = (int *) malloc (size); - if (unlikely (!font->coords)) - font->num_coords = 0; + int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0])); + float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0])); + if (likely (coords && design_coords)) + { + memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); + memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); + _hb_font_adopt_var_coords (font, coords, design_coords, num_coords); + } else - memcpy (font->coords, parent->coords, size); + { + free (coords); + free (design_coords); + } } return font; @@ -1407,25 +1607,25 @@ hb_font_create_sub_font (hb_font_t *parent) /** * hb_font_get_empty: * + * Fetches the empty font object. * - * - * Return value: (transfer full) + * Return value: (transfer full): The empty font object * * Since: 0.9.2 **/ hb_font_t * hb_font_get_empty () { - return const_cast (&Null(hb_font_t)); + return const_cast (&Null (hb_font_t)); } /** * hb_font_reference: (skip) - * @font: a font. + * @font: #hb_font_t to work upon * + * Increases the reference count on the given font object. * - * - * Return value: (transfer full): + * Return value: (transfer full): The @font object * * Since: 0.9.2 **/ @@ -1437,9 +1637,11 @@ hb_font_reference (hb_font_t *font) /** * hb_font_destroy: (skip) - * @font: a font. - * + * @font: #hb_font_t to work upon * + * Decreases the reference count on the given font object. When the + * reference count reaches zero, the font is destroyed, + * freeing all memory. * * Since: 0.9.2 **/ @@ -1458,21 +1660,22 @@ hb_font_destroy (hb_font_t *font) hb_font_funcs_destroy (font->klass); free (font->coords); + free (font->design_coords); free (font); } /** * hb_font_set_user_data: (skip) - * @font: a font. - * @key: - * @data: - * @destroy: - * @replace: - * + * @font: #hb_font_t to work upon + * @key: The user-data key + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * + * Attaches a user-data key/data pair to the specified font object. * - * Return value: + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ @@ -1480,7 +1683,7 @@ hb_bool_t hb_font_set_user_data (hb_font_t *font, hb_user_data_key_t *key, void * data, - hb_destroy_func_t destroy, + hb_destroy_func_t destroy /* May be NULL. */, hb_bool_t replace) { return hb_object_set_user_data (font, key, data, destroy, replace); @@ -1488,12 +1691,13 @@ hb_font_set_user_data (hb_font_t *font, /** * hb_font_get_user_data: (skip) - * @font: a font. - * @key: + * @font: #hb_font_t to work upon + * @key: The user-data key to query * + * Fetches the user-data object associated with the specified key, + * attached to the specified font object. * - * - * Return value: (transfer none): + * Return value: (transfer none): Pointer to the user data * * Since: 0.9.2 **/ @@ -1506,9 +1710,9 @@ hb_font_get_user_data (hb_font_t *font, /** * hb_font_make_immutable: - * @font: a font. - * + * @font: #hb_font_t to work upon * + * Makes @font immutable. * * Since: 0.9.2 **/ @@ -1526,11 +1730,11 @@ hb_font_make_immutable (hb_font_t *font) /** * hb_font_is_immutable: - * @font: a font. - * + * @font: #hb_font_t to work upon * + * Tests whether a font object is immutable. * - * Return value: + * Return value: %true if @font is immutable, %false otherwise * * Since: 0.9.2 **/ @@ -1542,10 +1746,10 @@ hb_font_is_immutable (hb_font_t *font) /** * hb_font_set_parent: - * @font: a font. - * @parent: new parent. + * @font: #hb_font_t to work upon + * @parent: The parent font object to assign * - * Sets parent font of @font. + * Sets the parent font of @font. * * Since: 1.0.5 **/ @@ -1568,11 +1772,11 @@ hb_font_set_parent (hb_font_t *font, /** * hb_font_get_parent: - * @font: a font. - * + * @font: #hb_font_t to work upon * + * Fetches the parent font of @font. * - * Return value: (transfer none): + * Return value: (transfer none): The parent font object * * Since: 0.9.2 **/ @@ -1584,10 +1788,10 @@ hb_font_get_parent (hb_font_t *font) /** * hb_font_set_face: - * @font: a font. - * @face: new face. + * @font: #hb_font_t to work upon + * @face: The #hb_face_t to assign * - * Sets font-face of @font. + * Sets @face as the font-face value of @font. * * Since: 1.4.3 **/ @@ -1612,11 +1816,11 @@ hb_font_set_face (hb_font_t *font, /** * hb_font_get_face: - * @font: a font. - * + * @font: #hb_font_t to work upon * + * Fetches the face associated with the specified font object. * - * Return value: (transfer none): + * Return value: (transfer none): The #hb_face_t value * * Since: 0.9.2 **/ @@ -1629,12 +1833,13 @@ hb_font_get_face (hb_font_t *font) /** * hb_font_set_funcs: - * @font: a font. - * @klass: (closure font_data) (destroy destroy) (scope notified): - * @font_data: - * @destroy: - * + * @font: #hb_font_t to work upon + * @klass: (closure font_data) (destroy destroy) (scope notified): The font-functions structure. + * @font_data: Data to attach to @font + * @destroy: (nullable): The function to call when @font_data is not needed anymore * + * Replaces the font-functions structure attached to a font, updating + * the font's user-data with @font-data and the @destroy callback. * * Since: 0.9.2 **/ @@ -1642,7 +1847,7 @@ void hb_font_set_funcs (hb_font_t *font, hb_font_funcs_t *klass, void *font_data, - hb_destroy_func_t destroy) + hb_destroy_func_t destroy /* May be NULL. */) { if (hb_object_is_immutable (font)) { @@ -1666,18 +1871,19 @@ hb_font_set_funcs (hb_font_t *font, /** * hb_font_set_funcs_data: - * @font: a font. - * @font_data: (destroy destroy) (scope notified): - * @destroy: - * + * @font: #hb_font_t to work upon + * @font_data: (destroy destroy) (scope notified): Data to attach to @font + * @destroy: (nullable): The function to call when @font_data is not needed anymore * + * Replaces the user data attached to a font, updating the font's + * @destroy callback. * * Since: 0.9.2 **/ void hb_font_set_funcs_data (hb_font_t *font, void *font_data, - hb_destroy_func_t destroy) + hb_destroy_func_t destroy /* May be NULL. */) { /* Destroy user_data? */ if (hb_object_is_immutable (font)) @@ -1697,18 +1903,18 @@ hb_font_set_funcs_data (hb_font_t *font, /** * hb_font_set_scale: - * @font: a font. - * @x_scale: - * @y_scale: - * + * @font: #hb_font_t to work upon + * @x_scale: Horizontal scale value to assign + * @y_scale: Vertical scale value to assign * + * Sets the horizontal and vertical scale of a font. * * Since: 0.9.2 **/ void hb_font_set_scale (hb_font_t *font, - int x_scale, - int y_scale) + int x_scale, + int y_scale) { if (hb_object_is_immutable (font)) return; @@ -1720,18 +1926,18 @@ hb_font_set_scale (hb_font_t *font, /** * hb_font_get_scale: - * @font: a font. - * @x_scale: (out): - * @y_scale: (out): - * + * @font: #hb_font_t to work upon + * @x_scale: (out): Horizontal scale value + * @y_scale: (out): Vertical scale value * + * Fetches the horizontal and vertical scale of a font. * * Since: 0.9.2 **/ void hb_font_get_scale (hb_font_t *font, - int *x_scale, - int *y_scale) + int *x_scale, + int *y_scale) { if (x_scale) *x_scale = font->x_scale; if (y_scale) *y_scale = font->y_scale; @@ -1739,18 +1945,18 @@ hb_font_get_scale (hb_font_t *font, /** * hb_font_set_ppem: - * @font: a font. - * @x_ppem: - * @y_ppem: - * + * @font: #hb_font_t to work upon + * @x_ppem: Horizontal ppem value to assign + * @y_ppem: Vertical ppem value to assign * + * Sets the horizontal and vertical pixels-per-em (ppem) of a font. * * Since: 0.9.2 **/ void -hb_font_set_ppem (hb_font_t *font, - unsigned int x_ppem, - unsigned int y_ppem) +hb_font_set_ppem (hb_font_t *font, + unsigned int x_ppem, + unsigned int y_ppem) { if (hb_object_is_immutable (font)) return; @@ -1761,16 +1967,16 @@ hb_font_set_ppem (hb_font_t *font, /** * hb_font_get_ppem: - * @font: a font. - * @x_ppem: (out): - * @y_ppem: (out): - * + * @font: #hb_font_t to work upon + * @x_ppem: (out): Horizontal ppem value + * @y_ppem: (out): Vertical ppem value * + * Fetches the horizontal and vertical points-per-em (ppem) of a font. * * Since: 0.9.2 **/ void -hb_font_get_ppem (hb_font_t *font, +hb_font_get_ppem (hb_font_t *font, unsigned int *x_ppem, unsigned int *y_ppem) { @@ -1780,17 +1986,19 @@ hb_font_get_ppem (hb_font_t *font, /** * hb_font_set_ptem: - * @font: a font. + * @font: #hb_font_t to work upon * @ptem: font size in points. * - * Sets "point size" of the font. Set to 0 to unset. + * Sets the "point size" of a font. Set to zero to unset. + * Used in CoreText to implement optical sizing. * - * There are 72 points in an inch. + * Note: There are 72 points in an inch. * * Since: 1.6.0 **/ void -hb_font_set_ptem (hb_font_t *font, float ptem) +hb_font_set_ptem (hb_font_t *font, + float ptem) { if (hb_object_is_immutable (font)) return; @@ -1800,11 +2008,12 @@ hb_font_set_ptem (hb_font_t *font, float ptem) /** * hb_font_get_ptem: - * @font: a font. + * @font: #hb_font_t to work upon * - * Gets the "point size" of the font. A value of 0 means unset. + * Fetches the "point size" of a font. Used in CoreText to + * implement optical sizing. * - * Return value: Point size. + * Return value: Point size. A value of zero means "not set." * * Since: 0.9.2 **/ @@ -1819,26 +2028,20 @@ hb_font_get_ptem (hb_font_t *font) * Variations */ -static void -_hb_font_adopt_var_coords_normalized (hb_font_t *font, - int *coords, /* 2.14 normalized */ - unsigned int coords_length) -{ - free (font->coords); - - font->coords = coords; - font->num_coords = coords_length; -} - /** * hb_font_set_variations: + * @font: #hb_font_t to work upon + * @variations: (array length=variations_length): Array of variation settings to apply + * @variations_length: Number of variations to apply + * + * Applies a list of font-variation settings to a font. * * Since: 1.4.2 */ void -hb_font_set_variations (hb_font_t *font, +hb_font_set_variations (hb_font_t *font, const hb_variation_t *variations, - unsigned int variations_length) + unsigned int variations_length) { if (hb_object_is_immutable (font)) return; @@ -1852,34 +2055,66 @@ hb_font_set_variations (hb_font_t *font, unsigned int coords_length = hb_ot_var_get_axis_count (font->face); int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr; - if (unlikely (coords_length && !normalized)) + float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr; + + if (unlikely (coords_length && !(normalized && design_coords))) + { + free (normalized); + free (design_coords); return; + } - hb_ot_var_normalize_variations (font->face, - variations, variations_length, - normalized, coords_length); - _hb_font_adopt_var_coords_normalized (font, normalized, coords_length); + const OT::fvar &fvar = *font->face->table.fvar; + for (unsigned int i = 0; i < variations_length; i++) + { + hb_ot_var_axis_info_t info; + if (hb_ot_var_find_axis_info (font->face, variations[i].tag, &info) && + info.axis_index < coords_length) + { + float v = variations[i].value; + design_coords[info.axis_index] = v; + normalized[info.axis_index] = fvar.normalize_axis_value (info.axis_index, v); + } + } + font->face->table.avar->map_coords (normalized, coords_length); + + _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } /** * hb_font_set_var_coords_design: + * @font: #hb_font_t to work upon + * @coords: (array length=coords_length): Array of variation coordinates to apply + * @coords_length: Number of coordinates to apply + * + * Applies a list of variation coordinates (in design-space units) + * to a font. * * Since: 1.4.2 */ void -hb_font_set_var_coords_design (hb_font_t *font, - const float *coords, - unsigned int coords_length) +hb_font_set_var_coords_design (hb_font_t *font, + const float *coords, + unsigned int coords_length) { if (hb_object_is_immutable (font)) return; int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr; - if (unlikely (coords_length && !normalized)) + float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr; + + if (unlikely (coords_length && !(normalized && design_coords))) + { + free (normalized); + free (design_coords); return; + } + + if (coords_length) + memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); - _hb_font_adopt_var_coords_normalized (font, normalized, coords_length); + _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } /** @@ -1911,29 +2146,59 @@ hb_font_set_var_named_instance (hb_font_t *font, /** * hb_font_set_var_coords_normalized: + * @font: #hb_font_t to work upon + * @coords: (array length=coords_length): Array of variation coordinates to apply + * @coords_length: Number of coordinates to apply + * + * Applies a list of variation coordinates (in normalized units) + * to a font. + * + * Note: Coordinates should be normalized to 2.14. * * Since: 1.4.2 */ void -hb_font_set_var_coords_normalized (hb_font_t *font, - const int *coords, /* 2.14 normalized */ - unsigned int coords_length) +hb_font_set_var_coords_normalized (hb_font_t *font, + const int *coords, /* 2.14 normalized */ + unsigned int coords_length) { if (hb_object_is_immutable (font)) return; int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr; - if (unlikely (coords_length && !copy)) + int *unmapped = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr; + float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (design_coords[0])) : nullptr; + + if (unlikely (coords_length && !(copy && unmapped && design_coords))) + { + free (copy); + free (unmapped); + free (design_coords); return; + } if (coords_length) + { memcpy (copy, coords, coords_length * sizeof (coords[0])); + memcpy (unmapped, coords, coords_length * sizeof (coords[0])); + } + + /* Best effort design coords simulation */ + font->face->table.avar->unmap_coords (unmapped, coords_length); + for (unsigned int i = 0; i < coords_length; ++i) + design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]); + free (unmapped); - _hb_font_adopt_var_coords_normalized (font, copy, coords_length); + _hb_font_adopt_var_coords (font, copy, design_coords, coords_length); } /** * hb_font_get_var_coords_normalized: + * @font: #hb_font_t to work upon + * @length: Number of coordinates retrieved + * + * Fetches the list of normalized variation coordinates currently + * set on a font. * * Return value is valid as long as variation coordinates of the font * are not modified. @@ -1941,7 +2206,7 @@ hb_font_set_var_coords_normalized (hb_font_t *font, * Since: 1.4.2 */ const int * -hb_font_get_var_coords_normalized (hb_font_t *font, +hb_font_get_var_coords_normalized (hb_font_t *font, unsigned int *length) { if (length) @@ -1949,6 +2214,30 @@ hb_font_get_var_coords_normalized (hb_font_t *font, return font->coords; } + +#ifdef HB_EXPERIMENTAL_API +/** + * hb_font_get_var_coords_design: + * @font: #hb_font_t to work upon + * @length: (out): number of coordinates + * + * Return value is valid as long as variation coordinates of the font + * are not modified. + * + * Return value: coordinates array + * + * Since: EXPERIMENTAL + */ +const float * +hb_font_get_var_coords_design (hb_font_t *font, + unsigned int *length) +{ + if (length) + *length = font->num_coords; + + return font->design_coords; +} +#endif #endif #ifndef HB_DISABLE_DEPRECATED @@ -2013,23 +2302,23 @@ trampoline_destroy (void *user_data) typedef hb_trampoline_t hb_font_get_glyph_trampoline_t; static hb_bool_t -hb_font_get_nominal_glyph_trampoline (hb_font_t *font, - void *font_data, - hb_codepoint_t unicode, +hb_font_get_nominal_glyph_trampoline (hb_font_t *font, + void *font_data, + hb_codepoint_t unicode, hb_codepoint_t *glyph, - void *user_data) + void *user_data) { hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data; return trampoline->func (font, font_data, unicode, 0, glyph, trampoline->closure.user_data); } static hb_bool_t -hb_font_get_variation_glyph_trampoline (hb_font_t *font, - void *font_data, - hb_codepoint_t unicode, - hb_codepoint_t variation_selector, +hb_font_get_variation_glyph_trampoline (hb_font_t *font, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, hb_codepoint_t *glyph, - void *user_data) + void *user_data) { hb_font_get_glyph_trampoline_t *trampoline = (hb_font_get_glyph_trampoline_t *) user_data; return trampoline->func (font, font_data, unicode, variation_selector, glyph, trampoline->closure.user_data); @@ -2037,10 +2326,10 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font, /** * hb_font_funcs_set_glyph_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): callback function. - * @user_data: data to pass to @func. - * @destroy: function to call when @user_data is not needed anymore. + * @ffuncs: The font-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): callback function + * @user_data: data to pass to @func + * @destroy: (nullable): function to call when @user_data is not needed anymore * * Deprecated. Use hb_font_funcs_set_nominal_glyph_func() and * hb_font_funcs_set_variation_glyph_func() instead. @@ -2049,10 +2338,18 @@ hb_font_get_variation_glyph_trampoline (hb_font_t *font, * Deprecated: 1.2.3 **/ void -hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_func_t func, - void *user_data, hb_destroy_func_t destroy) +hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) { + if (hb_object_is_immutable (ffuncs)) + { + if (destroy) + destroy (user_data); + return; + } + hb_font_get_glyph_trampoline_t *trampoline; trampoline = trampoline_create (func, user_data, destroy); diff --git a/src/hb-font.h b/src/hb-font.h index 9b6518791e1a48c7a5a684f1332c1335978109df..15dc126523a42f0d223e8a95c2e101de3b568f7d 100644 --- a/src/hb-font.h +++ b/src/hb-font.h @@ -24,7 +24,7 @@ * Red Hat Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -33,10 +33,16 @@ #include "hb-common.h" #include "hb-face.h" +#include "hb-draw.h" HB_BEGIN_DECLS - +/** + * hb_font_t: + * + * Data type for holding fonts. + * + */ typedef struct hb_font_t hb_font_t; @@ -44,6 +50,19 @@ typedef struct hb_font_t hb_font_t; * hb_font_funcs_t */ +/** + * hb_font_funcs_t: + * + * Data type containing a set of virtual methods used for + * working on #hb_font_t font objects. + * + * HarfBuzz provides a lightweight default function for each of + * the methods in #hb_font_funcs_t. Client programs can implement + * their own replacements for the individual font functions, as + * needed, and replace the default by calling the setter for a + * method. + * + **/ typedef struct hb_font_funcs_t hb_font_funcs_t; HB_EXTERN hb_font_funcs_t * @@ -80,12 +99,21 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); /* font and glyph extents */ -/* Note that typically ascender is positive and descender negative in coordinate systems that grow up. */ -typedef struct hb_font_extents_t -{ - hb_position_t ascender; /* typographic ascender. */ - hb_position_t descender; /* typographic descender. */ - hb_position_t line_gap; /* suggested line spacing gap. */ +/** + * hb_font_extents_t: + * @ascender: The height of typographic ascenders. + * @descender: The depth of typographic descenders. + * @line_gap: The suggested line-spacing gap. + * + * Font-wide extent values, measured in font units. + * + * Note that typically @ascender is positive and @descender + * negative, in coordinate systems that grow up. + **/ +typedef struct hb_font_extents_t { + hb_position_t ascender; + hb_position_t descender; + hb_position_t line_gap; /*< private >*/ hb_position_t reserved9; hb_position_t reserved8; @@ -98,33 +126,130 @@ typedef struct hb_font_extents_t hb_position_t reserved1; } hb_font_extents_t; -/* Note that height is negative in coordinate systems that grow up. */ -typedef struct hb_glyph_extents_t -{ - hb_position_t x_bearing; /* left side of glyph from origin. */ - hb_position_t y_bearing; /* top side of glyph from origin. */ - hb_position_t width; /* distance from left to right side. */ - hb_position_t height; /* distance from top to bottom side. */ +/** + * hb_glyph_extents_t: + * @x_bearing: Distance from the x-origin to the left extremum of the glyph. + * @y_bearing: Distance from the top extremum of the glyph to the y-origin. + * @width: Distance from the left extremum of the glyph to the right extremum. + * @height: Distance from the top extremum of the glyph to the bottom extremum. + * + * Glyph extent values, measured in font units. + * + * Note that @height is negative, in coordinate systems that grow up. + **/ +typedef struct hb_glyph_extents_t { + hb_position_t x_bearing; + hb_position_t y_bearing; + hb_position_t width; + hb_position_t height; } hb_glyph_extents_t; /* func types */ +/** + * hb_font_get_font_extents_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @extents: (out): The font extents retrieved + * @user_data: User data pointer passed by the caller + * + * This method should retrieve the extents for a font. + * + **/ typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data, hb_font_extents_t *extents, void *user_data); + +/** + * hb_font_get_font_h_extents_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the extents for a font, for horizontal-direction + * text segments. Extents must be returned in an #hb_glyph_extents output + * parameter. + * + **/ typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t; + +/** + * hb_font_get_font_v_extents_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the extents for a font, for vertical-direction + * text segments. Extents must be returned in an #hb_glyph_extents output + * parameter. + * + **/ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t; +/** + * hb_font_get_nominal_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @unicode: The Unicode code point to query + * @glyph: (out): The glyph ID retrieved + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the nominal glyph ID for a specified Unicode code + * point. Glyph IDs must be returned in a #hb_codepoint_t output parameter. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t *glyph, void *user_data); + +/** + * hb_font_get_variation_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @unicode: The Unicode code point to query + * @variation_selector: The variation-selector code point to query + * @glyph: (out): The glyph ID retrieved + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the glyph ID for a specified Unicode code point + * followed by a specified Variation Selector code point. Glyph IDs must be + * returned in a #hb_codepoint_t output parameter. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph, void *user_data); + +/** + * hb_font_get_nominal_glyphs_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @count: number of code points to query + * @first_unicode: The first Unicode code point to query + * @unicode_stride: The stride between successive code points + * @first_glyph: (out): The first glyph ID retrieved + * @glyph_stride: The stride between successive glyph IDs + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the nominal glyph IDs for a sequence of + * Unicode code points. Glyph IDs must be returned in a #hb_codepoint_t + * output parameter. + * + * Return value: the number of code points processed + * + **/ typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data, unsigned int count, const hb_codepoint_t *first_unicode, @@ -133,13 +258,65 @@ typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void unsigned int glyph_stride, void *user_data); - +/** + * hb_font_get_glyph_advance_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the advance for a specified glyph. The + * method must return an #hb_position_t. + * + * Return value: The advance of @glyph within @font + * + **/ typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, void *user_data); + +/** + * hb_font_get_glyph_h_advance_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the advance for a specified glyph, in + * horizontal-direction text segments. Advances must be returned in + * an #hb_position_t output parameter. + * + **/ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t; + +/** + * hb_font_get_glyph_v_advance_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the advance for a specified glyph, in + * vertical-direction text segments. Advances must be returned in + * an #hb_position_t output parameter. + * + **/ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t; +/** + * hb_font_get_glyph_advances_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @count: The number of glyph IDs in the sequence queried + * @first_glyph: The first glyph ID to query + * @glyph_stride: The stride between successive glyph IDs + * @first_advance: (out): The first advance retrieved + * @advance_stride: The stride between successive advances + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the advances for a sequence of glyphs. + * + **/ typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data, unsigned int count, const hb_codepoint_t *first_glyph, @@ -147,36 +324,188 @@ typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_d hb_position_t *first_advance, unsigned advance_stride, void *user_data); + +/** + * hb_font_get_glyph_h_advances_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the advances for a sequence of glyphs, in + * horizontal-direction text segments. + * + **/ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t; + +/** + * hb_font_get_glyph_v_advances_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the advances for a sequence of glyphs, in + * vertical-direction text segments. + * + **/ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t; +/** + * hb_font_get_glyph_origin_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @x: (out): The X coordinate of the origin + * @y: (out): The Y coordinate of the origin + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in font units) of the + * origin for a glyph. Each coordinate must be returned in an #hb_position_t + * output parameter. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, void *user_data); + +/** + * hb_font_get_glyph_h_origin_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in font units) of the + * origin for a glyph, for horizontal-direction text segments. Each + * coordinate must be returned in an #hb_position_t output parameter. + * + **/ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t; + +/** + * hb_font_get_glyph_v_origin_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in font units) of the + * origin for a glyph, for vertical-direction text segments. Each coordinate + * must be returned in an #hb_position_t output parameter. + * + **/ typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t; +/** + * hb_font_get_glyph_kerning_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @first_glyph: The glyph ID of the first glyph in the glyph pair + * @second_glyph: The glyph ID of the second glyph in the glyph pair + * @user_data: User data pointer passed by the caller + * + * This method should retrieve the kerning-adjustment value for a glyph-pair in + * the specified font, for horizontal text segments. + * + **/ typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, void *user_data); +/** + * hb_font_get_glyph_h_kerning_func_t: + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the kerning-adjustment value for a glyph-pair in + * the specified font, for horizontal text segments. + * + **/ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; +/** + * hb_font_get_glyph_extents_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @extents: (out): The #hb_glyph_extents_t retrieved + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the extents for a specified glyph. Extents must be + * returned in an #hb_glyph_extents output parameter. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents, void *user_data); + +/** + * hb_font_get_glyph_contour_point_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @point_index: The contour-point index to query + * @x: (out): The X value retrieved for the contour point + * @y: (out): The Y value retrieved for the contour point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the (X,Y) coordinates (in font units) for a + * specified contour point in a glyph. Each coordinate must be returned as + * an #hb_position_t output parameter. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y, void *user_data); +/** + * hb_font_get_glyph_name_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @name: (out) (array length=size): Name string retrieved for the glyph ID + * @size: Length of the glyph-name string retrieved + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the glyph name that corresponds to a + * glyph ID. The name should be returned in a string output parameter. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, char *name, unsigned int size, void *user_data); + +/** + * hb_font_get_glyph_from_name_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @name: (array length=len): The name string to query + * @len: The length of the name queried + * @glyph: (out): The glyph ID retrieved + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * This method should retrieve the glyph ID that corresponds to a glyph-name + * string. + * + * Return value: %true if data found, %false otherwise + * + **/ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data, const char *name, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph, @@ -187,12 +516,12 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * /** * hb_font_funcs_set_font_h_extents_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_font_h_extents_func_t. * * Since: 1.1.2 **/ @@ -203,12 +532,12 @@ hb_font_funcs_set_font_h_extents_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_font_v_extents_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_font_v_extents_func_t. * * Since: 1.1.2 **/ @@ -219,12 +548,12 @@ hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_nominal_glyph_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_nominal_glyph_func_t. * * Since: 1.2.3 **/ @@ -235,12 +564,12 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_nominal_glyphs_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_nominal_glyphs_func_t. * * Since: 2.0.0 **/ @@ -251,12 +580,12 @@ hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_variation_glyph_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_variation_glyph_func_t. * * Since: 1.2.3 **/ @@ -267,12 +596,12 @@ hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_h_advance_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_h_advance_func_t. * * Since: 0.9.2 **/ @@ -283,12 +612,12 @@ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_v_advance_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_v_advance_func_t. * * Since: 0.9.2 **/ @@ -299,12 +628,12 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_h_advances_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_h_advances_func_t. * * Since: 1.8.6 **/ @@ -315,12 +644,12 @@ hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_v_advances_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_v_advances_func_t. * * Since: 1.8.6 **/ @@ -331,12 +660,12 @@ hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_h_origin_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_h_origin_func_t. * * Since: 0.9.2 **/ @@ -347,12 +676,12 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_v_origin_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_v_origin_func_t. * * Since: 0.9.2 **/ @@ -363,12 +692,12 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_h_kerning_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_h_kerning_func_t. * * Since: 0.9.2 **/ @@ -379,12 +708,12 @@ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_extents_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_extents_func_t. * * Since: 0.9.2 **/ @@ -395,12 +724,12 @@ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_contour_point_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_contour_point_func_t. * * Since: 0.9.2 **/ @@ -411,12 +740,12 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_name_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_name_func_t. * * Since: 0.9.2 **/ @@ -427,12 +756,12 @@ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs, /** * hb_font_funcs_set_glyph_from_name_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * + * Sets the implementation function for #hb_font_get_glyph_from_name_func_t. * * Since: 0.9.2 **/ @@ -459,6 +788,14 @@ hb_font_get_variation_glyph (hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph); +HB_EXTERN unsigned int +hb_font_get_nominal_glyphs (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride); + HB_EXTERN hb_position_t hb_font_get_glyph_h_advance (hb_font_t *font, hb_codepoint_t glyph); @@ -649,8 +986,8 @@ hb_font_set_funcs (hb_font_t *font, /* Be *very* careful with this function! */ HB_EXTERN void hb_font_set_funcs_data (hb_font_t *font, - void *font_data, - hb_destroy_func_t destroy); + void *font_data, + hb_destroy_func_t destroy); HB_EXTERN void @@ -696,6 +1033,12 @@ hb_font_set_var_coords_design (hb_font_t *font, const float *coords, unsigned int coords_length); +#ifdef HB_EXPERIMENTAL_API +HB_EXTERN const float * +hb_font_get_var_coords_design (hb_font_t *font, + unsigned int *length); +#endif + HB_EXTERN void hb_font_set_var_coords_normalized (hb_font_t *font, const int *coords, /* 2.14 normalized */ @@ -709,6 +1052,12 @@ HB_EXTERN void hb_font_set_var_named_instance (hb_font_t *font, unsigned instance_index); +#ifdef HB_EXPERIMENTAL_API +HB_EXTERN hb_bool_t +hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, + const hb_draw_funcs_t *funcs, void *user_data); +#endif + HB_END_DECLS #endif /* HB_FONT_H */ diff --git a/src/hb-font.hh b/src/hb-font.hh index 4adf6ae99a962b388fae07700f2771cc24904a25..8fc7f44d44b4fe86883d524101fb8d104c099559 100644 --- a/src/hb-font.hh +++ b/src/hb-font.hh @@ -120,6 +120,7 @@ struct hb_font_t /* Font variation coordinates. */ unsigned int num_coords; int *coords; + float *design_coords; hb_font_funcs_t *klass; void *user_data; @@ -216,7 +217,7 @@ struct hb_font_t } hb_bool_t get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) + hb_codepoint_t *glyph) { *glyph = 0; return klass->get.f.nominal_glyph (this, user_data, @@ -286,7 +287,7 @@ struct hb_font_t } hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y) { *x = *y = 0; return klass->get.f.glyph_h_origin (this, user_data, @@ -328,7 +329,7 @@ struct hb_font_t } hb_bool_t get_glyph_extents (hb_codepoint_t glyph, - hb_glyph_extents_t *extents) + hb_glyph_extents_t *extents) { memset (extents, 0, sizeof (*extents)); return klass->get.f.glyph_extents (this, user_data, @@ -338,7 +339,7 @@ struct hb_font_t } hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y) { *x = *y = 0; return klass->get.f.glyph_contour_point (this, user_data, @@ -499,7 +500,7 @@ struct hb_font_t } void subtract_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y) { hb_position_t origin_x, origin_y; diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 2d7f2b959b9e51d0e9e31ff80b69e6d8de5ff044..b82c1a67bd0e1d4b6ce26dca80a3564feef5e870 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -48,8 +48,13 @@ * @short_description: FreeType integration * @include: hb-ft.h * - * Functions for using HarfBuzz with the FreeType library to provide face and + * Functions for using HarfBuzz with the FreeType library. + * + * HarfBuzz supports using FreeType to provide face and * font data. + * + * Note that FreeType is not thread-safe, therefore these + * functions are not thread-safe either. **/ @@ -79,7 +84,7 @@ struct hb_ft_font_t bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ - mutable hb_atomic_int_t cached_x_scale; + mutable int cached_x_scale; mutable hb_advance_cache_t advance_cache; }; @@ -87,9 +92,7 @@ static hb_ft_font_t * _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) { hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t)); - - if (unlikely (!ft_font)) - return nullptr; + if (unlikely (!ft_font)) return nullptr; ft_font->lock.init (); ft_font->ft_face = ft_face; @@ -98,7 +101,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; - ft_font->cached_x_scale.set_relaxed (0); + ft_font->cached_x_scale = 0; ft_font->advance_cache.init (); return ft_font; @@ -127,10 +130,13 @@ _hb_ft_font_destroy (void *data) /** * hb_ft_font_set_load_flags: - * @font: - * @load_flags: + * @font: #hb_font_t to work upon + * @load_flags: The FreeType load flags to set * + * Sets the FT_Load_Glyph load flags for the specified #hb_font_t. * + * For more information, see + * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * * Since: 1.0.5 **/ @@ -140,7 +146,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) if (hb_object_is_immutable (font)) return; - if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) return; hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; @@ -150,17 +156,21 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) /** * hb_ft_font_get_load_flags: - * @font: + * @font: #hb_font_t to work upon * + * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t. * + * For more information, see + * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx + * + * Return value: FT_Load_Glyph flags found * - * Return value: * Since: 1.0.5 **/ int hb_ft_font_get_load_flags (hb_font_t *font) { - if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) return 0; const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; @@ -168,10 +178,21 @@ hb_ft_font_get_load_flags (hb_font_t *font) return ft_font->load_flags; } +/** + * hb_ft_font_get_face: + * @font: #hb_font_t to work upon + * + * Fetches the FT_Face associated with the specified #hb_font_t + * font object. + * + * Return value: (nullable): the FT_Face found or %NULL + * + * Since: 0.9.2 + **/ FT_Face hb_ft_font_get_face (hb_font_t *font) { - if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) return nullptr; const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; @@ -179,6 +200,47 @@ hb_ft_font_get_face (hb_font_t *font) return ft_font->ft_face; } +/** + * hb_ft_font_lock_face: + * @font: #hb_font_t to work upon + * + * Gets the FT_Face associated with @font, This face will be kept around until + * you call hb_ft_font_unlock_face(). + * + * Return value: (nullable): the FT_Face associated with @font or %NULL + * Since: 2.6.5 + **/ +FT_Face +hb_ft_font_lock_face (hb_font_t *font) +{ + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) + return nullptr; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + ft_font->lock.lock (); + + return ft_font->ft_face; +} + +/** + * hb_ft_font_unlock_face: + * @font: #hb_font_t to work upon + * + * Releases an FT_Face previously obtained with hb_ft_font_lock_face(). + * + * Since: 2.6.5 + **/ +void +hb_ft_font_unlock_face (hb_font_t *font) +{ + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) + return; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + ft_font->lock.unlock (); +} static hb_bool_t @@ -273,10 +335,10 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, int load_flags = ft_font->load_flags; int mult = font->x_scale < 0 ? -1 : +1; - if (font->x_scale != ft_font->cached_x_scale.get ()) + if (font->x_scale != ft_font->cached_x_scale) { ft_font->advance_cache.clear (); - ft_font->cached_x_scale.set (font->x_scale); + ft_font->cached_x_scale = font->x_scale; } for (unsigned int i = 0; i < count; i++) @@ -471,7 +533,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, /* Check whether the given name was actually the name of glyph 0. */ char buf[128]; if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) && - len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) + len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) return true; } @@ -556,9 +618,12 @@ _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) { bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL; + hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref); + if (unlikely (!ft_font)) return; + hb_font_set_funcs (font, _hb_ft_get_font_funcs (), - _hb_ft_font_create (ft_face, symbol, unref), + ft_font, _hb_ft_font_destroy); } @@ -595,12 +660,22 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data /** * hb_ft_face_create: - * @ft_face: (destroy destroy) (scope notified): - * @destroy: + * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon + * @destroy: (nullable): A callback to call when the face object is not needed anymore * + * Creates an #hb_face_t face object from the specified FT_Face. * + * This variant of the function does not provide any life-cycle management. + * + * Most client programs should use hb_ft_face_create_referenced() + * (or, perhaps, hb_ft_face_create_cached()) instead. + * + * If you know you have valid reasons not to use hb_ft_face_create_referenced(), + * then it is the client program's responsibility to destroy @ft_face + * after the #hb_face_t face object has been destroyed. + * + * Return value: (transfer full): the new #hb_face_t face object * - * Return value: (transfer full): * Since: 0.9.2 **/ hb_face_t * @@ -630,11 +705,20 @@ hb_ft_face_create (FT_Face ft_face, /** * hb_ft_face_create_referenced: - * @ft_face: + * @ft_face: FT_Face to work upon + * + * Creates an #hb_face_t face object from the specified FT_Face. * + * This is the preferred variant of the hb_ft_face_create* + * function family, because it calls FT_Reference_Face() on @ft_face, + * ensuring that @ft_face remains alive as long as the resulting + * #hb_face_t face object remains alive. Also calls FT_Done_Face() + * when the #hb_face_t face object is destroyed. * + * Use this version unless you know you have good reasons not to. + * + * Return value: (transfer full): the new #hb_face_t face object * - * Return value: (transfer full): * Since: 0.9.38 **/ hb_face_t * @@ -652,11 +736,21 @@ hb_ft_face_finalize (FT_Face ft_face) /** * hb_ft_face_create_cached: - * @ft_face: + * @ft_face: FT_Face to work upon + * + * Creates an #hb_face_t face object from the specified FT_Face. + * + * This variant of the function caches the newly created #hb_face_t + * face object, using the @generic pointer of @ft_face. Subsequent function + * calls that are passed the same @ft_face parameter will have the same + * #hb_face_t returned to them, and that #hb_face_t will be correctly + * reference counted. * + * However, client programs are still responsible for destroying + * @ft_face after the last #hb_face_t face object has been destroyed. * + * Return value: (transfer full): the new #hb_face_t face object * - * Return value: (transfer full): * Since: 0.9.2 **/ hb_face_t * @@ -674,15 +768,34 @@ hb_ft_face_create_cached (FT_Face ft_face) return hb_face_reference ((hb_face_t *) ft_face->generic.data); } - /** * hb_ft_font_create: - * @ft_face: (destroy destroy) (scope notified): - * @destroy: + * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon + * @destroy: (nullable): A callback to call when the font object is not needed anymore + * + * Creates an #hb_font_t font object from the specified FT_Face. + * + * Note: You must set the face size on @ft_face before calling + * hb_ft_font_create() on it. HarfBuzz assumes size is always set and will + * access `size` member of FT_Face unconditionally. + * + * This variant of the function does not provide any life-cycle management. + * + * Most client programs should use hb_ft_font_create_referenced() + * instead. + * + * If you know you have valid reasons not to use hb_ft_font_create_referenced(), + * then it is the client program's responsibility to destroy @ft_face + * after the #hb_font_t font object has been destroyed. * + * HarfBuzz will use the @destroy callback on the #hb_font_t font object + * if it is supplied when you use this function. However, even if @destroy + * is provided, it is the client program's responsibility to destroy @ft_face, + * and it is the client program's responsibility to ensure that @ft_face is + * destroyed only after the #hb_font_t font object has been destroyed. * + * Return value: (transfer full): the new #hb_font_t font object * - * Return value: (transfer full): * Since: 0.9.2 **/ hb_font_t * @@ -700,6 +813,16 @@ hb_ft_font_create (FT_Face ft_face, return font; } +/** + * hb_ft_font_changed: + * @font: #hb_font_t to work upon + * + * Refreshes the state of @font when the underlying FT_Face has changed. + * This function should be called after changing the size or + * variation-axis settings on the FT_Face. + * + * Since: 1.0.5 + **/ void hb_ft_font_changed (hb_font_t *font) { @@ -707,6 +830,7 @@ hb_ft_font_changed (hb_font_t *font) return; hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + FT_Face ft_face = ft_font->ft_face; hb_font_set_scale (font, @@ -718,7 +842,7 @@ hb_ft_font_changed (hb_font_t *font) ft_face->size->metrics.y_ppem); #endif -#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES +#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) FT_MM_Var *mm_var = nullptr; if (!FT_Get_MM_Var (ft_face, &mm_var)) { @@ -755,11 +879,23 @@ hb_ft_font_changed (hb_font_t *font) /** * hb_ft_font_create_referenced: - * @ft_face: + * @ft_face: FT_Face to work upon + * + * Creates an #hb_font_t font object from the specified FT_Face. + * + * Note: You must set the face size on @ft_face before calling + * hb_ft_font_create_referenced() on it. HarfBuzz assumes size is always set + * and will access `size` member of FT_Face unconditionally. + * + * This is the preferred variant of the hb_ft_font_create* + * function family, because it calls FT_Reference_Face() on @ft_face, + * ensuring that @ft_face remains alive as long as the resulting + * #hb_font_t font object remains alive. * + * Use this version unless you know you have good reasons not to. * + * Return value: (transfer full): the new #hb_font_t font object * - * Return value: (transfer full): * Since: 0.9.38 **/ hb_font_t * @@ -818,6 +954,28 @@ _release_blob (FT_Face ft_face) hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); } +/** + * hb_ft_font_set_funcs: + * @font: #hb_font_t to work upon + * + * Configures the font-functions structure of the specified + * #hb_font_t font object to use FreeType font functions. + * + * In particular, you can use this function to configure an + * existing #hb_face_t face object for use with FreeType font + * functions even if that #hb_face_t face object was initially + * created with hb_face_create(), and therefore was not + * initially configured to use FreeType font functions. + * + * An #hb_face_t face object created with hb_ft_face_create() + * is preconfigured for FreeType font functions and does not + * require this function to be used. + * + * Note: Internally, this function creates an FT_Face. +* + * + * Since: 1.0.5 + **/ void hb_ft_font_set_funcs (hb_font_t *font) { @@ -840,8 +998,8 @@ hb_ft_font_set_funcs (hb_font_t *font) return; } - if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE)) - FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL); + if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) + FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); FT_Set_Char_Size (ft_face, abs (font->x_scale), abs (font->y_scale), @@ -857,7 +1015,7 @@ hb_ft_font_set_funcs (hb_font_t *font) FT_Set_Transform (ft_face, &matrix, nullptr); } -#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES +#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) unsigned int num_coords; const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); if (num_coords) @@ -866,7 +1024,7 @@ hb_ft_font_set_funcs (hb_font_t *font) if (ft_coords) { for (unsigned int i = 0; i < num_coords; i++) - ft_coords[i] = coords[i] << 2; + ft_coords[i] = coords[i] * 4; FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords); free (ft_coords); } diff --git a/src/hb-ft.h b/src/hb-ft.h index 94013eeb915ee90b0765d1d9496a0cbe9033d0a9..bf07115ab92fefb65f2609d1149bdf15a2c66318 100644 --- a/src/hb-ft.h +++ b/src/hb-ft.h @@ -110,6 +110,12 @@ hb_ft_font_create_referenced (FT_Face ft_face); HB_EXTERN FT_Face hb_ft_font_get_face (hb_font_t *font); +HB_EXTERN FT_Face +hb_ft_font_lock_face (hb_font_t *font); + +HB_EXTERN void +hb_ft_font_unlock_face (hb_font_t *font); + HB_EXTERN void hb_ft_font_set_load_flags (hb_font_t *font, int load_flags); diff --git a/src/hb-gdi.cc b/src/hb-gdi.cc index d55085cb4429ae93b8eaf6b36402e6971fe73e1b..dc4659c7f626a3b67625e25f262726158d7801f7 100644 --- a/src/hb-gdi.cc +++ b/src/hb-gdi.cc @@ -28,6 +28,16 @@ #include "hb-gdi.h" + +/** + * SECTION:hb-gdi + * @title: hb-gdi + * @short_description: GDI integration + * @include: hb-gdi.h + * + * Functions for using HarfBuzz with GDI fonts. + **/ + static hb_blob_t * _hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { @@ -58,7 +68,9 @@ fail: /** * hb_gdi_face_create: - * @hdc: a HFONT object. + * @hfont: a HFONT object. + * + * Constructs a new face object from the specified GDI HFONT. * * Return value: #hb_face_t object corresponding to the given input * diff --git a/src/hb-glib.cc b/src/hb-glib.cc index db02b6760e3d995a920188b38162ba2696053409..f93bb8853caaa247b0ebe0f684724b62539aaf0b 100644 --- a/src/hb-glib.cc +++ b/src/hb-glib.cc @@ -41,166 +41,46 @@ * @short_description: GLib integration * @include: hb-glib.h * - * Functions for using HarfBuzz with the GLib library to provide Unicode data. + * Functions for using HarfBuzz with the GLib library. + * + * HarfBuzz supports using GLib to provide Unicode data, by attaching + * GLib functions to the virtual methods in a #hb_unicode_funcs_t function + * structure. **/ -#if !GLIB_CHECK_VERSION(2,29,14) -static const hb_script_t -glib_script_to_script[] = -{ - HB_SCRIPT_COMMON, - HB_SCRIPT_INHERITED, - HB_SCRIPT_ARABIC, - HB_SCRIPT_ARMENIAN, - HB_SCRIPT_BENGALI, - HB_SCRIPT_BOPOMOFO, - HB_SCRIPT_CHEROKEE, - HB_SCRIPT_COPTIC, - HB_SCRIPT_CYRILLIC, - HB_SCRIPT_DESERET, - HB_SCRIPT_DEVANAGARI, - HB_SCRIPT_ETHIOPIC, - HB_SCRIPT_GEORGIAN, - HB_SCRIPT_GOTHIC, - HB_SCRIPT_GREEK, - HB_SCRIPT_GUJARATI, - HB_SCRIPT_GURMUKHI, - HB_SCRIPT_HAN, - HB_SCRIPT_HANGUL, - HB_SCRIPT_HEBREW, - HB_SCRIPT_HIRAGANA, - HB_SCRIPT_KANNADA, - HB_SCRIPT_KATAKANA, - HB_SCRIPT_KHMER, - HB_SCRIPT_LAO, - HB_SCRIPT_LATIN, - HB_SCRIPT_MALAYALAM, - HB_SCRIPT_MONGOLIAN, - HB_SCRIPT_MYANMAR, - HB_SCRIPT_OGHAM, - HB_SCRIPT_OLD_ITALIC, - HB_SCRIPT_ORIYA, - HB_SCRIPT_RUNIC, - HB_SCRIPT_SINHALA, - HB_SCRIPT_SYRIAC, - HB_SCRIPT_TAMIL, - HB_SCRIPT_TELUGU, - HB_SCRIPT_THAANA, - HB_SCRIPT_THAI, - HB_SCRIPT_TIBETAN, - HB_SCRIPT_CANADIAN_SYLLABICS, - HB_SCRIPT_YI, - HB_SCRIPT_TAGALOG, - HB_SCRIPT_HANUNOO, - HB_SCRIPT_BUHID, - HB_SCRIPT_TAGBANWA, - - /* Unicode-4.0 additions */ - HB_SCRIPT_BRAILLE, - HB_SCRIPT_CYPRIOT, - HB_SCRIPT_LIMBU, - HB_SCRIPT_OSMANYA, - HB_SCRIPT_SHAVIAN, - HB_SCRIPT_LINEAR_B, - HB_SCRIPT_TAI_LE, - HB_SCRIPT_UGARITIC, - - /* Unicode-4.1 additions */ - HB_SCRIPT_NEW_TAI_LUE, - HB_SCRIPT_BUGINESE, - HB_SCRIPT_GLAGOLITIC, - HB_SCRIPT_TIFINAGH, - HB_SCRIPT_SYLOTI_NAGRI, - HB_SCRIPT_OLD_PERSIAN, - HB_SCRIPT_KHAROSHTHI, - - /* Unicode-5.0 additions */ - HB_SCRIPT_UNKNOWN, - HB_SCRIPT_BALINESE, - HB_SCRIPT_CUNEIFORM, - HB_SCRIPT_PHOENICIAN, - HB_SCRIPT_PHAGS_PA, - HB_SCRIPT_NKO, - - /* Unicode-5.1 additions */ - HB_SCRIPT_KAYAH_LI, - HB_SCRIPT_LEPCHA, - HB_SCRIPT_REJANG, - HB_SCRIPT_SUNDANESE, - HB_SCRIPT_SAURASHTRA, - HB_SCRIPT_CHAM, - HB_SCRIPT_OL_CHIKI, - HB_SCRIPT_VAI, - HB_SCRIPT_CARIAN, - HB_SCRIPT_LYCIAN, - HB_SCRIPT_LYDIAN, - - /* Unicode-5.2 additions */ - HB_SCRIPT_AVESTAN, - HB_SCRIPT_BAMUM, - HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, - HB_SCRIPT_IMPERIAL_ARAMAIC, - HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, - HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, - HB_SCRIPT_JAVANESE, - HB_SCRIPT_KAITHI, - HB_SCRIPT_TAI_THAM, - HB_SCRIPT_LISU, - HB_SCRIPT_MEETEI_MAYEK, - HB_SCRIPT_OLD_SOUTH_ARABIAN, - HB_SCRIPT_OLD_TURKIC, - HB_SCRIPT_SAMARITAN, - HB_SCRIPT_TAI_VIET, - - /* Unicode-6.0 additions */ - HB_SCRIPT_BATAK, - HB_SCRIPT_BRAHMI, - HB_SCRIPT_MANDAIC, - - /* Unicode-6.1 additions */ - HB_SCRIPT_CHAKMA, - HB_SCRIPT_MEROITIC_CURSIVE, - HB_SCRIPT_MEROITIC_HIEROGLYPHS, - HB_SCRIPT_MIAO, - HB_SCRIPT_SHARADA, - HB_SCRIPT_SORA_SOMPENG, - HB_SCRIPT_TAKRI -}; -#endif - +/** + * hb_glib_script_to_script: + * @script: The GUnicodeScript identifier to query + * + * Fetches the #hb_script_t script that corresponds to the + * specified GUnicodeScript identifier. + * + * Return value: the #hb_script_t script found + * + * Since: 0.9.38 + **/ hb_script_t hb_glib_script_to_script (GUnicodeScript script) { -#if GLIB_CHECK_VERSION(2,29,14) return (hb_script_t) g_unicode_script_to_iso15924 (script); -#else - if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script))) - return glib_script_to_script[script]; - - if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE)) - return HB_SCRIPT_INVALID; - - return HB_SCRIPT_UNKNOWN; -#endif } +/** + * hb_glib_script_from_script: + * @script: The #hb_script_t to query + * + * Fetches the GUnicodeScript identifier that corresponds to the + * specified #hb_script_t script. + * + * Return value: the GUnicodeScript identifier found + * + * Since: 0.9.38 + **/ GUnicodeScript hb_glib_script_from_script (hb_script_t script) { -#if GLIB_CHECK_VERSION(2,29,14) return g_unicode_script_from_iso15924 (script); -#else - unsigned int count = ARRAY_LENGTH (glib_script_to_script); - for (unsigned int i = 0; i < count; i++) - if (glib_script_to_script[i] == script) - return (GUnicodeScript) i; - - if (unlikely (script == HB_SCRIPT_INVALID)) - return G_UNICODE_SCRIPT_INVALID_CODE; - - return G_UNICODE_SCRIPT_UNKNOWN; -#endif } @@ -373,6 +253,16 @@ void free_static_glib_funcs () } #endif +/** + * hb_glib_get_unicode_funcs: + * + * Fetches a Unicode-functions structure that is populated + * with the appropriate GLib function for each method. + * + * Return value: (transfer none): a pointer to the #hb_unicode_funcs_t Unicode-functions structure + * + * Since: 0.9.38 + **/ hb_unicode_funcs_t * hb_glib_get_unicode_funcs () { @@ -391,6 +281,12 @@ _hb_g_bytes_unref (void *data) /** * hb_glib_blob_create: + * @gbytes: the GBytes structure to work upon + * + * Creates an #hb_blob_t blob from the specified + * GBytes data structure. + * + * Return value: (transfer full): the new #hb_blob_t blob object * * Since: 0.9.38 **/ diff --git a/src/hb-gobject-enums.cc.tmpl b/src/hb-gobject-enums.cc.tmpl index 17f1adeb1dc4265e8602589c935f379065a0ab16..87a11dd407ebc220172f359a1af631325c6b2864 100644 --- a/src/hb-gobject-enums.cc.tmpl +++ b/src/hb-gobject-enums.cc.tmpl @@ -1,6 +1,6 @@ /*** BEGIN file-header ***/ /* - * Copyright © 2011 Google, Inc. + * Copyright (C) 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -43,7 +43,7 @@ /*** END file-header ***/ /*** BEGIN file-production ***/ -/* enumerations from "@filename@" */ +/* enumerations from "@basename@" */ /*** END file-production ***/ /*** BEGIN file-tail ***/ diff --git a/src/hb-gobject-enums.h.tmpl b/src/hb-gobject-enums.h.tmpl index 7ef9dfc02959868d8004537f409355b67d926780..a8467868bdbb3dc45743b2b3e44a8c484b065f11 100644 --- a/src/hb-gobject-enums.h.tmpl +++ b/src/hb-gobject-enums.h.tmpl @@ -1,6 +1,6 @@ /*** BEGIN file-header ***/ /* - * Copyright © 2013 Google, Inc. + * Copyright (C) 2013 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -25,7 +25,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_GOBJECT_H_IN +#if !defined(HB_GOBJECT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif diff --git a/src/hb-gobject-structs.cc b/src/hb-gobject-structs.cc index 7f4922ef19217854765180547738901d8b479b56..7c46e2640076f308b9e6286f0ebc47d86325e65c 100644 --- a/src/hb-gobject-structs.cc +++ b/src/hb-gobject-structs.cc @@ -32,11 +32,20 @@ /** * SECTION:hb-gobject * @title: hb-gobject - * @short_description: GObject integration + * @short_description: GObject integration support * @include: hb-gobject.h * - * Functions for using HarfBuzz with the GObject library to provide + * Support for using HarfBuzz with the GObject library to provide * type data. + * + * The types and functions listed here are solely a linkage between + * HarfBuzz's public data types and the GTypes used by the GObject framework. + * HarfBuzz uses GObject introspection to generate its Python bindings + * (and potentially other language bindings); client programs should never need + * to access the GObject-integration mechanics. + * + * For client programs using the GNOME and GTK software stack, please see the + * GLib and FreeType integration pages. **/ diff --git a/src/hb-gobject-structs.h b/src/hb-gobject-structs.h index 800beede0f1c647c2698a5c20416f53863ea7153..63467f80dfdfebc20627c4d1cd3ed7b451af6296 100644 --- a/src/hb-gobject-structs.h +++ b/src/hb-gobject-structs.h @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright (C) 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_GOBJECT_H_IN +#if !defined(HB_GOBJECT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -40,47 +40,22 @@ HB_BEGIN_DECLS /* Object types */ -/** - * hb_gobject_blob_get_type: - * - * Since: 0.9.2 - **/ HB_EXTERN GType hb_gobject_blob_get_type (void); #define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ()) -/** - * hb_gobject_buffer_get_type: - * - * Since: 0.9.2 - **/ HB_EXTERN GType hb_gobject_buffer_get_type (void); #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ()) -/** - * hb_gobject_face_get_type: - * - * Since: 0.9.2 - **/ HB_EXTERN GType hb_gobject_face_get_type (void); #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ()) -/** - * hb_gobject_font_get_type: - * - * Since: 0.9.2 - **/ HB_EXTERN GType hb_gobject_font_get_type (void); #define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ()) -/** - * hb_gobject_font_funcs_get_type: - * - * Since: 0.9.2 - **/ HB_EXTERN GType hb_gobject_font_funcs_get_type (void); #define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ()) @@ -97,11 +72,6 @@ HB_EXTERN GType hb_gobject_shape_plan_get_type (void); #define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ()) -/** - * hb_gobject_unicode_funcs_get_type: - * - * Since: 0.9.2 - **/ HB_EXTERN GType hb_gobject_unicode_funcs_get_type (void); #define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ()) diff --git a/src/hb-gobject.h b/src/hb-gobject.h index ea1bd25df82d46a222436a1ad078d0fc95d5c303..8891aa0ee798ede9cb8abc2f180e47936b9c88c4 100644 --- a/src/hb-gobject.h +++ b/src/hb-gobject.h @@ -1,5 +1,5 @@ /* - * Copyright © 2011 Google, Inc. + * Copyright (C) 2011 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index 40ac9061ff2d4c58f0bba57b44019721d2a23749..9dafe654c87ea10a0a7f7119150d50331ea33340 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -45,7 +45,11 @@ * @short_description: Graphite2 integration * @include: hb-graphite2.h * - * Functions for using HarfBuzz with the Graphite2 fonts. + * Functions for using HarfBuzz with fonts that include Graphite features. + * + * For Graphite features to work, you must be sure that HarfBuzz was compiled + * with the `graphite2` shaping engine enabled. Currently, the default is to + * not enable `graphite2` shaping. **/ @@ -152,7 +156,15 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data) free (data); } -/* +/** + * hb_graphite2_face_get_gr_face: + * @face: @hb_face_t to query + * + * Fetches the Graphite2 gr_face corresponding to the specified + * #hb_face_t face object. + * + * Return value: the gr_face found + * * Since: 0.9.10 */ gr_face * @@ -183,6 +195,11 @@ _hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED #ifndef HB_DISABLE_DEPRECATED /** * hb_graphite2_font_get_gr_font: + * @font: An #hb_font_t + * + * Always returns %NULL. Use hb_graphite2_face_get_gr_face() instead. + * + * Return value: (nullable): Graphite2 font associated with @font. * * Since: 0.9.10 * Deprecated: 1.4.2 @@ -272,7 +289,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, return true; } - buffer->ensure (glyph_count); + (void) buffer->ensure (glyph_count); scratch = buffer->get_scratch_buffer (&scratch_size); while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) + DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size) @@ -340,14 +357,14 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, c->num_glyphs = 0; if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) { - c->advance = curradv - gr_slot_origin_X(is) * xscale; - curradv -= c->advance; + c->advance = curradv - gr_slot_origin_X(is) * xscale; + curradv -= c->advance; } else { - c->advance = 0; - clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv; - curradv += clusters[ci].advance; + c->advance = 0; + clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv; + curradv += clusters[ci].advance; } ci++; } @@ -376,7 +393,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, buffer->len = glyph_count; /* Positioning. */ - unsigned int currclus = (unsigned int) -1; + unsigned int currclus = UINT_MAX; const hb_glyph_info_t *info = buffer->info; hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr); if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction)) diff --git a/src/hb-graphite2.h b/src/hb-graphite2.h index 1720191b42fe16f141962288b132fc052a83f608..f299da9f71c97d3d860f3bfbdeca0c8645deb779 100644 --- a/src/hb-graphite2.h +++ b/src/hb-graphite2.h @@ -32,7 +32,15 @@ HB_BEGIN_DECLS - +/** + * HB_GRAPHITE2_TAG_SILF: + * + * The #hb_tag_t tag for the `Silf` table, which holds Graphite + * features. + * + * For more information, see http://graphite.sil.org/ + * + **/ #define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f') diff --git a/src/hb-icu.cc b/src/hb-icu.cc index e98908de74323ddadcab5e20c35dbf807f283c98..008a39e414c2900b8043e88f477de114fc78018c 100644 --- a/src/hb-icu.cc +++ b/src/hb-icu.cc @@ -41,6 +41,12 @@ #include #include +/* ICU extra semicolon, fixed since 65, https://github.com/unicode-org/icu/commit/480bec3 */ +#if U_ICU_VERSION_MAJOR_NUM < 65 && (defined(__GNUC__) || defined(__clang__)) +#define HB_ICU_EXTRA_SEMI_IGNORED +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wextra-semi-stmt" +#endif /** * SECTION:hb-icu @@ -48,12 +54,22 @@ * @short_description: ICU integration * @include: hb-icu.h * - * Functions for using HarfBuzz with the ICU library to provide Unicode data. + * Functions for using HarfBuzz with the International Components for Unicode + * (ICU) library. HarfBuzz supports using ICU to provide Unicode data, by attaching + * ICU functions to the virtual methods in a #hb_unicode_funcs_t function + * structure. **/ -/* ICU doesn't do-while(0) around their statements. Ugh! - * https://unicode-org.atlassian.net/browse/CLDR-13027 */ -#define HB_ICU_STMT(S) do { S } while (0) +/** + * hb_icu_script_to_script: + * @script: The UScriptCode identifier to query + * + * Fetches the #hb_script_t script that corresponds to the + * specified UScriptCode identifier. + * + * Return value: the #hb_script_t script found + * + **/ hb_script_t hb_icu_script_to_script (UScriptCode script) @@ -64,6 +80,16 @@ hb_icu_script_to_script (UScriptCode script) return hb_script_from_string (uscript_getShortName (script), -1); } +/** + * hb_icu_script_from_script: + * @script: The #hb_script_t script to query + * + * Fetches the UScriptCode identifier that corresponds to the + * specified #hb_script_t script. + * + * Return value: the UScriptCode identifier found + * + **/ UScriptCode hb_icu_script_from_script (hb_script_t script) { @@ -166,45 +192,13 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab, - void *user_data HB_UNUSED) + void *user_data) { -#if U_ICU_VERSION_MAJOR_NUM >= 49 - { - const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data; - UChar32 ret = unorm2_composePair (normalizer, a, b); - if (ret < 0) return false; - *ab = ret; - return true; - } -#endif - - /* We don't ifdef-out the fallback code such that compiler always - * sees it and makes sure it's compilable. */ - - UChar utf16[4], normalized[5]; - unsigned int len; - hb_bool_t ret, err; - UErrorCode icu_err; - - len = 0; - err = false; - HB_ICU_STMT (U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err)); - if (err) return false; - HB_ICU_STMT (U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err)); - if (err) return false; - - icu_err = U_ZERO_ERROR; - len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err); - if (U_FAILURE (icu_err)) - return false; - if (u_countChar32 (normalized, len) == 1) { - HB_ICU_STMT (U16_GET_UNSAFE (normalized, 0, *ab)); - ret = true; - } else { - ret = false; - } - - return ret; + const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data; + UChar32 ret = unorm2_composePair (normalizer, a, b); + if (ret < 0) return false; + *ab = ret; + return true; } static hb_bool_t @@ -212,97 +206,30 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b, - void *user_data HB_UNUSED) + void *user_data) { -#if U_ICU_VERSION_MAJOR_NUM >= 49 + const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data; + UChar decomposed[4]; + int len; + UErrorCode icu_err = U_ZERO_ERROR; + len = unorm2_getRawDecomposition (normalizer, ab, decomposed, + ARRAY_LENGTH (decomposed), &icu_err); + if (U_FAILURE (icu_err) || len < 0) return false; + + len = u_countChar32 (decomposed, len); + if (len == 1) { - const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data; - UChar decomposed[4]; - int len; - UErrorCode icu_err = U_ZERO_ERROR; - len = unorm2_getRawDecomposition (normalizer, ab, decomposed, - ARRAY_LENGTH (decomposed), &icu_err); - if (U_FAILURE (icu_err) || len < 0) return false; - - len = u_countChar32 (decomposed, len); - if (len == 1) { - HB_ICU_STMT (U16_GET_UNSAFE (decomposed, 0, *a)); - *b = 0; - return *a != ab; - } else if (len == 2) { - len =0; - HB_ICU_STMT (U16_NEXT_UNSAFE (decomposed, len, *a)); - HB_ICU_STMT (U16_NEXT_UNSAFE (decomposed, len, *b)); - } - return true; - } -#endif - - /* We don't ifdef-out the fallback code such that compiler always - * sees it and makes sure it's compilable. */ - - UChar utf16[2], normalized[2 * 19/*HB_UNICODE_MAX_DECOMPOSITION_LEN*/ + 1]; - unsigned int len; - hb_bool_t ret, err; - UErrorCode icu_err; - - /* This function is a monster! Maybe it wasn't a good idea adding a - * pairwise decompose API... */ - /* Watchout for the dragons. Err, watchout for macros changing len. */ - - len = 0; - err = false; - HB_ICU_STMT (U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err)); - if (err) return false; - - icu_err = U_ZERO_ERROR; - len = unorm2_normalize (unorm2_getNFDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err); - if (U_FAILURE (icu_err)) - return false; - - len = u_countChar32 (normalized, len); - - if (len == 1) { - HB_ICU_STMT (U16_GET_UNSAFE (normalized, 0, *a)); + U16_GET_UNSAFE (decomposed, 0, *a); *b = 0; - ret = *a != ab; - } else if (len == 2) { - len =0; - HB_ICU_STMT (U16_NEXT_UNSAFE (normalized, len, *a)); - HB_ICU_STMT (U16_NEXT_UNSAFE (normalized, len, *b)); - - /* Here's the ugly part: if ab decomposes to a single character and - * that character decomposes again, we have to detect that and undo - * the second part :-(. */ - UChar recomposed[20]; - icu_err = U_ZERO_ERROR; - unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err); - if (U_FAILURE (icu_err)) - return false; - hb_codepoint_t c; - HB_ICU_STMT (U16_GET_UNSAFE (recomposed, 0, c)); - if (c != *a && c != ab) { - *a = c; - *b = 0; - } - ret = true; - } else { - /* If decomposed to more than two characters, take the last one, - * and recompose the rest to get the first component. */ - HB_ICU_STMT (U16_PREV_UNSAFE (normalized, len, *b)); /* Changes len in-place. */ - UChar recomposed[18 * 2]; - icu_err = U_ZERO_ERROR; - len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err); - if (U_FAILURE (icu_err)) - return false; - /* We expect that recomposed has exactly one character now. */ - if (unlikely (u_countChar32 (recomposed, len) != 1)) - return false; - HB_ICU_STMT (U16_GET_UNSAFE (recomposed, 0, *a)); - ret = true; + return *a != ab; } - - return ret; + else if (len == 2) + { + len = 0; + U16_NEXT_UNSAFE (decomposed, len, *a); + U16_NEXT_UNSAFE (decomposed, len, *b); + } + return true; } @@ -315,11 +242,9 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_ static hb_unicode_funcs_t *create () { void *user_data = nullptr; -#if U_ICU_VERSION_MAJOR_NUM >= 49 UErrorCode icu_err = U_ZERO_ERROR; user_data = (void *) unorm2_getNFCInstance (&icu_err); assert (user_data); -#endif hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); @@ -348,11 +273,24 @@ void free_static_icu_funcs () } #endif +/** + * hb_icu_get_unicode_funcs: + * + * Fetches a Unicode-functions structure that is populated + * with the appropriate ICU function for each method. + * + * Return value: (transfer none): a pointer to the #hb_unicode_funcs_t Unicode-functions structure + * + * Since: 0.9.38 + **/ hb_unicode_funcs_t * hb_icu_get_unicode_funcs () { return static_icu_funcs.get_unconst (); } +#ifdef HB_ICU_EXTRA_SEMI_IGNORED +#pragma GCC diagnostic pop +#endif #endif diff --git a/src/hb-iter.hh b/src/hb-iter.hh index 8d2ff80c2186a7234bdda16605ea4968f5c1b96d..f7018150e4729757e2e01794fdfb6121428c8361 100644 --- a/src/hb-iter.hh +++ b/src/hb-iter.hh @@ -64,7 +64,7 @@ template struct hb_iter_t { typedef Item item_t; - static constexpr unsigned item_size = hb_static_size (Item); + constexpr unsigned get_item_size () const { return hb_static_size (Item); } static constexpr bool is_iterator = true; static constexpr bool is_random_access_iterator = false; static constexpr bool is_sorted_iterator = false; @@ -72,7 +72,7 @@ struct hb_iter_t private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ const iter_t* thiz () const { return static_cast (this); } - iter_t* thiz () { return static_cast< iter_t *> (this); } + iter_t* thiz () { return static_cast< iter_t *> (this); } public: /* TODO: @@ -130,7 +130,7 @@ struct hb_iter_t using item_t = typename Name::item_t; \ using Name::begin; \ using Name::end; \ - using Name::item_size; \ + using Name::get_item_size; \ using Name::is_iterator; \ using Name::iter; \ using Name::operator bool; \ @@ -156,6 +156,7 @@ using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ()); template struct hb_array_t; +template struct hb_sorted_array_t; struct { @@ -175,6 +176,14 @@ struct } HB_FUNCOBJ (hb_iter); +struct +{ + template unsigned + operator () (T&& c) const + { return c.len (); } + +} +HB_FUNCOBJ (hb_len); /* Mixin to fill in what the subclass doesn't provide. */ template @@ -183,7 +192,7 @@ struct hb_iter_fallback_mixin_t private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ const iter_t* thiz () const { return static_cast (this); } - iter_t* thiz () { return static_cast< iter_t *> (this); } + iter_t* thiz () { return static_cast< iter_t *> (this); } public: /* Access: Implement __item__(), or __item_at__() if random-access. */ @@ -563,7 +572,7 @@ struct hb_zip_iter_t : B b; }; struct -{ +{ HB_PARTIALIZE(2); template hb_zip_iter_t, hb_iter_type> @@ -602,18 +611,18 @@ struct } HB_FUNCOBJ (hb_apply); -/* hb_iota()/hb_range() */ +/* hb_range()/hb_iota()/hb_repeat() */ template -struct hb_counter_iter_t : - hb_iter_t, T> +struct hb_range_iter_t : + hb_iter_t, T> { - hb_counter_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {} + hb_range_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {} typedef T __item_t__; static constexpr bool is_random_access_iterator = true; static constexpr bool is_sorted_iterator = true; - __item_t__ __item__ () const { return +v; } + __item_t__ __item__ () const { return hb_ridentity (v); } __item_t__ __item_at__ (unsigned j) const { return v + j * step; } bool __more__ () const { return v != end_; } unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; } @@ -621,8 +630,8 @@ struct hb_counter_iter_t : void __forward__ (unsigned n) { v += n * step; } void __prev__ () { v -= step; } void __rewind__ (unsigned n) { v -= n * step; } - hb_counter_iter_t __end__ () const { return hb_counter_iter_t (end_, end_, step); } - bool operator != (const hb_counter_iter_t& o) const + hb_range_iter_t __end__ () const { return hb_range_iter_t (end_, end_, step); } + bool operator != (const hb_range_iter_t& o) const { return v != o.v; } private: @@ -644,24 +653,91 @@ struct hb_counter_iter_t : }; struct { - template hb_counter_iter_t - operator () (T start = 0u, S&& step = 1u) const - { return hb_counter_iter_t (start, step >= 0 ? hb_int_max (T) : hb_int_min (T), step); } + template hb_range_iter_t + operator () (T end = (unsigned) -1) const + { return hb_range_iter_t (0, end, 1u); } + + template hb_range_iter_t + operator () (T start, T end, S step = 1u) const + { return hb_range_iter_t (start, end, step); } } -HB_FUNCOBJ (hb_iota); +HB_FUNCOBJ (hb_range); + +template +struct hb_iota_iter_t : + hb_iter_with_fallback_t, T> +{ + hb_iota_iter_t (T start, S step) : v (start), step (step) {} + + private: + + template + auto + inc (hb_type_identity s, hb_priority<1>) + -> hb_void_t (s), hb_declval ()))> + { v = hb_invoke (hb_forward (s), v); } + + void + inc (S s, hb_priority<0>) + { v += s; } + + public: + + typedef T __item_t__; + static constexpr bool is_random_access_iterator = true; + static constexpr bool is_sorted_iterator = true; + __item_t__ __item__ () const { return hb_ridentity (v); } + bool __more__ () const { return true; } + unsigned __len__ () const { return UINT_MAX; } + void __next__ () { inc (step, hb_prioritize); } + void __prev__ () { v -= step; } + hb_iota_iter_t __end__ () const { return *this; } + bool operator != (const hb_iota_iter_t& o) const { return true; } + + private: + T v; + S step; +}; struct { - template hb_counter_iter_t - operator () (T end = (unsigned) -1) const - { return hb_counter_iter_t (0, end, 1u); } + template hb_iota_iter_t + operator () (T start = 0u, S step = 1u) const + { return hb_iota_iter_t (start, step); } +} +HB_FUNCOBJ (hb_iota); + +template +struct hb_repeat_iter_t : + hb_iter_t, T> +{ + hb_repeat_iter_t (T value) : v (value) {} - template hb_counter_iter_t - operator () (T start, T end, S&& step = 1u) const - { return hb_counter_iter_t (start, end, step); } + typedef T __item_t__; + static constexpr bool is_random_access_iterator = true; + static constexpr bool is_sorted_iterator = true; + __item_t__ __item__ () const { return v; } + __item_t__ __item_at__ (unsigned j) const { return v; } + bool __more__ () const { return true; } + unsigned __len__ () const { return UINT_MAX; } + void __next__ () {} + void __forward__ (unsigned) {} + void __prev__ () {} + void __rewind__ (unsigned) {} + hb_repeat_iter_t __end__ () const { return *this; } + bool operator != (const hb_repeat_iter_t& o) const { return true; } + + private: + T v; +}; +struct +{ + template hb_repeat_iter_t + operator () (T value) const + { return hb_repeat_iter_t (value); } } -HB_FUNCOBJ (hb_range); +HB_FUNCOBJ (hb_repeat); -/* hb_enumerate */ +/* hb_enumerate()/hb_take() */ struct { @@ -673,6 +749,37 @@ struct } HB_FUNCOBJ (hb_enumerate); +struct +{ HB_PARTIALIZE(2); + template + auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN + ( hb_zip (hb_range (count), it) | hb_map (hb_second) ) + + /* Specialization arrays. */ + + template inline hb_array_t + operator () (hb_array_t array, unsigned count) const + { return array.sub_array (0, count); } + + template inline hb_sorted_array_t + operator () (hb_sorted_array_t array, unsigned count) const + { return array.sub_array (0, count); } +} +HB_FUNCOBJ (hb_take); + +struct +{ HB_PARTIALIZE(2); + template + auto operator () (Iter it, unsigned count) const HB_AUTO_RETURN + ( + + hb_iota (it, hb_add (count)) + | hb_map (hb_take (count)) + | hb_take ((hb_len (it) + count - 1) / count) + ) +} +HB_FUNCOBJ (hb_chop); /* hb_sink() */ @@ -815,7 +922,7 @@ HB_FUNCOBJ (hb_none); template inline void -hb_fill (C& c, const V &v) +hb_fill (C&& c, const V &v) { for (auto i = hb_iter (c); i; i++) *i = v; diff --git a/src/hb-kern.hh b/src/hb-kern.hh index fd5bb9e45ef2751c0e416e5970b2a5bb0ac46558..3f952fe7fce199e7627324ef59742b95cb23bcfe 100644 --- a/src/hb-kern.hh +++ b/src/hb-kern.hh @@ -52,8 +52,7 @@ struct hb_kern_machine_t OT::hb_ot_apply_context_t c (1, font, buffer); c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); - OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; - skippy_iter.init (&c); + auto &skippy_iter = c.iter_input; bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); unsigned int count = buffer->len; @@ -82,11 +81,11 @@ struct hb_kern_machine_t if (likely (!kern)) - goto skip; + goto skip; if (horizontal) { - if (scale) + if (scale) kern = font->em_scale_x (kern); if (crossStream) { @@ -104,7 +103,7 @@ struct hb_kern_machine_t } else { - if (scale) + if (scale) kern = font->em_scale_y (kern); if (crossStream) { diff --git a/src/hb-machinery.hh b/src/hb-machinery.hh index 5a2087e4aa90fcb3d0b2b81c8981f306fa621610..3bd5a979b05cac8c13b8a8e5c91276e5ecceecc1 100644 --- a/src/hb-machinery.hh +++ b/src/hb-machinery.hh @@ -41,22 +41,6 @@ * Casts */ -/* Cast to struct T, reference to reference */ -template -static inline const Type& CastR(const TObject &X) -{ return reinterpret_cast (X); } -template -static inline Type& CastR(TObject &X) -{ return reinterpret_cast (X); } - -/* Cast to struct T, pointer to pointer */ -template -static inline const Type* CastP(const TObject *X) -{ return reinterpret_cast (X); } -template -static inline Type* CastP(TObject *X) -{ return reinterpret_cast (X); } - /* StructAtOffset(P,Ofs) returns the struct T& that is placed at memory * location pointed to by P plus Ofs bytes. */ template @@ -70,7 +54,7 @@ static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int of { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" - return * reinterpret_cast ((char *) P + offset); + return * reinterpret_cast ((const char *) P + offset); #pragma GCC diagnostic pop } template @@ -96,6 +80,11 @@ static inline Type& StructAfter(TObject &X) * Size checking */ +/* Size signifying variable-sized array */ +#ifndef HB_VAR_ARRAY +#define HB_VAR_ARRAY 1 +#endif + /* Check _assertion in a method environment */ #define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \ void _instance_assertion_on_line_##_line () const \ @@ -135,7 +124,7 @@ static inline Type& StructAfter(TObject &X) #define DEFINE_SIZE_ARRAY(size, array) \ DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \ static constexpr unsigned null_size = (size); \ static constexpr unsigned min_size = (size) @@ -225,7 +214,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t if (unlikely (!cmpexch (nullptr, p))) { - do_destroy (p); + do_destroy (p); goto retry; } } @@ -250,7 +239,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t static Returned* convert (Stored *p) { return p; } /* By default null/init/fini the object. */ - static const Stored* get_null () { return &Null(Stored); } + static const Stored* get_null () { return &Null (Stored); } static Stored *create (Data *data) { Stored *p = (Stored *) calloc (1, sizeof (Stored)); diff --git a/src/hb-map.cc b/src/hb-map.cc index a2c770c586dfb556ed4b009e1be8518c6048b3e6..f115da2bb8765ef2184eb930f6c753599f50203a 100644 --- a/src/hb-map.cc +++ b/src/hb-map.cc @@ -42,7 +42,9 @@ /** * hb_map_create: (Xconstructor) * - * Return value: (transfer full): + * Creates a new, initially empty map. + * + * Return value: (transfer full): The new #hb_map_t * * Since: 1.7.7 **/ @@ -62,21 +64,25 @@ hb_map_create () /** * hb_map_get_empty: * - * Return value: (transfer full): + * Fetches the singleton empty #hb_map_t. + * + * Return value: (transfer full): The empty #hb_map_t * * Since: 1.7.7 **/ hb_map_t * hb_map_get_empty () { - return const_cast (&Null(hb_map_t)); + return const_cast (&Null (hb_map_t)); } /** * hb_map_reference: (skip) - * @map: a map. + * @map: A map + * + * Increases the reference count on a map. * - * Return value: (transfer full): + * Return value: (transfer full): The map * * Since: 1.7.7 **/ @@ -88,7 +94,11 @@ hb_map_reference (hb_map_t *map) /** * hb_map_destroy: (skip) - * @map: a map. + * @map: A map + * + * Decreases the reference count on a map. When + * the reference count reaches zero, the map is + * destroyed, freeing all memory. * * Since: 1.7.7 **/ @@ -104,13 +114,15 @@ hb_map_destroy (hb_map_t *map) /** * hb_map_set_user_data: (skip) - * @map: a map. - * @key: - * @data: - * @destroy: - * @replace: + * @map: A map + * @key: The user-data key to set + * @data: A pointer to the user data to set + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the specified map. * - * Return value: + * Return value: %true if success, %false otherwise * * Since: 1.7.7 **/ @@ -126,10 +138,13 @@ hb_map_set_user_data (hb_map_t *map, /** * hb_map_get_user_data: (skip) - * @map: a map. - * @key: + * @map: A map + * @key: The user-data key to query + * + * Fetches the user data associated with the specified key, + * attached to the specified map. * - * Return value: (transfer none): + * Return value: (transfer none): A pointer to the user data * * Since: 1.7.7 **/ @@ -143,11 +158,11 @@ hb_map_get_user_data (hb_map_t *map, /** * hb_map_allocation_successful: - * @map: a map. + * @map: A map * + * Tests whether memory allocation for a set was successful. * - * - * Return value: + * Return value: %true if allocation succeeded, %false otherwise * * Since: 1.7.7 **/ @@ -160,11 +175,11 @@ hb_map_allocation_successful (const hb_map_t *map) /** * hb_map_set: - * @map: a map. - * @key: - * @value: - * + * @map: A map + * @key: The key to store in the map + * @value: The value to store for @key * + * Stores @key:@value in the map. * * Since: 1.7.7 **/ @@ -178,10 +193,10 @@ hb_map_set (hb_map_t *map, /** * hb_map_get: - * @map: a map. - * @key: - * + * @map: A map + * @key: The key to query * + * Fetches the value stored for @key in @map. * * Since: 1.7.7 **/ @@ -194,10 +209,10 @@ hb_map_get (const hb_map_t *map, /** * hb_map_del: - * @map: a map. - * @key: - * + * @map: A map + * @key: The key to delete * + * Removes @key and its stored value from @map. * * Since: 1.7.7 **/ @@ -210,10 +225,12 @@ hb_map_del (hb_map_t *map, /** * hb_map_has: - * @map: a map. - * @key: + * @map: A map + * @key: The key to query * + * Tests whether @key is an element of @map. * + * Return value: %true if @key is found in @map, %false otherwise * * Since: 1.7.7 **/ @@ -227,23 +244,28 @@ hb_map_has (const hb_map_t *map, /** * hb_map_clear: - * @map: a map. - * + * @map: A map * + * Clears out the contents of @map. * * Since: 1.7.7 **/ void hb_map_clear (hb_map_t *map) { + if (unlikely (hb_object_is_immutable (map))) + return; + return map->clear (); } /** * hb_map_is_empty: - * @map: a map. + * @map: A map * + * Tests whether @map is empty (contains no elements). * + * Return value: %true if @map is empty * * Since: 1.7.7 **/ @@ -255,9 +277,11 @@ hb_map_is_empty (const hb_map_t *map) /** * hb_map_get_population: - * @map: a map. + * @map: A map * + * Returns the number of key-value pairs in the map. * + * Return value: The population of @map * * Since: 1.7.7 **/ diff --git a/src/hb-map.h b/src/hb-map.h index b77843c2baf84b546d4d25b0d1295c34317f9d4e..6a45a7bdd52411d2e7b00a63216844e36e7b2247 100644 --- a/src/hb-map.h +++ b/src/hb-map.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -36,11 +36,21 @@ HB_BEGIN_DECLS -/* +/** + * HB_MAP_VALUE_INVALID: + * + * Unset #hb_map_t value. + * * Since: 1.7.7 */ #define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1) +/** + * hb_map_t: + * + * Data type for holding integer-to-integer hash maps. + * + **/ typedef struct hb_map_t hb_map_t; diff --git a/src/hb-map.hh b/src/hb-map.hh index 26e4930a5f74b5c882231b6a5397b7662d5aa89a..ab9c17eb1c7ae260a25775a07b688442396a0fa7 100644 --- a/src/hb-map.hh +++ b/src/hb-map.hh @@ -46,18 +46,15 @@ struct hb_hashmap_t static_assert (hb_is_integral (K) || hb_is_pointer (K), ""); static_assert (hb_is_integral (V) || hb_is_pointer (V), ""); - /* TODO If key type is a pointer, keep hash in item_t and use to: - * 1. avoid rehashing when resizing table, and - * 2. compare hash before comparing keys, for speed. - */ struct item_t { K key; V value; + uint32_t hash; - void clear () { key = kINVALID; value = vINVALID; } + void clear () { key = kINVALID; value = vINVALID; hash = 0; } - bool operator == (K o) { return hb_deref (key) == hb_deref (o); } + bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } bool operator == (const item_t &o) { return *this == o.key; } bool is_unused () const { return key == kINVALID; } bool is_tombstone () const { return key != kINVALID && value == vINVALID; } @@ -100,8 +97,6 @@ struct hb_hashmap_t void reset () { - if (unlikely (hb_object_is_immutable (this))) - return; successful = true; clear (); } @@ -120,9 +115,8 @@ struct hb_hashmap_t successful = false; return false; } - + hb_iter (new_items, new_size) - | hb_apply (&item_t::clear) - ; + for (auto &_ : hb_iter (new_items, new_size)) + _.clear (); unsigned int old_size = mask + 1; item_t *old_items = items; @@ -137,38 +131,20 @@ struct hb_hashmap_t if (old_items) for (unsigned int i = 0; i < old_size; i++) if (old_items[i].is_real ()) - set (old_items[i].key, old_items[i].value); + set_with_hash (old_items[i].key, + old_items[i].hash, + old_items[i].value); free (old_items); return true; } - void set (K key, V value) + bool set (K key, V value) { - if (unlikely (!successful)) return; - if (unlikely (key == kINVALID)) return; - if ((occupancy + occupancy / 2) >= mask && !resize ()) return; - unsigned int i = bucket_for (key); - - if (value == vINVALID && items[i].key != key) - return; /* Trying to delete non-existent key. */ - - if (!items[i].is_unused ()) - { - occupancy--; - if (items[i].is_tombstone ()) - population--; - } - - items[i].key = key; - items[i].value = value; - - occupancy++; - if (!items[i].is_tombstone ()) - population++; - + return set_with_hash (key, hb_hash (key), value); } + V get (K key) const { if (unlikely (!items)) return vINVALID; @@ -193,17 +169,15 @@ struct hb_hashmap_t void clear () { - if (unlikely (hb_object_is_immutable (this))) - return; if (items) - + hb_iter (items, mask + 1) - | hb_apply (&item_t::clear) - ; + for (auto &_ : hb_iter (items, mask + 1)) + _.clear (); population = occupancy = 0; } bool is_empty () const { return population == 0; } + explicit operator bool () const { return !is_empty (); } unsigned int get_population () const { return population; } @@ -232,19 +206,52 @@ struct hb_hashmap_t ) /* Sink interface. */ - hb_hashmap_t& operator << (const hb_pair_t& v) + hb_hashmap_t& operator << (const hb_pair_t& v) { set (v.first, v.second); return *this; } protected: + bool set_with_hash (K key, uint32_t hash, V value) + { + if (unlikely (!successful)) return false; + if (unlikely (key == kINVALID)) return true; + if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; + unsigned int i = bucket_for_hash (key, hash); + + if (value == vINVALID && items[i].key != key) + return true; /* Trying to delete non-existent key. */ + + if (!items[i].is_unused ()) + { + occupancy--; + if (items[i].is_tombstone ()) + population--; + } + + items[i].key = key; + items[i].value = value; + items[i].hash = hash; + + occupancy++; + if (!items[i].is_tombstone ()) + population++; + + return true; + } + unsigned int bucket_for (K key) const { - unsigned int i = hb_hash (key) % prime; + return bucket_for_hash (key, hb_hash (key)); + } + + unsigned int bucket_for_hash (K key, uint32_t hash) const + { + unsigned int i = hash % prime; unsigned int step = 0; unsigned int tombstone = (unsigned) -1; while (!items[i].is_unused ()) { - if (items[i] == key) + if (items[i].hash == hash && items[i] == key) return i; if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) tombstone = i; diff --git a/src/hb-meta.hh b/src/hb-meta.hh index 2dfaeb7b46495b9a939f470b340e222aaa66f910..e40d9fd178c2174087a46f6f2f3b0150657497ab 100644 --- a/src/hb-meta.hh +++ b/src/hb-meta.hh @@ -49,6 +49,10 @@ template using hb_bool_constant = hb_integral_constant; using hb_true_type = hb_bool_constant; using hb_false_type = hb_bool_constant; +/* Static-assert as expression. */ +template struct static_assert_expr; +template <> struct static_assert_expr : hb_false_type {}; +#define static_assert_expr(C) static_assert_expr::value /* Basic type SFINAE. */ @@ -220,6 +224,8 @@ struct hb_reference_wrapper }; +/* Type traits */ + template using hb_is_integral = hb_bool_constant< hb_is_same (hb_decay, char) || @@ -292,6 +298,15 @@ template <> struct hb_int_max : hb_integral_constant::value +/* Class traits. */ + +#define HB_DELETE_COPY_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete +#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \ + TypeName() = delete; \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete template struct _hb_is_destructible : hb_false_type {}; @@ -343,7 +358,6 @@ using hb_is_move_assignable = hb_is_assignable, template union hb_trivial { T value; }; -/* Don't know how to do the following. */ template using hb_is_trivially_destructible= hb_is_destructible>; #define hb_is_trivially_destructible(T) hb_is_trivially_destructible::value @@ -396,5 +410,16 @@ using hb_is_trivial= hb_bool_constant< >; #define hb_is_trivial(T) hb_is_trivial::value +/* hb_unwrap_type (T) + * If T has no T::type, returns T. Otherwise calls itself on T::type recursively. + */ + +template +struct _hb_unwrap_type : hb_type_identity_t {}; +template +struct _hb_unwrap_type> : _hb_unwrap_type {}; +template +using hb_unwrap_type = _hb_unwrap_type; +#define hb_unwrap_type(T) typename hb_unwrap_type::type #endif /* HB_META_HH */ diff --git a/src/hb-mutex.hh b/src/hb-mutex.hh index e1362673180f0a604c7ecb32b1d8850bb7d6d247..2fc8d7ee58d3dfd6f94bdfd2030531ededc38be4 100644 --- a/src/hb-mutex.hh +++ b/src/hb-mutex.hh @@ -61,10 +61,9 @@ typedef pthread_mutex_t hb_mutex_impl_t; #elif !defined(HB_NO_MT) && defined(_WIN32) -#include typedef CRITICAL_SECTION hb_mutex_impl_t; #define HB_MUTEX_IMPL_INIT {0} -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) #else #define hb_mutex_impl_init(M) InitializeCriticalSection (M) @@ -74,43 +73,7 @@ typedef CRITICAL_SECTION hb_mutex_impl_t; #define hb_mutex_impl_finish(M) DeleteCriticalSection (M) -#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) - -#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) -# include -# define HB_SCHED_YIELD() sched_yield () -#else -# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END -#endif - -/* This actually is not a totally awful implementation. */ -typedef volatile int hb_mutex_impl_t; -#define HB_MUTEX_IMPL_INIT 0 -#define hb_mutex_impl_init(M) *(M) = 0 -#define hb_mutex_impl_lock(M) HB_STMT_START { while (__sync_lock_test_and_set((M), 1)) HB_SCHED_YIELD (); } HB_STMT_END -#define hb_mutex_impl_unlock(M) __sync_lock_release (M) -#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END - - -#elif !defined(HB_NO_MT) - -#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) -# include -# define HB_SCHED_YIELD() sched_yield () -#else -# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END -#endif - -#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */ -typedef volatile int hb_mutex_impl_t; -#define HB_MUTEX_IMPL_INIT 0 -#define hb_mutex_impl_init(M) *(M) = 0 -#define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END -#define hb_mutex_impl_unlock(M) (*(M))-- -#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END - - -#else /* HB_NO_MT */ +#elif defined(HB_NO_MT) typedef int hb_mutex_impl_t; #define HB_MUTEX_IMPL_INIT 0 @@ -120,6 +83,11 @@ typedef int hb_mutex_impl_t; #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END +#else + +#error "Could not find any system to define mutex macros." +#error "Check hb-mutex.hh for possible resolutions." + #endif diff --git a/src/hb-null.hh b/src/hb-null.hh index d4578205e33c3af3dee64fc065e05326a8a38f05..db38a4dfd24195ba810e9cfbb0e7126fbed24b1b 100644 --- a/src/hb-null.hh +++ b/src/hb-null.hh @@ -39,8 +39,11 @@ #define HB_NULL_POOL_SIZE 384 -/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size, - * otherwise return sizeof(T). */ +/* Use SFINAE to sniff whether T has min_size; in which case return the larger + * of sizeof(T) and T::null_size, otherwise return sizeof(T). + * + * The main purpose of this is to let structs communicate that they are not nullable, + * by defining min_size but *not* null_size. */ /* The hard way... * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol @@ -49,8 +52,9 @@ template struct _hb_null_size : hb_integral_constant {}; template -struct _hb_null_size> : hb_integral_constant {}; - +struct _hb_null_size> + : hb_integral_constant T::null_size ? sizeof (T) : T::null_size)> {}; template using hb_null_size = _hb_null_size; #define hb_null_size(T) hb_null_size::value @@ -68,6 +72,14 @@ template using hb_static_size = _hb_static_size; #define hb_static_size(T) hb_static_size::value +template +struct _hb_min_size : hb_integral_constant {}; +template +struct _hb_min_size> : hb_integral_constant {}; +template +using hb_min_size = _hb_min_size; +#define hb_min_size(T) hb_min_size::value + /* * Null() @@ -104,7 +116,7 @@ struct NullHelper } \ }; \ namespace Namespace { \ - static_assert (true, "Just so we take semicolon after.") + static_assert (true, "") /* Require semicolon after. */ #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size] @@ -117,7 +129,7 @@ struct NullHelper return _hb_Null_##Type; \ } \ }; \ - static_assert (true, "Just so we take semicolon after.") + static_assert (true, "") /* Require semicolon after. */ #define DEFINE_NULL_INSTANCE(Type) \ const Type _hb_Null_##Type @@ -135,7 +147,7 @@ template static inline Type& Crap () { static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); Type *obj = reinterpret_cast (_hb_CrapPool); - memcpy (obj, &Null(Type), sizeof (*obj)); + memcpy (obj, &Null (Type), sizeof (*obj)); return *obj; } template @@ -148,11 +160,11 @@ struct CrapHelper template struct CrapOrNullHelper { - static Type & get () { return Crap(Type); } + static Type & get () { return Crap (Type); } }; template struct CrapOrNullHelper { - static const Type & get () { return Null(Type); } + static const Type & get () { return Null (Type); } }; #define CrapOrNull(Type) CrapOrNullHelper::get () @@ -174,9 +186,10 @@ struct hb_nonnull_ptr_t /* Only auto-cast to const types. */ template operator const C * () const { return get (); } operator const char * () const { return (const char *) get (); } - T * get () const { return v ? v : const_cast (&Null(T)); } + T * get () const { return v ? v : const_cast (&Null (T)); } T * get_raw () const { return v; } + private: T *v; }; diff --git a/src/hb-number-parser.hh b/src/hb-number-parser.hh new file mode 100644 index 0000000000000000000000000000000000000000..1a9dbba6dd3dc9766ff134c5bc53512a38d6affa --- /dev/null +++ b/src/hb-number-parser.hh @@ -0,0 +1,237 @@ + +#line 1 "hb-number-parser.rl" +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#ifndef HB_NUMBER_PARSER_HH +#define HB_NUMBER_PARSER_HH + +#include "hb.hh" + + +#line 35 "hb-number-parser.hh" +static const unsigned char _double_parser_trans_keys[] = { + 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, + 46u, 101u, 0 +}; + +static const char _double_parser_key_spans[] = { + 0, 15, 12, 10, 15, 10, 54, 10, + 56 +}; + +static const unsigned char _double_parser_index_offsets[] = { + 0, 0, 16, 29, 40, 56, 67, 122, + 133 +}; + +static const char _double_parser_indicies[] = { + 0, 1, 2, 3, 1, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 1, 3, 1, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 1, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 1, 6, 1, 7, 1, 1, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 1, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 1, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 1, 3, 1, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 0 +}; + +static const char _double_parser_trans_targs[] = { + 2, 0, 2, 3, 8, 6, 5, 5, + 7, 4 +}; + +static const char _double_parser_trans_actions[] = { + 0, 0, 1, 0, 2, 3, 0, 4, + 5, 0 +}; + +static const int double_parser_start = 1; +static const int double_parser_first_final = 6; +static const int double_parser_error = 0; + +static const int double_parser_en_main = 1; + + +#line 68 "hb-number-parser.rl" + + +/* Works only for n < 512 */ +static inline double +_pow10 (unsigned exponent) +{ + static const double _powers_of_10[] = + { + 1.0e+256, + 1.0e+128, + 1.0e+64, + 1.0e+32, + 1.0e+16, + 1.0e+8, + 10000., + 100., + 10. + }; + unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1); + double result = 1; + for (const double *power = _powers_of_10; mask; ++power, mask >>= 1) + if (exponent & mask) result *= *power; + return result; +} + +/* a variant of strtod that also gets end of buffer in its second argument */ +static inline double +strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) +{ + double value = 0; + double frac = 0; + double frac_count = 0; + unsigned exp = 0; + bool neg = false, exp_neg = false, exp_overflow = false; + const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ + const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */ + + const char *pe = *end_ptr; + while (p < pe && ISSPACE (*p)) + p++; + + int cs; + +#line 139 "hb-number-parser.hh" + { + cs = double_parser_start; + } + +#line 144 "hb-number-parser.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _double_parser_trans_keys + (cs<<1); + _inds = _double_parser_indicies + _double_parser_index_offsets[cs]; + + _slen = _double_parser_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _double_parser_trans_targs[_trans]; + + if ( _double_parser_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _double_parser_trans_actions[_trans] ) { + case 1: +#line 37 "hb-number-parser.rl" + { neg = true; } + break; + case 4: +#line 38 "hb-number-parser.rl" + { exp_neg = true; } + break; + case 2: +#line 40 "hb-number-parser.rl" + { + value = value * 10. + ((*p) - '0'); +} + break; + case 3: +#line 43 "hb-number-parser.rl" + { + if (likely (frac <= MAX_FRACT / 10)) + { + frac = frac * 10. + ((*p) - '0'); + ++frac_count; + } +} + break; + case 5: +#line 50 "hb-number-parser.rl" + { + if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP)) + exp = exp * 10 + ((*p) - '0'); + else + exp_overflow = true; +} + break; +#line 202 "hb-number-parser.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 113 "hb-number-parser.rl" + + + *end_ptr = p; + + if (frac_count) value += frac / _pow10 (frac_count); + if (neg) value *= -1.; + + if (unlikely (exp_overflow)) + { + if (value == 0) return value; + if (exp_neg) return neg ? -DBL_MIN : DBL_MIN; + else return neg ? -DBL_MAX : DBL_MAX; + } + + if (exp) + { + if (exp_neg) value /= _pow10 (exp); + else value *= _pow10 (exp); + } + + return value; +} + +#endif /* HB_NUMBER_PARSER_HH */ diff --git a/src/hb-number-parser.rl b/src/hb-number-parser.rl new file mode 100644 index 0000000000000000000000000000000000000000..c6c4a3bab88d997f2df5ed99f9c017f60d371504 --- /dev/null +++ b/src/hb-number-parser.rl @@ -0,0 +1,136 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#ifndef HB_NUMBER_PARSER_HH +#define HB_NUMBER_PARSER_HH + +#include "hb.hh" + +%%{ + +machine double_parser; +alphtype unsigned char; +write data; + +action see_neg { neg = true; } +action see_exp_neg { exp_neg = true; } + +action add_int { + value = value * 10. + (fc - '0'); +} +action add_frac { + if (likely (frac <= MAX_FRACT / 10)) + { + frac = frac * 10. + (fc - '0'); + ++frac_count; + } +} +action add_exp { + if (likely (exp * 10 + (fc - '0') <= MAX_EXP)) + exp = exp * 10 + (fc - '0'); + else + exp_overflow = true; +} + +num = [0-9]+; + +main := ( + ( + (('+'|'-'@see_neg)? num @add_int) ('.' num @add_frac)? + | + (('+'|'-'@see_neg)? '.' num @add_frac) + ) + (('e'|'E') (('+'|'-'@see_exp_neg)? num @add_exp))? +); + +}%% + +/* Works only for n < 512 */ +static inline double +_pow10 (unsigned exponent) +{ + static const double _powers_of_10[] = + { + 1.0e+256, + 1.0e+128, + 1.0e+64, + 1.0e+32, + 1.0e+16, + 1.0e+8, + 10000., + 100., + 10. + }; + unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1); + double result = 1; + for (const double *power = _powers_of_10; mask; ++power, mask >>= 1) + if (exponent & mask) result *= *power; + return result; +} + +/* a variant of strtod that also gets end of buffer in its second argument */ +static inline double +strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) +{ + double value = 0; + double frac = 0; + double frac_count = 0; + unsigned exp = 0; + bool neg = false, exp_neg = false, exp_overflow = false; + const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ + const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */ + + const char *pe = *end_ptr; + while (p < pe && ISSPACE (*p)) + p++; + + int cs; + %%{ + write init; + write exec; + }%% + + *end_ptr = p; + + if (frac_count) value += frac / _pow10 (frac_count); + if (neg) value *= -1.; + + if (unlikely (exp_overflow)) + { + if (value == 0) return value; + if (exp_neg) return neg ? -DBL_MIN : DBL_MIN; + else return neg ? -DBL_MAX : DBL_MAX; + } + + if (exp) + { + if (exp_neg) value /= _pow10 (exp); + else value *= _pow10 (exp); + } + + return value; +} + +#endif /* HB_NUMBER_PARSER_HH */ diff --git a/src/hb-number.cc b/src/hb-number.cc new file mode 100644 index 0000000000000000000000000000000000000000..6e4f3f7ebd0a2f87e938cf36549fbc36fb095c85 --- /dev/null +++ b/src/hb-number.cc @@ -0,0 +1,80 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#include "hb.hh" +#include "hb-machinery.hh" +#include "hb-number.hh" +#include "hb-number-parser.hh" + +template +static bool +_parse_number (const char **pp, const char *end, T *pv, + bool whole_buffer, Func f) +{ + char buf[32]; + unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp)); + strncpy (buf, *pp, len); + buf[len] = '\0'; + + char *p = buf; + char *pend = p; + + errno = 0; + *pv = f (p, &pend); + if (unlikely (errno || p == pend || + /* Check if consumed whole buffer if is requested */ + (whole_buffer && pend - p != end - *pp))) + return false; + + *pp += pend - p; + return true; +} + +bool +hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer) +{ + return _parse_number (pp, end, pv, whole_buffer, + [] (const char *p, char **end) + { return strtol (p, end, 10); }); +} + +bool +hb_parse_uint (const char **pp, const char *end, unsigned *pv, + bool whole_buffer, int base) +{ + return _parse_number (pp, end, pv, whole_buffer, + [base] (const char *p, char **end) + { return strtoul (p, end, base); }); +} + +bool +hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer) +{ + const char *pend = end; + *pv = strtod_rl (*pp, &pend); + if (unlikely (*pp == pend)) return false; + *pp = pend; + return !whole_buffer || end == pend; +} diff --git a/src/dump-khmer-data.cc b/src/hb-number.hh similarity index 69% rename from src/dump-khmer-data.cc rename to src/hb-number.hh index cffbb92df721ad62e47cc8ff9c81c23130550293..14d1260aa3da34534e857f6907eaf1d05e549cfb 100644 --- a/src/dump-khmer-data.cc +++ b/src/hb-number.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Google, Inc. + * Copyright © 2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -21,21 +21,21 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-khmer.hh" +#ifndef HB_NUMBER_HH +#define HB_NUMBER_HH -int -main () -{ - for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) - { - hb_glyph_info_t info; - info.codepoint = u; - set_khmer_properties (info); - if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER) - printf("U+%04X %u\n", u, - info.khmer_category()); - } -} +HB_INTERNAL bool +hb_parse_int (const char **pp, const char *end, int *pv, + bool whole_buffer = false); + +HB_INTERNAL bool +hb_parse_uint (const char **pp, const char *end, unsigned int *pv, + bool whole_buffer = false, int base = 10); + +HB_INTERNAL bool +hb_parse_double (const char **pp, const char *end, double *pv, + bool whole_buffer = false); + +#endif /* HB_NUMBER_HH */ diff --git a/src/hb-object.hh b/src/hb-object.hh index 68520f2a1604b3677732ead7feecad5c87a5e36b..f3048b1c3ef9b361297dbdb8209960982aed80ae 100644 --- a/src/hb-object.hh +++ b/src/hb-object.hh @@ -62,7 +62,7 @@ struct hb_lockable_set_t old.fini (); } else { - item = nullptr; + item = nullptr; l.unlock (); } } else { @@ -140,9 +140,7 @@ struct hb_lockable_set_t * Reference-count. */ -#define HB_REFERENCE_COUNT_INERT_VALUE 0 -#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD -#define HB_REFERENCE_COUNT_INIT {HB_ATOMIC_INT_INIT (HB_REFERENCE_COUNT_INERT_VALUE)} +#define HB_REFERENCE_COUNT_INIT {0} struct hb_reference_count_t { @@ -152,9 +150,9 @@ struct hb_reference_count_t int get_relaxed () const { return ref_count.get_relaxed (); } int inc () const { return ref_count.inc (); } int dec () const { return ref_count.dec (); } - void fini () { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); } + void fini () { ref_count.set_relaxed (-0x0000DEAD); } - bool is_inert () const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; } + bool is_inert () const { return !ref_count.get_relaxed (); } bool is_valid () const { return ref_count.get_relaxed () > 0; } }; @@ -168,8 +166,8 @@ struct hb_user_data_array_t void *data; hb_destroy_func_t destroy; - bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } - bool operator == (hb_user_data_item_t &other) const { return key == other.key; } + bool operator == (const hb_user_data_key_t *other_key) const { return key == other_key; } + bool operator == (const hb_user_data_item_t &other) const { return key == other.key; } void fini () { if (destroy) destroy (data); } }; @@ -197,15 +195,10 @@ struct hb_user_data_array_t struct hb_object_header_t { hb_reference_count_t ref_count; - mutable hb_atomic_int_t writable; + mutable hb_atomic_int_t writable = 0; hb_atomic_ptr_t user_data; }; -#define HB_OBJECT_HEADER_STATIC \ - { \ - HB_REFERENCE_COUNT_INIT, \ - HB_ATOMIC_INT_INIT (false), \ - HB_ATOMIC_PTR_INIT (nullptr) \ - } +#define HB_OBJECT_HEADER_STATIC {} /* diff --git a/src/hb-open-file.hh b/src/hb-open-file.hh index f3f4dc07f50bd6915d1f40c7bab8c89844c81e5e..66ca03076bac3f1fd06cda00f5565e664ecc5c87 100644 --- a/src/hb-open-file.hh +++ b/src/hb-open-file.hh @@ -48,7 +48,7 @@ namespace OT { */ struct OpenTypeFontFile; -struct OffsetTable; +struct OpenTypeOffsetTable; struct TTCHeader; @@ -78,7 +78,7 @@ typedef struct TableRecord DEFINE_SIZE_STATIC (16); } OpenTypeTable; -typedef struct OffsetTable +typedef struct OpenTypeOffsetTable { friend struct OpenTypeFontFile; @@ -91,15 +91,10 @@ typedef struct OffsetTable { if (table_count) { - if (start_offset >= tables.len) - *table_count = 0; - else - *table_count = hb_min (*table_count, tables.len - start_offset); - - const TableRecord *sub_tables = tables.arrayZ + start_offset; - unsigned int count = *table_count; - for (unsigned int i = 0; i < count; i++) - table_tags[i] = sub_tables[i].tag; + + tables.sub_array (start_offset, table_count) + | hb_map (&TableRecord::tag) + | hb_sink (hb_array (table_tags, *table_count)) + ; } return tables.len; } @@ -223,7 +218,7 @@ struct TTCHeaderVersion1 Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ FixedVersion<>version; /* Version of the TTC Header (1.0), * 0x00010000u */ - LArrayOf> + Array32Of> table; /* Array of offsets to the OffsetTable for each font * from the beginning of the file */ public: @@ -249,7 +244,7 @@ struct TTCHeader switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ case 1: return u.version1.get_face (i); - default:return Null(OpenTypeFontFace); + default:return Null (OpenTypeFontFace); } } @@ -284,10 +279,10 @@ struct TTCHeader struct ResourceRecord { const OpenTypeFontFace & get_face (const void *data_base) const - { return CastR ((data_base+offset).arrayZ); } + { return * reinterpret_cast ((data_base+offset).arrayZ); } bool sanitize (hb_sanitize_context_t *c, - const void *data_base) const + const void *data_base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -300,7 +295,7 @@ struct ResourceRecord HBINT16 nameOffset; /* Offset from beginning of resource name list * to resource name, -1 means there is none. */ HBUINT8 attrs; /* Resource attributes */ - NNOffsetTo, HBUINT24> + NNOffset24To> offset; /* Offset from beginning of data block to * data for this resource */ HBUINT32 reserved; /* Reserved for handle to resource */ @@ -335,7 +330,7 @@ struct ResourceTypeRecord protected: Tag tag; /* Resource type. */ HBUINT16 resCountM1; /* Number of resources minus 1. */ - NNOffsetTo> + NNOffset16To> resourcesZ; /* Offset from beginning of resource type list * to reference item list for this type. */ public: @@ -391,7 +386,7 @@ struct ResourceMap HBUINT32 reserved1; /* Reserved for handle to next resource map */ HBUINT16 resreved2; /* Reserved for file reference number */ HBUINT16 attrs; /* Resource fork attribute */ - NNOffsetTo> + NNOffset16To> typeList; /* Offset from beginning of map to * resource type list */ Offset16 nameList; /* Offset from beginning of map to @@ -423,10 +418,10 @@ struct ResourceForkHeader } protected: - LNNOffsetTo> + NNOffset32To> data; /* Offset from beginning of resource fork * to resource data */ - LNNOffsetTo + NNOffset32To map; /* Offset from beginning of resource fork * to resource map */ HBUINT32 dataLen; /* Length of resource data */ @@ -478,7 +473,7 @@ struct OpenTypeFontFile case TrueTypeTag: return u.fontFace; case TTCTag: return u.ttcHeader.get_face (i); case DFontTag: return u.rfHeader.get_face (i, base_offset); - default: return Null(OpenTypeFontFace); + default: return Null (OpenTypeFontFace); } } diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh index ad995750b847fdf00dbf5df6e9e259427c2f988f..42eb8af05a9a236fa7c21d2b1e16f8667e7a35b3 100644 --- a/src/hb-open-type.hh +++ b/src/hb-open-type.hh @@ -53,26 +53,53 @@ namespace OT { */ /* Integer types in big-endian order and no alignment requirement */ -template +template struct IntType { typedef Type type; - typedef hb_conditional wide_type; - IntType& operator = (wide_type i) { v = i; return *this; } - operator wide_type () const { return v; } + IntType () = default; + explicit constexpr IntType (Type V) : v {V} {} + IntType& operator = (Type i) { v = i; return *this; } + /* For reason we define cast out operator for signed/unsigned, instead of Type, see: + * https://github.com/harfbuzz/harfbuzz/pull/2875/commits/09836013995cab2b9f07577a179ad7b024130467 */ + operator hb_conditional () const { return v; } + bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } bool operator != (const IntType &o) const { return !(*this == o); } + + IntType& operator += (unsigned count) { *this = *this + count; return *this; } + IntType& operator -= (unsigned count) { *this = *this - count; return *this; } + IntType& operator ++ () { *this += 1; return *this; } + IntType& operator -- () { *this -= 1; return *this; } + IntType operator ++ (int) { IntType c (*this); ++*this; return c; } + IntType operator -- (int) { IntType c (*this); --*this; return c; } + HB_INTERNAL static int cmp (const IntType *a, const IntType *b) { return b->cmp (*a); } - template + HB_INTERNAL static int cmp (const void *a, const void *b) + { + IntType *pa = (IntType *) a; + IntType *pb = (IntType *) b; + + return pb->cmp (*pa); + } + template int cmp (Type2 a) const { Type b = v; - if (sizeof (Type) < sizeof (int) && sizeof (Type2) < sizeof (int)) - return (int) a - (int) b; - else - return a < b ? -1 : a == b ? 0 : +1; + return (int) a - (int) b; + } + template + int cmp (Type2 a) const + { + Type b = v; + return a < b ? -1 : a == b ? 0 : +1; } bool sanitize (hb_sanitize_context_t *c) const { @@ -85,12 +112,12 @@ struct IntType DEFINE_SIZE_STATIC (Size); }; -typedef IntType HBUINT8; /* 8-bit unsigned integer. */ -typedef IntType HBINT8; /* 8-bit signed integer. */ -typedef IntType HBUINT16; /* 16-bit unsigned integer. */ -typedef IntType HBINT16; /* 16-bit signed integer. */ -typedef IntType HBUINT32; /* 32-bit unsigned integer. */ -typedef IntType HBINT32; /* 32-bit signed integer. */ +typedef IntType HBUINT8; /* 8-bit unsigned integer. */ +typedef IntType HBINT8; /* 8-bit signed integer. */ +typedef IntType HBUINT16; /* 16-bit unsigned integer. */ +typedef IntType HBINT16; /* 16-bit signed integer. */ +typedef IntType HBUINT32; /* 32-bit unsigned integer. */ +typedef IntType HBINT32; /* 32-bit signed integer. */ /* Note: we cannot defined a signed HBINT24 because there's no corresponding C type. * Works for unsigned, but not signed, since we rely on compiler for sign-extension. */ typedef IntType HBUINT24; /* 24-bit unsigned integer. */ @@ -116,9 +143,9 @@ struct F2DOT14 : HBINT16 }; /* 32-bit signed fixed-point number (16.16). */ -struct Fixed : HBINT32 +struct HBFixed : HBINT32 { - Fixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } + HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } // 65536 means 1<<16 float to_float () const { return ((int32_t) v) / 65536.f; } void set_float (float f) { v = roundf (f * 65536.f); } @@ -148,16 +175,16 @@ struct Tag : HBUINT32 { Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ - operator const char* () const { return reinterpret_cast (&this->v); } - operator char* () { return reinterpret_cast (&this->v); } + operator const char* () const { return reinterpret_cast (this); } + operator char* () { return reinterpret_cast (this); } public: DEFINE_SIZE_STATIC (4); }; /* Glyph index number, same as uint16 (length = 16 bits) */ -struct GlyphID : HBUINT16 +struct HBGlyphID : HBUINT16 { - GlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } + HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } }; /* Script/language-system/feature index */ @@ -169,6 +196,12 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, Index); typedef Index NameID; +struct VarIdx : HBUINT32 { + static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; + VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } +}; +DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); + /* Offset, Null offset = 0 */ template struct Offset : Type @@ -182,7 +215,9 @@ struct Offset : Type void *serialize (hb_serialize_context_t *c, const void *base) { void *t = c->start_embed (); - c->check_assign (*this, (unsigned) ((char *) t - (char *) base)); + c->check_assign (*this, + (unsigned) ((char *) t - (char *) base), + HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); return t; } @@ -191,6 +226,7 @@ struct Offset : Type }; typedef Offset Offset16; +typedef Offset Offset24; typedef Offset Offset32; @@ -256,11 +292,11 @@ struct _hb_has_null template struct _hb_has_null { - static const Type *get_null () { return &Null(Type); } - static Type *get_crap () { return &Crap(Type); } + static const Type *get_null () { return &Null (Type); } + static Type *get_crap () { return &Crap (Type); } }; -template +template struct OffsetTo : Offset { HB_DELETE_COPY_ASSIGN (OffsetTo); @@ -298,11 +334,8 @@ struct OffsetTo : Offset } template - bool serialize_subset (hb_subset_context_t *c, - const OffsetTo& src, - const void *src_base, - const void *dst_base, - Ts&&... ds) + bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, + const void *src_base, Ts&&... ds) { *this = 0; if (src.is_null ()) @@ -315,7 +348,7 @@ struct OffsetTo : Offset bool ret = c->dispatch (src_base+src, hb_forward (ds)...); if (ret || !has_null) - s->add_link (*this, s->pop_pack (), dst_base); + s->add_link (*this, s->pop_pack ()); else s->pop_discard (); @@ -323,11 +356,13 @@ struct OffsetTo : Offset } /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ + /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 + * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... + */ template - bool serialize_copy (hb_serialize_context_t *c, - const OffsetTo& src, - const void *src_base, - const void *dst_base, + bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, + const void *src_base, unsigned dst_bias, + hb_serialize_context_t::whence_t whence, Ts&&... ds) { *this = 0; @@ -338,17 +373,21 @@ struct OffsetTo : Offset bool ret = c->copy (src_base+src, hb_forward (ds)...); - c->add_link (*this, c->pop_pack (), dst_base); + c->add_link (*this, c->pop_pack (), whence, dst_bias); return ret; } + bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, + const void *src_base, unsigned dst_bias = 0) + { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } + bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) return_trace (false); if (unlikely (this->is_null ())) return_trace (true); - if (unlikely (!c->check_range (base, *this))) return_trace (false); + if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false); return_trace (true); } @@ -371,12 +410,14 @@ struct OffsetTo : Offset DEFINE_SIZE_STATIC (sizeof (OffsetType)); }; /* Partial specializations. */ -template -using LOffsetTo = OffsetTo; -template -using NNOffsetTo = OffsetTo; -template -using LNNOffsetTo = LOffsetTo; +template using Offset16To = OffsetTo; +template using Offset24To = OffsetTo; +template using Offset32To = OffsetTo; + +template using NNOffsetTo = OffsetTo; +template using NNOffset16To = Offset16To; +template using NNOffset24To = Offset24To; +template using NNOffset32To = Offset32To; /* @@ -415,8 +456,6 @@ struct UnsizedArrayOf { return hb_array (arrayZ, len); } hb_array_t as_array (unsigned int len) const { return hb_array (arrayZ, len); } - operator hb_array_t () { return as_array (); } - operator hb_array_t () const { return as_array (); } template Type &lsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type)) @@ -424,6 +463,9 @@ struct UnsizedArrayOf template const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const { return *as_array (len).lsearch (x, ¬_found); } + template + bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const + { return as_array (len).lfind (x, pos); } void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array (len).qsort (start, end); } @@ -475,18 +517,18 @@ struct UnsizedArrayOf } public: - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_UNBOUNDED (0); }; /* Unsized array of offset's */ template -using UnsizedOffsetArrayOf = UnsizedArrayOf>; +using UnsizedArray16OfOffsetTo = UnsizedArrayOf>; /* Unsized array of offsets relative to the beginning of the array itself. */ template -struct UnsizedOffsetListOf : UnsizedOffsetArrayOf +struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo { const Type& operator [] (int i_) const { @@ -507,7 +549,7 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf + return_trace ((UnsizedArray16OfOffsetTo ::sanitize (c, count, this, hb_forward (ds)...))); } }; @@ -531,14 +573,14 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf { return *as_array (len).bsearch (x, ¬_found); } template bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { return as_array (len).bfind (x, i, not_found, to_store); } }; /* An array with a number of elements. */ -template +template struct ArrayOf { typedef Type item_t; @@ -564,6 +606,8 @@ struct ArrayOf explicit operator bool () const { return len; } + void pop () { len--; } + hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } hb_array_t as_array () const { return hb_array (arrayZ, len); } @@ -584,17 +628,30 @@ struct ArrayOf hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) { return as_array ().sub_array (start_offset, count); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + template + Type &lsearch (const T &x, Type ¬_found = Crap (Type)) + { return *as_array ().lsearch (x, ¬_found); } + template + const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const + { return *as_array ().lsearch (x, ¬_found); } + template + bool lfind (const T &x, unsigned *pos = nullptr) const + { return as_array ().lfind (x, pos); } + + void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) + { as_array ().qsort (start, end); } + + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - c->check_assign (len, items_len); + c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); if (unlikely (!c->extend (*this))) return_trace (false); return_trace (true); } template - bool serialize (hb_serialize_context_t *c, Iterator items) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); unsigned count = items.len (); @@ -606,12 +663,24 @@ struct ArrayOf return_trace (true); } + Type* serialize_append (hb_serialize_context_t *c) + { + TRACE_SERIALIZE (this); + len++; + if (unlikely (!len || !c->extend (*this))) + { + len--; + return_trace (nullptr); + } + return_trace (&arrayZ[len - 1]); + } + ArrayOf* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); auto *out = c->start_embed (this); if (unlikely (!c->extend_min (out))) return_trace (nullptr); - c->check_assign (out->len, len); + c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); if (unlikely (!as_array ().copy (c))) return_trace (nullptr); return_trace (out); } @@ -629,16 +698,6 @@ struct ArrayOf return_trace (true); } - template - Type &lsearch (const T &x, Type ¬_found = Crap (Type)) - { return *as_array ().lsearch (x, ¬_found); } - template - const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const - { return *as_array ().lsearch (x, ¬_found); } - - void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) - { as_array ().qsort (start, end); } - bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -647,25 +706,22 @@ struct ArrayOf public: LenType len; - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; -template -using LArrayOf = ArrayOf; +template using Array16Of = ArrayOf; +template using Array32Of = ArrayOf; using PString = ArrayOf; /* Array of Offset's */ -template -using OffsetArrayOf = ArrayOf>; -template -using LOffsetArrayOf = ArrayOf>; -template -using LOffsetLArrayOf = ArrayOf, HBUINT32>; +template using Array16OfOffset16To = ArrayOf, HBUINT16>; +template using Array16OfOffset32To = ArrayOf, HBUINT16>; +template using Array32OfOffset32To = ArrayOf, HBUINT32>; /* Array of offsets relative to the beginning of the array itself. */ template -struct OffsetListOf : OffsetArrayOf +struct List16OfOffset16To : Array16OfOffset16To { const Type& operator [] (int i_) const { @@ -683,7 +739,7 @@ struct OffsetListOf : OffsetArrayOf bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - struct OffsetListOf *out = c->serializer->embed (*this); + struct List16OfOffset16To *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); unsigned int count = this->len; for (unsigned int i = 0; i < count; i++) @@ -695,7 +751,7 @@ struct OffsetListOf : OffsetArrayOf bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace (OffsetArrayOf::sanitize (c, this, hb_forward (ds)...)); + return_trace (Array16OfOffset16To::sanitize (c, this, hb_forward (ds)...)); } }; @@ -720,17 +776,40 @@ struct HeadlessArrayOf return arrayZ[i-1]; } unsigned int get_size () const - { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; } + { return lenP1.static_size + get_length () * Type::static_size; } + + unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } + + hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } + hb_array_t as_array () const { return hb_array (arrayZ, get_length ()); } + + /* Iterator. */ + typedef hb_array_t iter_t; + typedef hb_array_t< Type> writer_t; + iter_t iter () const { return as_array (); } + writer_t writer () { return as_array (); } + operator iter_t () const { return iter (); } + operator writer_t () { return writer (); } - bool serialize (hb_serialize_context_t *c, - hb_array_t items) + bool serialize (hb_serialize_context_t *c, unsigned int items_len) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - c->check_assign (lenP1, items.length + 1); + c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); if (unlikely (!c->extend (*this))) return_trace (false); - for (unsigned int i = 0; i < items.length; i++) - arrayZ[i] = items[i]; + return_trace (true); + } + template + bool serialize (hb_serialize_context_t *c, Iterator items) + { + TRACE_SERIALIZE (this); + unsigned count = items.len (); + if (unlikely (!serialize (c, count))) return_trace (false); + /* TODO Umm. Just exhaust the iterator instead? Being extra + * cautious right now.. */ + for (unsigned i = 0; i < count; i++, ++items) + arrayZ[i] = *items; return_trace (true); } @@ -740,7 +819,7 @@ struct HeadlessArrayOf TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); - unsigned int count = lenP1 ? lenP1 - 1 : 0; + unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], hb_forward (ds)...))) return_trace (false); @@ -757,7 +836,7 @@ struct HeadlessArrayOf public: LenType lenP1; - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; @@ -788,6 +867,7 @@ struct ArrayOfM1 { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); + if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) if (unlikely (!c->dispatch (arrayZ[i], hb_forward (ds)...))) @@ -805,13 +885,13 @@ struct ArrayOfM1 public: LenType lenM1; - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; /* An array with sorted elements. Supports binary searching. */ -template +template struct SortedArrayOf : ArrayOf { hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } @@ -857,11 +937,14 @@ struct SortedArrayOf : ArrayOf { return *as_array ().bsearch (x, ¬_found); } template bool bfind (const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { return as_array ().bfind (x, i, not_found, to_store); } }; +template using SortedArray16Of = SortedArrayOf; +template using SortedArray32Of = SortedArrayOf; + /* * Binary-search arrays */ @@ -944,7 +1027,7 @@ struct VarSizedBinSearchArrayOf unsigned int count = Type::TerminationWordCount; for (unsigned int i = 0; i < count; i++) if (words[i] != 0xFFFFu) - return false; + return false; return true; } @@ -981,18 +1064,15 @@ struct VarSizedBinSearchArrayOf template const Type *bsearch (const T &key) const { - unsigned int size = header.unitSize; - int min = 0, max = (int) get_length () - 1; - while (min <= max) - { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); - int c = p->cmp (key); - if (c < 0) max = mid - 1; - else if (c > 0) min = mid + 1; - else return p; - } - return nullptr; + unsigned pos; + return hb_bsearch_impl (&pos, + key, + (const void *) bytesZ, + get_length (), + header.unitSize, + _hb_cmp_method) + ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) + : nullptr; } private: diff --git a/src/hb-ot-cff-common.hh b/src/hb-ot-cff-common.hh index aced77c83de1f8841f492fe5c2def1b6e5d15914..864a27f45848c63701ab401bd39d7704dd65f31a 100644 --- a/src/hb-ot-cff-common.hh +++ b/src/hb-ot-cff-common.hh @@ -38,6 +38,9 @@ using namespace OT; #define CFF_UNDEF_CODE 0xFFFFFFFF +using objidx_t = hb_serialize_context_t::objidx_t; +using whence_t = hb_serialize_context_t::whence_t; + /* utility macro */ template static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) @@ -89,11 +92,14 @@ struct CFFIndex unsigned int offset_array_size () const { return calculate_offset_array_size (offSize, count); } - static unsigned int calculate_serialized_size (unsigned int offSize_, unsigned int count, - unsigned int dataSize) + CFFIndex *copy (hb_serialize_context_t *c) const { - if (count == 0) return COUNT::static_size; - return min_size + calculate_offset_array_size (offSize_, count) + dataSize; + TRACE_SERIALIZE (this); + unsigned int size = get_size (); + CFFIndex *out = c->allocate_size (size); + if (likely (out)) + memcpy (out, this, size); + return_trace (out); } bool serialize (hb_serialize_context_t *c, const CFFIndex &src) @@ -101,7 +107,7 @@ struct CFFIndex TRACE_SERIALIZE (this); unsigned int size = src.get_size (); CFFIndex *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } @@ -114,7 +120,7 @@ struct CFFIndex if (byteArray.length == 0) { COUNT *dest = c->allocate_min (); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); *dest = 0; } else @@ -139,10 +145,9 @@ struct CFFIndex /* serialize data */ for (unsigned int i = 0; i < byteArray.length; i++) { - const byte_str_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size (bs.length); - if (unlikely (dest == nullptr)) - return_trace (false); + const byte_str_t &bs = byteArray[i]; + unsigned char *dest = c->allocate_size (bs.length); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &bs[0], bs.length); } } @@ -163,6 +168,71 @@ struct CFFIndex return result; } + template + bool serialize (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + if (it.len () == 0) + { + COUNT *dest = c->allocate_min (); + if (unlikely (!dest)) return_trace (false); + *dest = 0; + } + else + { + serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; })); + for (const auto &_ : +it) + _.copy (c); + } + return_trace (true); + } + + bool serialize (hb_serialize_context_t *c, + const byte_str_array_t &byteArray) + { return serialize (c, + hb_iter (byteArray)); } + + bool serialize (hb_serialize_context_t *c, + const str_buff_vec_t &buffArray) + { + auto it = + + hb_iter (buffArray) + | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); }) + ; + return serialize (c, it); + } + + template + bool serialize_header (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + + unsigned total = + it | hb_reduce (hb_add, 0); + unsigned off_size = calcOffSize (total); + + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count = it.len (); + this->offSize = off_size; + if (unlikely (!c->allocate_size (off_size * (it.len () + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (unsigned _ : +it) + { + CFFIndex::set_offset_at (i++, offset); + offset += _; + } + CFFIndex::set_offset_at (i, offset); + + return_trace (true); + } + void set_offset_at (unsigned int index, unsigned int offset) { HBUINT8 *p = offsets + offSize * index + offSize; @@ -189,7 +259,7 @@ struct CFFIndex unsigned int length_at (unsigned int index) const { if (unlikely ((offset_at (index + 1) < offset_at (index)) || - (offset_at (index + 1) > offset_at (count)))) + (offset_at (index + 1) > offset_at (count)))) return 0; return offset_at (index + 1) - offset_at (index); } @@ -237,8 +307,9 @@ struct CFFIndex public: COUNT count; /* Number of object data. Note there are (count+1) offsets */ HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ - HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */ - /* HBUINT8 data[VAR]; Object data */ + HBUINT8 offsets[HB_VAR_ARRAY]; + /* The array of (count + 1) offsets into objects array (1-base). */ + /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ public: DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); }; @@ -250,7 +321,7 @@ struct CFFIndexOf : CFFIndex { if (likely (index < CFFIndex::count)) return byte_str_t (CFFIndex::data_base () + CFFIndex::offset_at (index) - 1, CFFIndex::length_at (index)); - return Null(byte_str_t); + return Null (byte_str_t); } template @@ -284,85 +355,41 @@ struct CFFIndexOf : CFFIndex for (unsigned int i = 0; i < dataArrayLen; i++) { TYPE *dest = c->start_embed (); - if (unlikely (dest == nullptr || - !dest->serialize (c, dataArray[i], param1, param2))) + if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2))) return_trace (false); } return_trace (true); } - - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, - const DATA *dataArray, - unsigned int dataArrayLen, - hb_vector_t &dataSizeArray, /* OUT */ - const PARAM ¶m) - { - /* determine offset size */ - unsigned int totalDataSize = 0; - for (unsigned int i = 0; i < dataArrayLen; i++) - { - unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param); - dataSizeArray[i] = dataSize; - totalDataSize += dataSize; - } - offSize_ = calcOffSize (totalDataSize); - - return CFFIndex::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize); - } }; /* Top Dict, Font Dict, Private Dict */ struct Dict : UnsizedByteStr { - template + template bool serialize (hb_serialize_context_t *c, const DICTVAL &dictval, OP_SERIALIZER& opszr, - PARAM& param) + Ts&&... ds) { TRACE_SERIALIZE (this); for (unsigned int i = 0; i < dictval.get_count (); i++) - if (unlikely (!opszr.serialize (c, dictval[i], param))) + if (unlikely (!opszr.serialize (c, dictval[i], hb_forward (ds)...))) return_trace (false); return_trace (true); } - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (const DICTVAL &dictval, - OP_SERIALIZER& opszr, - PARAM& param) - { - unsigned int size = 0; - for (unsigned int i = 0; i < dictval.get_count (); i++) - size += opszr.calculate_serialized_size (dictval[i], param); - return size; - } - - template - static unsigned int calculate_serialized_size (const DICTVAL &dictval, - OP_SERIALIZER& opszr) - { - unsigned int size = 0; - for (unsigned int i = 0; i < dictval.get_count (); i++) - size += opszr.calculate_serialized_size (dictval[i]); - return size; - } - - template - static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp) + template + static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp) { // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation - if (/*unlikely*/ (!serialize_int (c, intOp, value))) + if (/*unlikely*/ (!serialize_int (c, intOp, value))) return false; TRACE_SERIALIZE (this); /* serialize the opcode */ HBUINT8 *p = c->allocate_size (OpCode_Size (op)); - if (unlikely (p == nullptr)) return_trace (false); + if (unlikely (!p)) return_trace (false); if (Is_OpCode_ESC (op)) { *p = OpCode_escape; @@ -373,17 +400,28 @@ struct Dict : UnsizedByteStr return_trace (true); } - static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value) - { return serialize_int_op (c, op, value, OpCode_longintdict); } + template + static bool serialize_int4_op (hb_serialize_context_t *c, op_code_t op, V value) + { return serialize_int_op (c, op, value, OpCode_longintdict); } + + template + static bool serialize_int2_op (hb_serialize_context_t *c, op_code_t op, V value) + { return serialize_int_op (c, op, value, OpCode_shortint); } - static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value) - { return serialize_int_op (c, op, value, OpCode_shortint); } + template + static bool serialize_link_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence) + { + T &ofs = *(T *) (c->head + OpCode_Size (int_op)); + if (unlikely (!serialize_int_op (c, op, 0, int_op))) return false; + c->add_link (ofs, link, whence); + return true; + } - static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value) - { return serialize_uint4_op (c, op, value); } + static bool serialize_link4_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head) + { return serialize_link_op (c, op, link, whence); } - static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value) - { return serialize_uint2_op (c, op, value); } + static bool serialize_link2_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head) + { return serialize_link_op (c, op, link, whence); } }; struct TopDict : Dict {}; @@ -392,105 +430,39 @@ struct PrivateDict : Dict {}; struct table_info_t { - void init () { offSize = offset = size = 0; } + void init () { offset = size = 0; link = 0; } unsigned int offset; unsigned int size; - unsigned int offSize; + objidx_t link; }; template struct FDArray : CFFIndexOf { - /* used by CFF1 */ - template + template bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const hb_vector_t &fontDicts, + Iterator it, OP_SERIALIZER& opszr) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count = fontDicts.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (fontDicts.length + 1)))) - return_trace (false); - - /* serialize font dict offsets */ - unsigned int offset = 1; - unsigned int fid = 0; - for (; fid < fontDicts.length; fid++) - { - CFFIndexOf::set_offset_at (fid, offset); - offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr); - } - CFFIndexOf::set_offset_at (fid, offset); - /* serialize font dicts */ - for (unsigned int i = 0; i < fontDicts.length; i++) + /* serialize INDEX data */ + hb_vector_t sizes; + c->push (); + + it + | hb_map ([&] (const hb_pair_t &_) { FontDict *dict = c->start_embed (); - if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i]))) - return_trace (false); - } - return_trace (true); - } - - /* used by CFF2 */ - template - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const hb_vector_t &fontDicts, - unsigned int fdCount, - const hb_inc_bimap_t &fdmap, - OP_SERIALIZER& opszr, - const hb_vector_t &privateInfos) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count = fdCount; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (fdCount + 1)))) - return_trace (false); - - /* serialize font dict offsets */ - unsigned int offset = 1; - unsigned int fid = 0; - for (unsigned i = 0; i < fontDicts.length; i++) - if (fdmap.has (i)) - { - if (unlikely (fid >= fdCount)) return_trace (false); - CFFIndexOf::set_offset_at (fid++, offset); - offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); - } - CFFIndexOf::set_offset_at (fid, offset); - - /* serialize font dicts */ - for (unsigned int i = 0; i < fontDicts.length; i++) - if (fdmap.has (i)) - { - FontDict *dict = c->start_embed (); - if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) - return_trace (false); - } - return_trace (true); - } - - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, - const hb_vector_t &fontDicts, - unsigned int fdCount, - const hb_inc_bimap_t &fdmap, - OP_SERIALIZER& opszr) - { - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < fontDicts.len; i++) - if (fdmap.has (i)) - dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); - - offSize_ = calcOffSize (dictsSize); - return CFFIndex::calculate_serialized_size (offSize_, fdCount, dictsSize); + dict->serialize (c, _.first, opszr, _.second); + return c->head - (const char*)dict; + }) + | hb_sink (sizes) + ; + c->pop_pack (false); + + /* serialize INDEX header */ + return_trace (CFFIndex::serialize_header (c, hb_iter (sizes))); } }; @@ -514,9 +486,9 @@ struct FDSelect0 { unsigned int get_size (unsigned int num_glyphs) const { return HBUINT8::static_size * num_glyphs; } - HBUINT8 fds[VAR]; + HBUINT8 fds[HB_VAR_ARRAY]; - DEFINE_SIZE_MIN (1); + DEFINE_SIZE_MIN (0); }; template @@ -544,7 +516,7 @@ struct FDSelect3_4 { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) || - (nRanges () == 0) || ranges[0].first != 0)) + (nRanges () == 0) || ranges[0].first != 0)) return_trace (false); for (unsigned int i = 1; i < nRanges (); i++) @@ -564,13 +536,13 @@ struct FDSelect3_4 if (glyph < ranges[i].first) break; - return (hb_codepoint_t)ranges[i - 1].fd; + return (hb_codepoint_t) ranges[i - 1].fd; } - GID_TYPE &nRanges () { return ranges.len; } - GID_TYPE nRanges () const { return ranges.len; } - GID_TYPE &sentinel () { return StructAfter (ranges[nRanges () - 1]); } - const GID_TYPE &sentinel () const { return StructAfter (ranges[nRanges () - 1]); } + GID_TYPE &nRanges () { return ranges.len; } + GID_TYPE nRanges () const { return ranges.len; } + GID_TYPE &sentinel () { return StructAfter (ranges[nRanges () - 1]); } + const GID_TYPE &sentinel () const { return StructAfter (ranges[nRanges () - 1]); } ArrayOf, GID_TYPE> ranges; /* GID_TYPE sentinel */ @@ -588,14 +560,11 @@ struct FDSelect TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); FDSelect *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } - unsigned int calculate_serialized_size (unsigned int num_glyphs) const - { return get_size (num_glyphs); } - unsigned int get_size (unsigned int num_glyphs) const { switch (format) @@ -608,8 +577,8 @@ struct FDSelect hb_codepoint_t get_fd (hb_codepoint_t glyph) const { - if (this == &Null (FDSelect)) - return 0; + if (this == &Null (FDSelect)) return 0; + switch (format) { case 0: return u.format0.get_fd (glyph); diff --git a/src/hb-ot-cff1-std-str.hh b/src/hb-ot-cff1-std-str.hh new file mode 100644 index 0000000000000000000000000000000000000000..65d56ae18b5d80f26c6af7f426ad6f3ba96a9e73 --- /dev/null +++ b/src/hb-ot-cff1-std-str.hh @@ -0,0 +1,425 @@ +/* + * Copyright © 2019 Adobe, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_CFF1_STD_STR_HH +#if 0 /* Make checks happy. */ +#define HB_OT_CFF1_STD_STR_HH +#include "hb.hh" +#endif + +_S(".notdef") +_S("space") +_S("exclam") +_S("quotedbl") +_S("numbersign") +_S("dollar") +_S("percent") +_S("ampersand") +_S("quoteright") +_S("parenleft") +_S("parenright") +_S("asterisk") +_S("plus") +_S("comma") +_S("hyphen") +_S("period") +_S("slash") +_S("zero") +_S("one") +_S("two") +_S("three") +_S("four") +_S("five") +_S("six") +_S("seven") +_S("eight") +_S("nine") +_S("colon") +_S("semicolon") +_S("less") +_S("equal") +_S("greater") +_S("question") +_S("at") +_S("A") +_S("B") +_S("C") +_S("D") +_S("E") +_S("F") +_S("G") +_S("H") +_S("I") +_S("J") +_S("K") +_S("L") +_S("M") +_S("N") +_S("O") +_S("P") +_S("Q") +_S("R") +_S("S") +_S("T") +_S("U") +_S("V") +_S("W") +_S("X") +_S("Y") +_S("Z") +_S("bracketleft") +_S("backslash") +_S("bracketright") +_S("asciicircum") +_S("underscore") +_S("quoteleft") +_S("a") +_S("b") +_S("c") +_S("d") +_S("e") +_S("f") +_S("g") +_S("h") +_S("i") +_S("j") +_S("k") +_S("l") +_S("m") +_S("n") +_S("o") +_S("p") +_S("q") +_S("r") +_S("s") +_S("t") +_S("u") +_S("v") +_S("w") +_S("x") +_S("y") +_S("z") +_S("braceleft") +_S("bar") +_S("braceright") +_S("asciitilde") +_S("exclamdown") +_S("cent") +_S("sterling") +_S("fraction") +_S("yen") +_S("florin") +_S("section") +_S("currency") +_S("quotesingle") +_S("quotedblleft") +_S("guillemotleft") +_S("guilsinglleft") +_S("guilsinglright") +_S("fi") +_S("fl") +_S("endash") +_S("dagger") +_S("daggerdbl") +_S("periodcentered") +_S("paragraph") +_S("bullet") +_S("quotesinglbase") +_S("quotedblbase") +_S("quotedblright") +_S("guillemotright") +_S("ellipsis") +_S("perthousand") +_S("questiondown") +_S("grave") +_S("acute") +_S("circumflex") +_S("tilde") +_S("macron") +_S("breve") +_S("dotaccent") +_S("dieresis") +_S("ring") +_S("cedilla") +_S("hungarumlaut") +_S("ogonek") +_S("caron") +_S("emdash") +_S("AE") +_S("ordfeminine") +_S("Lslash") +_S("Oslash") +_S("OE") +_S("ordmasculine") +_S("ae") +_S("dotlessi") +_S("lslash") +_S("oslash") +_S("oe") +_S("germandbls") +_S("onesuperior") +_S("logicalnot") +_S("mu") +_S("trademark") +_S("Eth") +_S("onehalf") +_S("plusminus") +_S("Thorn") +_S("onequarter") +_S("divide") +_S("brokenbar") +_S("degree") +_S("thorn") +_S("threequarters") +_S("twosuperior") +_S("registered") +_S("minus") +_S("eth") +_S("multiply") +_S("threesuperior") +_S("copyright") +_S("Aacute") +_S("Acircumflex") +_S("Adieresis") +_S("Agrave") +_S("Aring") +_S("Atilde") +_S("Ccedilla") +_S("Eacute") +_S("Ecircumflex") +_S("Edieresis") +_S("Egrave") +_S("Iacute") +_S("Icircumflex") +_S("Idieresis") +_S("Igrave") +_S("Ntilde") +_S("Oacute") +_S("Ocircumflex") +_S("Odieresis") +_S("Ograve") +_S("Otilde") +_S("Scaron") +_S("Uacute") +_S("Ucircumflex") +_S("Udieresis") +_S("Ugrave") +_S("Yacute") +_S("Ydieresis") +_S("Zcaron") +_S("aacute") +_S("acircumflex") +_S("adieresis") +_S("agrave") +_S("aring") +_S("atilde") +_S("ccedilla") +_S("eacute") +_S("ecircumflex") +_S("edieresis") +_S("egrave") +_S("iacute") +_S("icircumflex") +_S("idieresis") +_S("igrave") +_S("ntilde") +_S("oacute") +_S("ocircumflex") +_S("odieresis") +_S("ograve") +_S("otilde") +_S("scaron") +_S("uacute") +_S("ucircumflex") +_S("udieresis") +_S("ugrave") +_S("yacute") +_S("ydieresis") +_S("zcaron") +_S("exclamsmall") +_S("Hungarumlautsmall") +_S("dollaroldstyle") +_S("dollarsuperior") +_S("ampersandsmall") +_S("Acutesmall") +_S("parenleftsuperior") +_S("parenrightsuperior") +_S("twodotenleader") +_S("onedotenleader") +_S("zerooldstyle") +_S("oneoldstyle") +_S("twooldstyle") +_S("threeoldstyle") +_S("fouroldstyle") +_S("fiveoldstyle") +_S("sixoldstyle") +_S("sevenoldstyle") +_S("eightoldstyle") +_S("nineoldstyle") +_S("commasuperior") +_S("threequartersemdash") +_S("periodsuperior") +_S("questionsmall") +_S("asuperior") +_S("bsuperior") +_S("centsuperior") +_S("dsuperior") +_S("esuperior") +_S("isuperior") +_S("lsuperior") +_S("msuperior") +_S("nsuperior") +_S("osuperior") +_S("rsuperior") +_S("ssuperior") +_S("tsuperior") +_S("ff") +_S("ffi") +_S("ffl") +_S("parenleftinferior") +_S("parenrightinferior") +_S("Circumflexsmall") +_S("hyphensuperior") +_S("Gravesmall") +_S("Asmall") +_S("Bsmall") +_S("Csmall") +_S("Dsmall") +_S("Esmall") +_S("Fsmall") +_S("Gsmall") +_S("Hsmall") +_S("Ismall") +_S("Jsmall") +_S("Ksmall") +_S("Lsmall") +_S("Msmall") +_S("Nsmall") +_S("Osmall") +_S("Psmall") +_S("Qsmall") +_S("Rsmall") +_S("Ssmall") +_S("Tsmall") +_S("Usmall") +_S("Vsmall") +_S("Wsmall") +_S("Xsmall") +_S("Ysmall") +_S("Zsmall") +_S("colonmonetary") +_S("onefitted") +_S("rupiah") +_S("Tildesmall") +_S("exclamdownsmall") +_S("centoldstyle") +_S("Lslashsmall") +_S("Scaronsmall") +_S("Zcaronsmall") +_S("Dieresissmall") +_S("Brevesmall") +_S("Caronsmall") +_S("Dotaccentsmall") +_S("Macronsmall") +_S("figuredash") +_S("hypheninferior") +_S("Ogoneksmall") +_S("Ringsmall") +_S("Cedillasmall") +_S("questiondownsmall") +_S("oneeighth") +_S("threeeighths") +_S("fiveeighths") +_S("seveneighths") +_S("onethird") +_S("twothirds") +_S("zerosuperior") +_S("foursuperior") +_S("fivesuperior") +_S("sixsuperior") +_S("sevensuperior") +_S("eightsuperior") +_S("ninesuperior") +_S("zeroinferior") +_S("oneinferior") +_S("twoinferior") +_S("threeinferior") +_S("fourinferior") +_S("fiveinferior") +_S("sixinferior") +_S("seveninferior") +_S("eightinferior") +_S("nineinferior") +_S("centinferior") +_S("dollarinferior") +_S("periodinferior") +_S("commainferior") +_S("Agravesmall") +_S("Aacutesmall") +_S("Acircumflexsmall") +_S("Atildesmall") +_S("Adieresissmall") +_S("Aringsmall") +_S("AEsmall") +_S("Ccedillasmall") +_S("Egravesmall") +_S("Eacutesmall") +_S("Ecircumflexsmall") +_S("Edieresissmall") +_S("Igravesmall") +_S("Iacutesmall") +_S("Icircumflexsmall") +_S("Idieresissmall") +_S("Ethsmall") +_S("Ntildesmall") +_S("Ogravesmall") +_S("Oacutesmall") +_S("Ocircumflexsmall") +_S("Otildesmall") +_S("Odieresissmall") +_S("OEsmall") +_S("Oslashsmall") +_S("Ugravesmall") +_S("Uacutesmall") +_S("Ucircumflexsmall") +_S("Udieresissmall") +_S("Yacutesmall") +_S("Thornsmall") +_S("Ydieresissmall") +_S("001.000") +_S("001.001") +_S("001.002") +_S("001.003") +_S("Black") +_S("Bold") +_S("Book") +_S("Light") +_S("Medium") +_S("Regular") +_S("Roman") +_S("Semibold") + +#endif /* HB_OT_CFF1_STD_STR_HH */ diff --git a/src/hb-ot-cff1-table.cc b/src/hb-ot-cff1-table.cc index 3e4fc204f34055a61353b8e06b0eff5a947ed737..3298fa35ae6f5c64a2faf97c25b2355daec32805 100644 --- a/src/hb-ot-cff1-table.cc +++ b/src/hb-ot-cff1-table.cc @@ -28,11 +28,25 @@ #ifndef HB_NO_CFF +#include "hb-draw.hh" +#include "hb-algs.hh" #include "hb-ot-cff1-table.hh" #include "hb-cff1-interp-cs.hh" using namespace CFF; +struct sid_to_gid_t +{ + uint16_t sid; + uint8_t gid; + + int cmp (uint16_t a) const + { + if (a == sid) return 0; + return (a < sid) ? -1 : 1; + } +}; + /* SID to code */ static const uint8_t standard_encoding_to_code [] = { @@ -104,6 +118,80 @@ static const uint16_t expert_subset_charset_to_sid [] = 340, 341, 342, 343, 344, 345, 346 }; +/* SID to glyph ID */ +static const sid_to_gid_t expert_charset_sid_to_gid [] = +{ + { 1, 1 }, { 13, 12 }, { 14, 13 }, { 15, 14 }, + { 27, 26 }, { 28, 27 }, { 99, 15 }, { 109, 46 }, + { 110, 47 }, { 150, 111 }, { 155, 101 }, { 158, 100 }, + { 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 }, + { 230, 3 }, { 231, 4 }, { 232, 5 }, { 233, 6 }, + { 234, 7 }, { 235, 8 }, { 236, 9 }, { 237, 10 }, + { 238, 11 }, { 239, 16 }, { 240, 17 }, { 241, 18 }, + { 242, 19 }, { 243, 20 }, { 244, 21 }, { 245, 22 }, + { 246, 23 }, { 247, 24 }, { 248, 25 }, { 249, 28 }, + { 250, 29 }, { 251, 30 }, { 252, 31 }, { 253, 32 }, + { 254, 33 }, { 255, 34 }, { 256, 35 }, { 257, 36 }, + { 258, 37 }, { 259, 38 }, { 260, 39 }, { 261, 40 }, + { 262, 41 }, { 263, 42 }, { 264, 43 }, { 265, 44 }, + { 266, 45 }, { 267, 48 }, { 268, 49 }, { 269, 50 }, + { 270, 51 }, { 271, 52 }, { 272, 53 }, { 273, 54 }, + { 274, 55 }, { 275, 56 }, { 276, 57 }, { 277, 58 }, + { 278, 59 }, { 279, 60 }, { 280, 61 }, { 281, 62 }, + { 282, 63 }, { 283, 64 }, { 284, 65 }, { 285, 66 }, + { 286, 67 }, { 287, 68 }, { 288, 69 }, { 289, 70 }, + { 290, 71 }, { 291, 72 }, { 292, 73 }, { 293, 74 }, + { 294, 75 }, { 295, 76 }, { 296, 77 }, { 297, 78 }, + { 298, 79 }, { 299, 80 }, { 300, 81 }, { 301, 82 }, + { 302, 83 }, { 303, 84 }, { 304, 85 }, { 305, 86 }, + { 306, 87 }, { 307, 88 }, { 308, 89 }, { 309, 90 }, + { 310, 91 }, { 311, 92 }, { 312, 93 }, { 313, 94 }, + { 314, 95 }, { 315, 96 }, { 316, 97 }, { 317, 98 }, + { 318, 99 }, { 319, 103 }, { 320, 104 }, { 321, 105 }, + { 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 }, + { 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 }, + { 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 }, + { 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 }, + { 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 }, + { 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 }, + { 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 }, + { 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 }, + { 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 }, + { 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 }, + { 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 }, + { 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 }, + { 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 }, + { 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 }, + { 378, 165 } +}; + +/* SID to glyph ID */ +static const sid_to_gid_t expert_subset_charset_sid_to_gid [] = +{ + { 1, 1 }, { 13, 8 }, { 14, 9 }, { 15, 10 }, + { 27, 22 }, { 28, 23 }, { 99, 11 }, { 109, 41 }, + { 110, 42 }, { 150, 64 }, { 155, 55 }, { 158, 54 }, + { 163, 56 }, { 164, 65 }, { 169, 66 }, { 231, 2 }, + { 232, 3 }, { 235, 4 }, { 236, 5 }, { 237, 6 }, + { 238, 7 }, { 239, 12 }, { 240, 13 }, { 241, 14 }, + { 242, 15 }, { 243, 16 }, { 244, 17 }, { 245, 18 }, + { 246, 19 }, { 247, 20 }, { 248, 21 }, { 249, 24 }, + { 250, 25 }, { 251, 26 }, { 253, 27 }, { 254, 28 }, + { 255, 29 }, { 256, 30 }, { 257, 31 }, { 258, 32 }, + { 259, 33 }, { 260, 34 }, { 261, 35 }, { 262, 36 }, + { 263, 37 }, { 264, 38 }, { 265, 39 }, { 266, 40 }, + { 267, 43 }, { 268, 44 }, { 269, 45 }, { 270, 46 }, + { 272, 47 }, { 300, 48 }, { 301, 49 }, { 302, 50 }, + { 305, 51 }, { 314, 52 }, { 315, 53 }, { 320, 57 }, + { 321, 58 }, { 322, 59 }, { 323, 60 }, { 324, 61 }, + { 325, 62 }, { 326, 63 }, { 327, 67 }, { 328, 68 }, + { 329, 69 }, { 330, 70 }, { 331, 71 }, { 332, 72 }, + { 333, 73 }, { 334, 74 }, { 335, 75 }, { 336, 76 }, + { 337, 77 }, { 338, 78 }, { 339, 79 }, { 340, 80 }, + { 341, 81 }, { 342, 82 }, { 343, 83 }, { 344, 84 }, + { 345, 85 }, { 346, 86 } +}; + /* code to SID */ static const uint8_t standard_encoding_to_sid [] = { @@ -157,6 +245,18 @@ hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t gl return 0; } +hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid) +{ + const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid); + return pair ? pair->gid : 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid) +{ + const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid); + return pair ? pair->gid : 0; +} + hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code) { if (code < ARRAY_LENGTH (standard_encoding_to_sid)) @@ -203,8 +303,7 @@ struct bounds_t } } - bool empty () const - { return (min.x >= max.x) || (min.y >= max.y); } + bool empty () const { return (min.x >= max.x) || (min.y >= max.y); } point_t min; point_t max; @@ -219,12 +318,12 @@ struct cff1_extents_param_t bounds.init (); } - void start_path () { path_open = true; } - void end_path () { path_open = false; } + void start_path () { path_open = true; } + void end_path () { path_open = false; } bool is_path_open () const { return path_open; } - bool path_open; - bounds_t bounds; + bool path_open; + bounds_t bounds; const OT::cff1::accelerator_t *cff; }; @@ -307,14 +406,14 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun return true; } -bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const +bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; #endif - bounds_t bounds; + bounds_t bounds; if (!_get_bounds (this, glyph, bounds)) return false; @@ -326,8 +425,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->x_bearing = (int32_t)bounds.min.x.floor (); - extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); + extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing; } if (bounds.min.y >= bounds.max.y) { @@ -336,13 +435,137 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->y_bearing = (int32_t)bounds.max.y.ceil (); - extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); + extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing; } return true; } +#ifdef HB_EXPERIMENTAL_API +struct cff1_path_param_t +{ + cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_, + draw_helper_t &draw_helper_, point_t *delta_) + { + draw_helper = &draw_helper_; + cff = cff_; + font = font_; + delta = delta_; + } + + void move_to (const point_t &p) + { + point_t point = p; + if (delta) point.move (*delta); + draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + } + + void line_to (const point_t &p) + { + point_t point = p; + if (delta) point.move (*delta); + draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + } + + void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) + { + point_t point1 = p1, point2 = p2, point3 = p3; + if (delta) + { + point1.move (*delta); + point2.move (*delta); + point3.move (*delta); + } + draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()), + font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()), + font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ())); + } + + void end_path () { draw_helper->end_path (); } + + hb_font_t *font; + draw_helper_t *draw_helper; + point_t *delta; + + const OT::cff1::accelerator_t *cff; +}; + +struct cff1_path_procs_path_t : path_procs_t +{ + static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt) + { + param.move_to (pt); + env.moveto (pt); + } + + static void line (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1) + { + param.line_to (pt1); + env.moveto (pt1); + } + + static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { + param.cubic_to (pt1, pt2, pt3); + env.moveto (pt3); + } +}; + +static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, + draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr); + +struct cff1_cs_opset_path_t : cff1_cs_opset_t +{ + static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param) + { + /* End previous path */ + param.end_path (); + + unsigned int n = env.argStack.get_count (); + point_t delta; + delta.x = env.argStack[n-4]; + delta.y = env.argStack[n-3]; + hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ()); + hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); + + if (unlikely (!(!env.in_seac && base && accent + && _get_path (param.cff, param.font, base, *param.draw_helper, true) + && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta)))) + env.set_error (); + } +}; + +bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, + draw_helper_t &draw_helper, bool in_seac, point_t *delta) +{ + if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; + + unsigned int fd = cff->fdSelect->get_fd (glyph); + cff1_cs_interpreter_t interp; + const byte_str_t str = (*cff->charStrings)[glyph]; + interp.env.init (str, *cff, fd); + interp.env.set_in_seac (in_seac); + cff1_path_param_t param (cff, font, draw_helper, delta); + if (unlikely (!interp.interpret (param))) return false; + + /* Let's end the path specially since it is called inside seac also */ + param.end_path (); + + return true; +} + +bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +{ +#ifdef HB_NO_OT_FONT_CFF + /* XXX Remove check when this code moves to .hh file. */ + return true; +#endif + + return _get_path (this, font, glyph, draw_helper); +} +#endif + struct get_seac_param_t { void init (const OT::cff1::accelerator_t *_cff) diff --git a/src/hb-ot-cff1-table.hh b/src/hb-ot-cff1-table.hh index 4050b7d6fb9dea6227f883c08dcf3c7d45f5ee56..157483b7f65b06b0ca218d213563021dba4dd7f9 100644 --- a/src/hb-ot-cff1-table.hh +++ b/src/hb-ot-cff1-table.hh @@ -27,15 +27,21 @@ #ifndef HB_OT_CFF1_TABLE_HH #define HB_OT_CFF1_TABLE_HH -#include "hb-ot-head-table.hh" #include "hb-ot-cff-common.hh" #include "hb-subset-cff1.hh" +#include "hb-draw.hh" + +#define HB_STRING_ARRAY_NAME cff1_std_strings +#define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh" +#include "hb-string-array.hh" +#undef HB_STRING_ARRAY_LIST +#undef HB_STRING_ARRAY_NAME namespace CFF { /* * CFF -- Compact Font Format (CFF) - * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf + * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf */ #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') @@ -49,7 +55,6 @@ template struct CFF1IndexOf : CFFIndexOf {}; typedef CFFIndex CFF1Index; typedef CFF1Index CFF1CharStrings; -typedef FDArray CFF1FDArray; typedef Subrs CFF1Subrs; struct CFF1FDSelect : FDSelect {}; @@ -169,7 +174,7 @@ struct Encoding TRACE_SERIALIZE (this); unsigned int size = src.get_size (); Encoding *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } @@ -183,13 +188,13 @@ struct Encoding { TRACE_SERIALIZE (this); Encoding *dest = c->extend_min (*this); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0); switch (format) { case 0: { Encoding0 *fmt0 = c->allocate_size (Encoding0::min_size + HBUINT8::static_size * enc_count); - if (unlikely (fmt0 == nullptr)) return_trace (false); + if (unlikely (!fmt0)) return_trace (false); fmt0->nCodes () = enc_count; unsigned int glyph = 0; for (unsigned int i = 0; i < code_ranges.length; i++) @@ -206,7 +211,7 @@ struct Encoding case 1: { Encoding1 *fmt1 = c->allocate_size (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length); - if (unlikely (fmt1 == nullptr)) return_trace (false); + if (unlikely (!fmt1)) return_trace (false); fmt1->nRanges () = code_ranges.length; for (unsigned int i = 0; i < code_ranges.length; i++) { @@ -223,7 +228,7 @@ struct Encoding if (supp_codes.length) { CFF1SuppEncData *suppData = c->allocate_size (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length); - if (unlikely (suppData == nullptr)) return_trace (false); + if (unlikely (!suppData)) return_trace (false); suppData->nSups () = supp_codes.length; for (unsigned int i = 0; i < supp_codes.length; i++) { @@ -235,23 +240,6 @@ struct Encoding return_trace (true); } - /* parallel to above: calculate the size of a subset Encoding */ - static unsigned int calculate_serialized_size (uint8_t format, - unsigned int enc_count, - unsigned int supp_count) - { - unsigned int size = min_size; - switch (format) - { - case 0: size += Encoding0::min_size + HBUINT8::static_size * enc_count; break; - case 1: size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; break; - default:return 0; - } - if (supp_count > 0) - size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; - return size; - } - unsigned int get_size () const { unsigned int size = min_size; @@ -357,7 +345,7 @@ struct Charset0 { return HBUINT16::static_size * (num_glyphs - 1); } - HBUINT16 sids[VAR]; + HBUINT16 sids[HB_VAR_ARRAY]; DEFINE_SIZE_ARRAY(0, sids); }; @@ -414,7 +402,7 @@ struct Charset1_2 { for (unsigned int i = 0;; i++) { if (glyph >= num_glyphs) - return 0; + return 0; if ((ranges[i].first <= sid) && (sid <= ranges[i].first + ranges[i].nLeft)) return glyph + (sid - ranges[i].first); glyph += (ranges[i].nLeft + 1); @@ -439,7 +427,7 @@ struct Charset1_2 { return size; } - Charset_Range ranges[VAR]; + Charset_Range ranges[HB_VAR_ARRAY]; DEFINE_SIZE_ARRAY (0, ranges); }; @@ -457,7 +445,7 @@ struct Charset TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); Charset *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } @@ -470,14 +458,14 @@ struct Charset { TRACE_SERIALIZE (this); Charset *dest = c->extend_min (*this); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); dest->format = format; switch (format) { case 0: { Charset0 *fmt0 = c->allocate_size (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); - if (unlikely (fmt0 == nullptr)) return_trace (false); + if (unlikely (!fmt0)) return_trace (false); unsigned int glyph = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { @@ -491,10 +479,10 @@ struct Charset case 1: { Charset1 *fmt1 = c->allocate_size (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); - if (unlikely (fmt1 == nullptr)) return_trace (false); + if (unlikely (!fmt1)) return_trace (false); for (unsigned int i = 0; i < sid_ranges.length; i++) { - if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) + if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) return_trace (false); fmt1->ranges[i].first = sid_ranges[i].code; fmt1->ranges[i].nLeft = sid_ranges[i].glyph; @@ -505,10 +493,10 @@ struct Charset case 2: { Charset2 *fmt2 = c->allocate_size (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); - if (unlikely (fmt2 == nullptr)) return_trace (false); + if (unlikely (!fmt2)) return_trace (false); for (unsigned int i = 0; i < sid_ranges.length; i++) { - if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) + if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) return_trace (false); fmt2->ranges[i].first = sid_ranges[i].code; fmt2->ranges[i].nLeft = sid_ranges[i].glyph; @@ -520,19 +508,6 @@ struct Charset return_trace (true); } - /* parallel to above: calculate the size of a subset Charset */ - static unsigned int calculate_serialized_size (uint8_t format, - unsigned int count) - { - switch (format) - { - case 0: return min_size + Charset0::min_size + HBUINT16::static_size * (count - 1); - case 1: return min_size + Charset1::min_size + Charset1_Range::static_size * count; - case 2: return min_size + Charset2::min_size + Charset2_Range::static_size * count; - default:return 0; - } - } - unsigned int get_size (unsigned int num_glyphs) const { switch (format) @@ -544,8 +519,9 @@ struct Charset } } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const { + if (unlikely (glyph >= num_glyphs)) return 0; switch (format) { case 0: return u.format0.get_sid (glyph); @@ -594,7 +570,7 @@ struct Charset struct CFF1StringIndex : CFF1Index { bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, - unsigned int offSize_, const hb_inc_bimap_t &sidmap) + const hb_inc_bimap_t &sidmap) { TRACE_SERIALIZE (this); if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0))) @@ -612,30 +588,14 @@ struct CFF1StringIndex : CFF1Index for (unsigned int i = 0; i < strings.count; i++) { hb_codepoint_t j = sidmap[i]; - if (j != CFF_UNDEF_CODE) + if (j != HB_MAP_VALUE_INVALID) bytesArray[j] = strings[i]; } - bool result = CFF1Index::serialize (c, offSize_, bytesArray); + bool result = CFF1Index::serialize (c, bytesArray); bytesArray.fini (); return_trace (result); } - - /* in parallel to above */ - unsigned int calculate_serialized_size (unsigned int &offSize_ /*OUT*/, const hb_inc_bimap_t &sidmap) const - { - offSize_ = 0; - if ((count == 0) || (sidmap.get_population () == 0)) - return count.static_size; - - unsigned int dataSize = 0; - for (unsigned int i = 0; i < count; i++) - if (sidmap[i] != CFF_UNDEF_CODE) - dataSize += length_at (i); - - offSize_ = calcOffSize(dataSize); - return CFF1Index::calculate_serialized_size (offSize_, sidmap.get_population (), dataSize); - } }; struct cff1_top_dict_interp_env_t : num_interp_env_t @@ -738,7 +698,7 @@ struct cff1_top_dict_values_t : top_dict_values_t unsigned int EncodingOffset; unsigned int CharsetOffset; unsigned int FDSelectOffset; - table_info_t privateDictInfo; + table_info_t privateDictInfo; }; struct cff1_top_dict_opset_t : top_dict_opset_t @@ -880,21 +840,10 @@ struct cff1_private_dict_values_base_t : dict_values_t { dict_values_t::init (); subrsOffset = 0; - localSubrs = &Null(CFF1Subrs); + localSubrs = &Null (CFF1Subrs); } void fini () { dict_values_t::fini (); } - unsigned int calculate_serialized_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < dict_values_t::get_count; i++) - if (dict_values_t::get_value (i).op == OpCode_Subrs) - size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); - else - size += dict_values_t::get_value (i).str.length; - return size; - } - unsigned int subrsOffset; const CFF1Subrs *localSubrs; }; @@ -997,6 +946,37 @@ typedef dict_interpreter_t cff1 typedef CFF1Index CFF1NameIndex; typedef CFF1IndexOf CFF1TopDictIndex; +struct cff1_font_dict_values_mod_t +{ + cff1_font_dict_values_mod_t() { init (); } + + void init () { init ( &Null (cff1_font_dict_values_t), CFF_UNDEF_SID ); } + + void init (const cff1_font_dict_values_t *base_, + unsigned int fontName_) + { + base = base_; + fontName = fontName_; + privateDictInfo.init (); + } + + unsigned get_count () const { return base->get_count (); } + + const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } + + const cff1_font_dict_values_t *base; + table_info_t privateDictInfo; + unsigned int fontName; +}; + +struct CFF1FDArray : FDArray +{ + /* FDArray::serialize() requires this partial specialization to compile */ + template + bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) + { return FDArray::serialize (c, it, opszr); } +}; + } /* namespace CFF */ namespace OT { @@ -1031,7 +1011,7 @@ struct cff1 const OT::cff1 *cff = this->blob->template as (); - if (cff == &Null(OT::cff1)) + if (cff == &Null (OT::cff1)) { fini (); return; } nameIndex = &cff->nameIndex (cff); @@ -1052,7 +1032,7 @@ struct cff1 } if (is_predef_charset ()) - charset = &Null(Charset); + charset = &Null (Charset); else { charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset); @@ -1064,16 +1044,30 @@ struct cff1 { fdArray = &StructAtOffsetOrNull (cff, topDict.FDArrayOffset); fdSelect = &StructAtOffsetOrNull (cff, topDict.FDSelectOffset); - if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || - (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) + if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) || + (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) { fini (); return; } fdCount = fdArray->count; } else { - fdArray = &Null(CFF1FDArray); - fdSelect = &Null(CFF1FDSelect); + fdArray = &Null (CFF1FDArray); + fdSelect = &Null (CFF1FDSelect); + } + + encoding = &Null (Encoding); + if (is_CID ()) + { + if (unlikely (charset == &Null (Charset))) { fini (); return; } + } + else + { + if (!is_predef_encoding ()) + { + encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset); + if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + } } stringIndex = &StructAtOffset (topDictIndex, topDictIndex->get_size ()); @@ -1086,14 +1080,15 @@ struct cff1 charStrings = &StructAtOffsetOrNull (cff, topDict.charStringsOffset); - if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) + if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) { fini (); return; } num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) { fini (); return; } - privateDicts.resize (fdCount); + if (unlikely (!privateDicts.resize (fdCount))) + { fini (); return; } for (unsigned int i = 0; i < fdCount; i++) privateDicts[i].init (); @@ -1104,14 +1099,14 @@ struct cff1 { byte_str_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } - cff1_font_dict_values_t *font; + cff1_font_dict_values_t *font; cff1_font_dict_interpreter_t font_interp; font_interp.env.init (fontDictStr); font = fontDicts.push (); - if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; } + if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; } font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } - PRIVDICTVAL *priv = &privateDicts[i]; + PRIVDICTVAL *priv = &privateDicts[i]; const byte_str_t privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } dict_interpreter_t priv_interp; @@ -1120,15 +1115,15 @@ struct cff1 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset); - if (priv->localSubrs != &Null(CFF1Subrs) && + if (priv->localSubrs != &Null (CFF1Subrs) && unlikely (!priv->localSubrs->sanitize (&sc))) { fini (); return; } } } else /* non-CID */ { - cff1_top_dict_values_t *font = &topDict; - PRIVDICTVAL *priv = &privateDicts[0]; + cff1_top_dict_values_t *font = &topDict; + PRIVDICTVAL *priv = &privateDicts[0]; const byte_str_t privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } @@ -1138,7 +1133,7 @@ struct cff1 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset); - if (priv->localSubrs != &Null(CFF1Subrs) && + if (priv->localSubrs != &Null (CFF1Subrs) && unlikely (!priv->localSubrs->sanitize (&sc))) { fini (); return; } } @@ -1154,8 +1149,8 @@ struct cff1 blob = nullptr; } - bool is_valid () const { return blob != nullptr; } - bool is_CID () const { return topDict.is_CID (); } + bool is_valid () const { return blob; } + bool is_CID () const { return topDict.is_CID (); } bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; } @@ -1165,149 +1160,237 @@ struct cff1 if (unlikely (sid == CFF_UNDEF_SID)) return 0; - if (charset != &Null(Charset)) + if (charset != &Null (Charset)) return charset->get_glyph (sid, num_glyphs); else if ((topDict.CharsetOffset == ISOAdobeCharset) && (code <= 228 /*zcaron*/)) return sid; return 0; } - protected: - hb_blob_t *blob; - hb_sanitize_context_t sc; - - public: - const Charset *charset; - const CFF1NameIndex *nameIndex; - const CFF1TopDictIndex *topDictIndex; - const CFF1StringIndex *stringIndex; - const CFF1Subrs *globalSubrs; - const CFF1CharStrings *charStrings; - const CFF1FDArray *fdArray; - const CFF1FDSelect *fdSelect; - unsigned int fdCount; - - cff1_top_dict_values_t topDict; - hb_vector_t fontDicts; - hb_vector_t privateDicts; - - unsigned int num_glyphs; - }; - - struct accelerator_t : accelerator_templ_t - { - HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; - HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; - }; + bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } - struct accelerator_subset_t : accelerator_templ_t - { - void init (hb_face_t *face) + hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const { - SUPER::init (face); - if (blob == nullptr) return; - - const OT::cff1 *cff = this->blob->as (); - encoding = &Null(Encoding); - if (is_CID ()) - { - if (unlikely (charset == &Null(Charset))) { fini (); return; } - } + if (encoding != &Null (Encoding)) + return encoding->get_code (glyph); else { - if (!is_predef_encoding ()) + hb_codepoint_t sid = glyph_to_sid (glyph); + if (sid == 0) return 0; + hb_codepoint_t code = 0; + switch (topDict.EncodingOffset) { - encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset); - if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + case StandardEncoding: + code = lookup_standard_encoding_for_code (sid); + break; + case ExpertEncoding: + code = lookup_expert_encoding_for_code (sid); + break; + default: + break; } + return code; } } - bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } - - hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const { - if (encoding != &Null(Encoding)) - return encoding->get_code (glyph); + if (charset != &Null (Charset)) + return charset->get_sid (glyph, num_glyphs); else { - hb_codepoint_t sid = glyph_to_sid (glyph); - if (sid == 0) return 0; - hb_codepoint_t code = 0; - switch (topDict.EncodingOffset) + hb_codepoint_t sid = 0; + switch (topDict.CharsetOffset) { - case StandardEncoding: - code = lookup_standard_encoding_for_code (sid); + case ISOAdobeCharset: + if (glyph <= 228 /*zcaron*/) sid = glyph; break; - case ExpertEncoding: - code = lookup_expert_encoding_for_code (sid); + case ExpertCharset: + sid = lookup_expert_charset_for_sid (glyph); + break; + case ExpertSubsetCharset: + sid = lookup_expert_subset_charset_for_sid (glyph); break; default: break; } - return code; + return sid; } } - hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const + hb_codepoint_t sid_to_glyph (hb_codepoint_t sid) const { - if (charset != &Null(Charset)) - return charset->get_sid (glyph); + if (charset != &Null (Charset)) + return charset->get_glyph (sid, num_glyphs); else { - hb_codepoint_t sid = 0; + hb_codepoint_t glyph = 0; switch (topDict.CharsetOffset) { - case ISOAdobeCharset: - if (glyph <= 228 /*zcaron*/) sid = glyph; + case ISOAdobeCharset: + if (sid <= 228 /*zcaron*/) glyph = sid; break; - case ExpertCharset: - sid = lookup_expert_charset_for_sid (glyph); + case ExpertCharset: + glyph = lookup_expert_charset_for_glyph (sid); break; - case ExpertSubsetCharset: - sid = lookup_expert_subset_charset_for_sid (glyph); + case ExpertSubsetCharset: + glyph = lookup_expert_subset_charset_for_glyph (sid); break; default: break; } - return sid; + return glyph; } } - const Encoding *encoding; + protected: + hb_blob_t *blob; + hb_sanitize_context_t sc; + + public: + const Encoding *encoding; + const Charset *charset; + const CFF1NameIndex *nameIndex; + const CFF1TopDictIndex *topDictIndex; + const CFF1StringIndex *stringIndex; + const CFF1Subrs *globalSubrs; + const CFF1CharStrings *charStrings; + const CFF1FDArray *fdArray; + const CFF1FDSelect *fdSelect; + unsigned int fdCount; - private: - typedef accelerator_templ_t SUPER; + cff1_top_dict_values_t topDict; + hb_vector_t + fontDicts; + hb_vector_t privateDicts; + + unsigned int num_glyphs; }; - bool subset (hb_subset_plan_t *plan) const + struct accelerator_t : accelerator_templ_t { - hb_blob_t *cff_prime = nullptr; - - bool success = true; - if (hb_subset_cff1 (plan, &cff_prime)) { - success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime); - hb_blob_t *head_blob = hb_sanitize_context_t().reference_table (plan->source); - success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); - hb_blob_destroy (head_blob); - } else { - success = false; + void init (hb_face_t *face) + { + SUPER::init (face); + + if (!is_valid ()) return; + if (is_CID ()) return; + + /* fill glyph_names */ + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t sid = glyph_to_sid (gid); + gname_t gname; + gname.sid = sid; + if (sid < cff1_std_strings_length) + gname.name = cff1_std_strings (sid); + else + { + byte_str_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; + gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length); + } + if (unlikely (!gname.name.arrayZ)) { fini (); return; } + glyph_names.push (gname); + } + glyph_names.qsort (); } - hb_blob_destroy (cff_prime); - return success; - } + void fini () + { + glyph_names.fini (); + + SUPER::fini (); + } + + bool get_glyph_name (hb_codepoint_t glyph, + char *buf, unsigned int buf_len) const + { + if (!buf) return true; + if (unlikely (!is_valid ())) return false; + if (is_CID()) return false; + hb_codepoint_t sid = glyph_to_sid (glyph); + const char *str; + size_t str_len; + if (sid < cff1_std_strings_length) + { + hb_bytes_t byte_str = cff1_std_strings (sid); + str = byte_str.arrayZ; + str_len = byte_str.length; + } + else + { + byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; + str = (const char *)ubyte_str.arrayZ; + str_len = ubyte_str.length; + } + if (!str_len) return false; + unsigned int len = hb_min (buf_len - 1, str_len); + strncpy (buf, (const char*)str, len); + buf[len] = '\0'; + return true; + } + + bool get_glyph_from_name (const char *name, int len, + hb_codepoint_t *glyph) const + { + if (len < 0) len = strlen (name); + if (unlikely (!len)) return false; + + gname_t key = { hb_bytes_t (name, len), 0 }; + const gname_t *gname = glyph_names.bsearch (key); + if (!gname) return false; + hb_codepoint_t gid = sid_to_glyph (gname->sid); + if (!gid && gname->sid) return false; + *glyph = gid; + return true; + } + + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; +#ifdef HB_EXPERIMENTAL_API + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; +#endif + + private: + struct gname_t + { + hb_bytes_t name; + uint16_t sid; + + static int cmp (const void *a_, const void *b_) + { + const gname_t *a = (const gname_t *)a_; + const gname_t *b = (const gname_t *)b_; + int minlen = hb_min (a->name.length, b->name.length); + int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen); + if (ret) return ret; + return a->name.length - b->name.length; + } + + int cmp (const gname_t &a) const { return cmp (&a, this); } + }; + + hb_sorted_vector_t glyph_names; + + typedef accelerator_templ_t SUPER; + }; + + struct accelerator_subset_t : accelerator_templ_t {}; + + bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); } protected: HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_glyph (hb_codepoint_t sid); + HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid); HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); public: FixedVersion version; /* Version of CFF table. set to 0x0100u */ - OffsetTo nameIndex; /* headerSize = Offset to Name INDEX. */ + NNOffsetTo nameIndex; /* headerSize = Offset to Name INDEX. */ HBUINT8 offSize; /* offset size (unused?) */ public: diff --git a/src/hb-ot-cff2-table.cc b/src/hb-ot-cff2-table.cc index 0251efac8b582b09b1d56c468c078c0f6f0b64b0..879b7cdb2304d290d62060064df9f18e69544711 100644 --- a/src/hb-ot-cff2-table.cc +++ b/src/hb-ot-cff2-table.cc @@ -30,6 +30,7 @@ #include "hb-ot-cff2-table.hh" #include "hb-cff2-interp-cs.hh" +#include "hb-draw.hh" using namespace CFF; @@ -44,8 +45,8 @@ struct cff2_extents_param_t max_y.set_int (INT_MIN); } - void start_path () { path_open = true; } - void end_path () { path_open = false; } + void start_path () { path_open = true; } + void end_path () { path_open = false; } bool is_path_open () const { return path_open; } void update_bounds (const point_t &pt) @@ -125,8 +126,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = (int32_t)param.min_x.floor (); - extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); + extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing; } if (param.min_y >= param.max_y) { @@ -135,12 +136,80 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = (int32_t)param.max_y.ceil (); - extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); + extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing; } return true; } +#ifdef HB_EXPERIMENTAL_API +struct cff2_path_param_t +{ + cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_) + { + draw_helper = &draw_helper_; + font = font_; + } + + void move_to (const point_t &p) + { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + + void line_to (const point_t &p) + { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + + void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) + { + draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()), + font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()), + font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ())); + } + + protected: + draw_helper_t *draw_helper; + hb_font_t *font; +}; + +struct cff2_path_procs_path_t : path_procs_t +{ + static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt) + { + param.move_to (pt); + env.moveto (pt); + } + + static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1) + { + param.line_to (pt1); + env.moveto (pt1); + } + + static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { + param.cubic_to (pt1, pt2, pt3); + env.moveto (pt3); + } +}; + +struct cff2_cs_opset_path_t : cff2_cs_opset_t {}; + +bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +{ +#ifdef HB_NO_OT_FONT_CFF + /* XXX Remove check when this code moves to .hh file. */ + return true; +#endif + + if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + + unsigned int fd = fdSelect->get_fd (glyph); + cff2_cs_interpreter_t interp; + const byte_str_t str = (*charStrings)[glyph]; + interp.env.init (str, *this, fd, font->coords, font->num_coords); + cff2_path_param_t param (font, draw_helper); + if (unlikely (!interp.interpret (param))) return false; + return true; +} +#endif #endif diff --git a/src/hb-ot-cff2-table.hh b/src/hb-ot-cff2-table.hh index 8646cde58d600bc106b38031d4aa79657a7576dd..829217feaa224ff1af0bc89c240f7bf1666aaf06 100644 --- a/src/hb-ot-cff2-table.hh +++ b/src/hb-ot-cff2-table.hh @@ -27,9 +27,9 @@ #ifndef HB_OT_CFF2_TABLE_HH #define HB_OT_CFF2_TABLE_HH -#include "hb-ot-head-table.hh" #include "hb-ot-cff-common.hh" #include "hb-subset-cff2.hh" +#include "hb-draw.hh" namespace CFF { @@ -43,7 +43,6 @@ typedef CFFIndex CFF2Index; template struct CFF2IndexOf : CFFIndexOf {}; typedef CFF2Index CFF2CharStrings; -typedef FDArray CFF2FDArray; typedef Subrs CFF2Subrs; typedef FDSelect3_4 FDSelect4; @@ -56,14 +55,11 @@ struct CFF2FDSelect TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); CFF2FDSelect *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } - unsigned int calculate_serialized_size (unsigned int num_glyphs) const - { return get_size (num_glyphs); } - unsigned int get_size (unsigned int num_glyphs) const { switch (format) @@ -127,7 +123,7 @@ struct CFF2VariationStore TRACE_SERIALIZE (this); unsigned int size_ = varStore->get_size (); CFF2VariationStore *dest = c->allocate_size (size_); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, varStore, size_); return_trace (true); } @@ -150,26 +146,6 @@ struct cff2_top_dict_values_t : top_dict_values_t<> } void fini () { top_dict_values_t<>::fini (); } - unsigned int calculate_serialized_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < get_count (); i++) - { - op_code_t op = get_value (i).op; - switch (op) - { - case OpCode_vstore: - case OpCode_FDSelect: - size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); - break; - default: - size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i)); - break; - } - } - return size; - } - unsigned int vstoreOffset; unsigned int FDSelectOffset; }; @@ -256,22 +232,11 @@ struct cff2_private_dict_values_base_t : dict_values_t { dict_values_t::init (); subrsOffset = 0; - localSubrs = &Null(CFF2Subrs); + localSubrs = &Null (CFF2Subrs); ivs = 0; } void fini () { dict_values_t::fini (); } - unsigned int calculate_serialized_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < dict_values_t::get_count; i++) - if (dict_values_t::get_value (i).op == OpCode_Subrs) - size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); - else - size += dict_values_t::get_value (i).str.length; - return size; - } - unsigned int subrsOffset; const CFF2Subrs *localSubrs; unsigned int ivs; @@ -404,6 +369,14 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t typedef dict_interpreter_t cff2_top_dict_interpreter_t; typedef dict_interpreter_t cff2_font_dict_interpreter_t; +struct CFF2FDArray : FDArray +{ + /* FDArray::serialize does not compile without this partial specialization */ + template + bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) + { return FDArray::serialize (c, it, opszr); } +}; + } /* namespace CFF */ namespace OT { @@ -438,7 +411,7 @@ struct cff2 const OT::cff2 *cff2 = this->blob->template as (); - if (cff2 == &Null(OT::cff2)) + if (cff2 == &Null (OT::cff2)) { fini (); return; } { /* parse top dict */ @@ -456,11 +429,11 @@ struct cff2 fdArray = &StructAtOffsetOrNull (cff2, topDict.FDArrayOffset); fdSelect = &StructAtOffsetOrNull (cff2, topDict.FDSelectOffset); - if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || - (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || - (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || - (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || - (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) + if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || + (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || + (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || + (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || + (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) { fini (); return; } num_glyphs = charStrings->count; @@ -468,7 +441,8 @@ struct cff2 { fini (); return; } fdCount = fdArray->count; - privateDicts.resize (fdCount); + if (!privateDicts.resize (fdCount)) + { fini (); return; } /* parse font dicts and gather private dicts */ for (unsigned int i = 0; i < fdCount; i++) @@ -479,7 +453,7 @@ struct cff2 cff2_font_dict_interpreter_t font_interp; font_interp.env.init (fontDictStr); font = fontDicts.push (); - if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; } + if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; } font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } @@ -491,7 +465,7 @@ struct cff2 if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; } privateDicts[i].localSubrs = &StructAtOffsetOrNull (&privDictStr[0], privateDicts[i].subrsOffset); - if (privateDicts[i].localSubrs != &Null(CFF2Subrs) && + if (privateDicts[i].localSubrs != &Null (CFF2Subrs) && unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) { fini (); return; } } @@ -507,7 +481,7 @@ struct cff2 blob = nullptr; } - bool is_valid () const { return blob != nullptr; } + bool is_valid () const { return blob; } protected: hb_blob_t *blob; @@ -533,27 +507,14 @@ struct cff2 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; +#ifdef HB_EXPERIMENTAL_API + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; +#endif }; typedef accelerator_templ_t accelerator_subset_t; - bool subset (hb_subset_plan_t *plan) const - { - hb_blob_t *cff2_prime = nullptr; - - bool success = true; - if (hb_subset_cff2 (plan, &cff2_prime)) { - success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime); - hb_blob_t *head_blob = hb_sanitize_context_t().reference_table (plan->source); - success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); - hb_blob_destroy (head_blob); - } else { - success = false; - } - hb_blob_destroy (cff2_prime); - - return success; - } + bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); } public: FixedVersion version; /* Version of CFF2 table. set to 0x0200u */ diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index 23ea4659d207a37af9d821a590d50bcfbe5f02de..add21f11550a64baead9dfe5b0b7757e3ecd1b5d 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -56,6 +56,18 @@ struct CmapSubtableFormat0 out->add (i); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + for (unsigned i = 0; i < 256; i++) + if (glyphIdArray[i]) + { + hb_codepoint_t glyph = glyphIdArray[i]; + unicodes->add (i); + mapping->set (i, glyph); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -76,25 +88,23 @@ struct CmapSubtableFormat4 { template + hb_requires (hb_is_iterator (Iterator))> HBUINT16* serialize_endcode_array (hb_serialize_context_t *c, - Iterator it) + Iterator it) { HBUINT16 *endCode = c->start_embed (); hb_codepoint_t prev_endcp = 0xFFFF; - + it - | hb_apply ([&] (const hb_item_type _) - { - if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first) - { - HBUINT16 end_code; - end_code = prev_endcp; - c->copy (end_code); - } - prev_endcp = _.first; - }) - ; + for (const auto& _ : +it) + { + if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first) + { + HBUINT16 end_code; + end_code = prev_endcp; + c->copy (end_code); + } + prev_endcp = _.first; + } { // last endCode @@ -104,9 +114,9 @@ struct CmapSubtableFormat4 // There must be a final entry with end_code == 0xFFFF. if (prev_endcp != 0xFFFF) { - HBUINT16 finalcode; - finalcode = 0xFFFF; - if (unlikely (!c->copy (finalcode))) return nullptr; + HBUINT16 finalcode; + finalcode = 0xFFFF; + if (unlikely (!c->copy (finalcode))) return nullptr; } } @@ -114,26 +124,24 @@ struct CmapSubtableFormat4 } template + hb_requires (hb_is_iterator (Iterator))> HBUINT16* serialize_startcode_array (hb_serialize_context_t *c, - Iterator it) + Iterator it) { HBUINT16 *startCode = c->start_embed (); hb_codepoint_t prev_cp = 0xFFFF; - - + it - | hb_apply ([&] (const hb_item_type _) - { - if (prev_cp == 0xFFFF || prev_cp + 1u != _.first) - { - HBUINT16 start_code; - start_code = _.first; - c->copy (start_code); - } - - prev_cp = _.first; - }) - ; + + for (const auto& _ : +it) + { + if (prev_cp == 0xFFFF || prev_cp + 1u != _.first) + { + HBUINT16 start_code; + start_code = _.first; + c->copy (start_code); + } + + prev_cp = _.first; + } // There must be a final entry with end_code == 0xFFFF. if (it.len () == 0 || prev_cp != 0xFFFF) @@ -147,45 +155,43 @@ struct CmapSubtableFormat4 } template + hb_requires (hb_is_iterator (Iterator))> HBINT16* serialize_idDelta_array (hb_serialize_context_t *c, - Iterator it, - HBUINT16 *endCode, - HBUINT16 *startCode, - unsigned segcount) + Iterator it, + HBUINT16 *endCode, + HBUINT16 *startCode, + unsigned segcount) { unsigned i = 0; hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF; bool use_delta = true; - + HBINT16 *idDelta = c->start_embed (); if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size) return nullptr; - + it - | hb_apply ([&] (const hb_item_type _) - { - if (_.first == startCode[i]) - { - use_delta = true; - start_gid = _.second; - } - else if (_.second != last_gid + 1) use_delta = false; - - if (_.first == endCode[i]) - { - HBINT16 delta; - if (use_delta) delta = (int)start_gid - (int)startCode[i]; - else delta = 0; - c->copy (delta); - - i++; - } - - last_gid = _.second; - last_cp = _.first; - }) - ; + for (const auto& _ : +it) + { + if (_.first == startCode[i]) + { + use_delta = true; + start_gid = _.second; + } + else if (_.second != last_gid + 1) use_delta = false; + + if (_.first == endCode[i]) + { + HBINT16 delta; + if (use_delta) delta = (int)start_gid - (int)startCode[i]; + else delta = 0; + c->copy (delta); + + i++; + } + + last_gid = _.second; + last_cp = _.first; + } if (it.len () == 0 || last_cp != 0xFFFF) { @@ -198,71 +204,81 @@ struct CmapSubtableFormat4 } template + hb_requires (hb_is_iterator (Iterator))> HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, - Iterator it, - HBUINT16 *endCode, - HBUINT16 *startCode, - HBINT16 *idDelta, - unsigned segcount) + Iterator it, + HBUINT16 *endCode, + HBUINT16 *startCode, + HBINT16 *idDelta, + unsigned segcount) { HBUINT16 *idRangeOffset = c->allocate_size (HBUINT16::static_size * segcount); if (unlikely (!c->check_success (idRangeOffset))) return nullptr; if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; - + + hb_range (segcount) | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }) | hb_apply ([&] (const unsigned i) - { - idRangeOffset[i] = 2 * (c->start_embed () - idRangeOffset - i); + { + idRangeOffset[i] = 2 * (c->start_embed () - idRangeOffset - i); - + it - | hb_filter ([&] (const hb_item_type _) { return _.first >= startCode[i] && _.first <= endCode[i]; }) - | hb_apply ([&] (const hb_item_type _) - { - HBUINT16 glyID; - glyID = _.second; - c->copy (glyID); - }) - ; + + it + | hb_filter ([&] (const hb_item_type _) { return _.first >= startCode[i] && _.first <= endCode[i]; }) + | hb_apply ([&] (const hb_item_type _) + { + HBUINT16 glyID; + glyID = _.second; + c->copy (glyID); + }) + ; - }) + }) ; return idRangeOffset; } template + hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it) { + auto format4_iter = + + it + | hb_filter ([&] (const hb_pair_t _) + { return _.first <= 0xFFFF; }) + ; + + if (format4_iter.len () == 0) return; + unsigned table_initpos = c->length (); if (unlikely (!c->extend_min (*this))) return; this->format = 4; //serialize endCode[] - HBUINT16 *endCode = serialize_endcode_array (c, it); + HBUINT16 *endCode = serialize_endcode_array (c, format4_iter); if (unlikely (!endCode)) return; unsigned segcount = (c->length () - min_size) / HBUINT16::static_size; - + // 2 bytes of padding. if (unlikely (!c->allocate_size (HBUINT16::static_size))) return; // 2 bytes of padding. // serialize startCode[] - HBUINT16 *startCode = serialize_startcode_array (c, it); + HBUINT16 *startCode = serialize_startcode_array (c, format4_iter); if (unlikely (!startCode)) return; - + //serialize idDelta[] - HBINT16 *idDelta = serialize_idDelta_array (c, it, endCode, startCode, segcount); + HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount); if (unlikely (!idDelta)) return; - HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, it, endCode, startCode, idDelta, segcount); + HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount); if (unlikely (!c->check_success (idRangeOffset))) return; - - if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return; + + if (unlikely (!c->check_assign(this->length, + c->length () - table_initpos, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) return; this->segCountX2 = segcount * 2; this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1; this->searchRange = 2 * (1u << this->entrySelector); @@ -291,27 +307,28 @@ struct CmapSubtableFormat4 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - /* Custom two-array bsearch. */ - int min = 0, max = (int) this->segCount - 1; - const HBUINT16 *startCount = this->startCount; - const HBUINT16 *endCount = this->endCount; - unsigned int i; - while (min <= max) + struct CustomRange { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - if (codepoint < startCount[mid]) - max = mid - 1; - else if (codepoint > endCount[mid]) - min = mid + 1; - else + int cmp (hb_codepoint_t k, + unsigned distance) const { - i = mid; - goto found; + if (k > last) return +1; + if (k < (&last)[distance]) return -1; + return 0; } - } - return false; + HBUINT16 last; + }; + + const HBUINT16 *found = hb_bsearch (codepoint, + this->endCount, + this->segCount, + 2, + _hb_cmp_method, + this->segCount + 1); + if (!found) + return false; + unsigned int i = found - endCount; - found: hb_codepoint_t gid; unsigned int rangeOffset = this->idRangeOffset[i]; if (rangeOffset == 0) @@ -333,10 +350,10 @@ struct CmapSubtableFormat4 *glyph = gid; return true; } + HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) - { - return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); - } + { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); } + void collect_unicodes (hb_set_t *out) const { unsigned int count = this->segCount; @@ -344,14 +361,22 @@ struct CmapSubtableFormat4 count--; /* Skip sentinel segment. */ for (unsigned int i = 0; i < count; i++) { + hb_codepoint_t start = this->startCount[i]; + hb_codepoint_t end = this->endCount[i]; unsigned int rangeOffset = this->idRangeOffset[i]; if (rangeOffset == 0) - out->add_range (this->startCount[i], this->endCount[i]); + { + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) + { + hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; + if (unlikely (!gid)) + continue; + out->add (codepoint); + } + } else { - for (hb_codepoint_t codepoint = this->startCount[i]; - codepoint <= this->endCount[i]; - codepoint++) + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) { unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; if (unlikely (index >= this->glyphIdArrayLength)) @@ -365,6 +390,45 @@ struct CmapSubtableFormat4 } } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + unsigned count = this->segCount; + if (count && this->startCount[count - 1] == 0xFFFFu) + count--; /* Skip sentinel segment. */ + for (unsigned i = 0; i < count; i++) + { + hb_codepoint_t start = this->startCount[i]; + hb_codepoint_t end = this->endCount[i]; + unsigned rangeOffset = this->idRangeOffset[i]; + if (rangeOffset == 0) + { + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) + { + hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; + if (unlikely (!gid)) + continue; + unicodes->add (codepoint); + mapping->set (codepoint, gid); + } + } + else + { + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) + { + unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; + if (unlikely (index >= this->glyphIdArrayLength)) + break; + hb_codepoint_t gid = this->glyphIdArray[index]; + if (unlikely (!gid)) + continue; + unicodes->add (codepoint); + mapping->set (codepoint, gid); + } + } + } + } + const HBUINT16 *endCount; const HBUINT16 *startCount; const HBUINT16 *idDelta; @@ -385,6 +449,13 @@ struct CmapSubtableFormat4 accel.collect_unicodes (out); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + accelerator_t accel (this); + accel.collect_mapping (unicodes, mapping); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -397,8 +468,8 @@ struct CmapSubtableFormat4 * If that is the case, just change the value to truncate * the subtable at the end of the blob. */ uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535, - (uintptr_t) (c->end - - (char *) this)); + (uintptr_t) (c->end - + (char *) this)); if (!c->try_set (&length, new_length)) return_trace (false); } @@ -487,6 +558,21 @@ struct CmapSubtableTrimmed out->add (start + i); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + hb_codepoint_t start_cp = startCharCode; + unsigned count = glyphIdArray.len; + for (unsigned i = 0; i < count; i++) + if (glyphIdArray[i]) + { + hb_codepoint_t unicode = start_cp + i; + hb_codepoint_t glyphid = glyphIdArray[i]; + unicodes->add (unicode); + mapping->set (unicode, glyphid); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -498,7 +584,7 @@ struct CmapSubtableTrimmed UINT length; /* Byte length of this subtable. */ UINT language; /* Ignore. */ UINT startCharCode; /* First character code covered. */ - ArrayOf + ArrayOf glyphIdArray; /* Array of glyph index values for character * codes in the range. */ public: @@ -522,12 +608,56 @@ struct CmapSubtableLongSegmented return true; } - void collect_unicodes (hb_set_t *out) const + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const { - for (unsigned int i = 0; i < this->groups.len; i++) { - out->add_range (this->groups[i].startCharCode, - hb_min ((hb_codepoint_t) this->groups[i].endCharCode, - (hb_codepoint_t) HB_UNICODE_MAX)); + for (unsigned int i = 0; i < this->groups.len; i++) + { + hb_codepoint_t start = this->groups[i].startCharCode; + hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, + (hb_codepoint_t) HB_UNICODE_MAX); + hb_codepoint_t gid = this->groups[i].glyphID; + if (!gid) + { + /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */ + if (! T::group_get_glyph (this->groups[i], end)) continue; + start++; + gid++; + } + if (unlikely ((unsigned int) gid >= num_glyphs)) continue; + if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) + end = start + (hb_codepoint_t) num_glyphs - gid; + + out->add_range (start, end); + } + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping, /* OUT */ + unsigned num_glyphs) const + { + for (unsigned i = 0; i < this->groups.len; i++) + { + hb_codepoint_t start = this->groups[i].startCharCode; + hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, + (hb_codepoint_t) HB_UNICODE_MAX); + hb_codepoint_t gid = this->groups[i].glyphID; + if (!gid) + { + /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */ + if (! T::group_get_glyph (this->groups[i], end)) continue; + start++; + gid++; + } + if (unlikely ((unsigned int) gid >= num_glyphs)) continue; + if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) + end = start + (hb_codepoint_t) num_glyphs - gid; + + for (unsigned cp = start; cp <= end; cp++) + { + unicodes->add (cp); + mapping->set (cp, gid); + gid++; + } } } @@ -542,7 +672,7 @@ struct CmapSubtableLongSegmented HBUINT16 reserved; /* Reserved; set to 0. */ HBUINT32 length; /* Byte length of this subtable. */ HBUINT32 language; /* Ignore. */ - SortedArrayOf + SortedArray32Of groups; /* Groupings. */ public: DEFINE_SIZE_ARRAY (16, groups); @@ -557,7 +687,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented template + hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it) { @@ -568,33 +698,29 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; hb_codepoint_t glyphID = 0; - + it - | hb_apply ([&] (const hb_item_type _) - { - if (startCharCode == 0xFFFF) - { - startCharCode = _.first; - endCharCode = _.first; - glyphID = _.second; - } - else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second)) - { - CmapSubtableLongGroup grouprecord; - grouprecord.startCharCode = startCharCode; - grouprecord.endCharCode = endCharCode; - grouprecord.glyphID = glyphID; - c->copy (grouprecord); - - startCharCode = _.first; - endCharCode = _.first; - glyphID = _.second; - } - else - { - endCharCode = _.first; - } - }) - ; + for (const auto& _ : +it) + { + if (startCharCode == 0xFFFF) + { + startCharCode = _.first; + endCharCode = _.first; + glyphID = _.second; + } + else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second)) + { + CmapSubtableLongGroup grouprecord; + grouprecord.startCharCode = startCharCode; + grouprecord.endCharCode = endCharCode; + grouprecord.glyphID = glyphID; + c->copy (grouprecord); + + startCharCode = _.first; + endCharCode = _.first; + glyphID = _.second; + } + else + endCharCode = _.first; + } CmapSubtableLongGroup record; record.startCharCode = startCharCode; @@ -609,14 +735,12 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented } static size_t get_sub_table_size (const hb_sorted_vector_t &groups_data) - { - return 16 + 12 * groups_data.length; - } + { return 16 + 12 * groups_data.length; } - private: + private: static bool _is_gid_consecutive (hb_codepoint_t endCharCode, - hb_codepoint_t startCharCode, - hb_codepoint_t glyphID, + hb_codepoint_t startCharCode, + hb_codepoint_t glyphID, hb_codepoint_t cp, hb_codepoint_t new_gid) { @@ -662,7 +786,7 @@ struct UnicodeValueRange DEFINE_SIZE_STATIC (4); }; -struct DefaultUVS : SortedArrayOf +struct DefaultUVS : SortedArray32Of { void collect_unicodes (hb_set_t *out) const { @@ -671,11 +795,70 @@ struct DefaultUVS : SortedArrayOf { hb_codepoint_t first = arrayZ[i].startUnicodeValue; hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), - (hb_codepoint_t) HB_UNICODE_MAX); + (hb_codepoint_t) HB_UNICODE_MAX); out->add_range (first, last); } } + DefaultUVS* copy (hb_serialize_context_t *c, + const hb_set_t *unicodes) const + { + DefaultUVS *out = c->start_embed (); + if (unlikely (!out)) return nullptr; + auto snap = c->snapshot (); + + HBUINT32 len; + len = 0; + if (unlikely (!c->copy (len))) return nullptr; + unsigned init_len = c->length (); + + hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID; + int count = -1; + + for (const UnicodeValueRange& _ : as_array ()) + { + for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1)) + { + unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt; + if (!unicodes->has (curEntry)) continue; + count += 1; + if (lastCode == HB_MAP_VALUE_INVALID) + lastCode = curEntry; + else if (lastCode + count != curEntry) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count - 1; + c->copy (rec); + + lastCode = curEntry; + count = 0; + } + } + } + + if (lastCode != HB_MAP_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count; + c->copy (rec); + } + + if (c->length () - init_len == 0) + { + c->revert (snap); + return nullptr; + } + else + { + if (unlikely (!c->check_assign (out->len, + (c->length () - init_len) / UnicodeValueRange::static_size, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr; + return out; + } + } + public: DEFINE_SIZE_ARRAY (4, *this); }; @@ -683,9 +866,7 @@ struct DefaultUVS : SortedArrayOf struct UVSMapping { int cmp (const hb_codepoint_t &codepoint) const - { - return unicodeValue.cmp (codepoint); - } + { return unicodeValue.cmp (codepoint); } bool sanitize (hb_sanitize_context_t *c) const { @@ -694,18 +875,72 @@ struct UVSMapping } HBUINT24 unicodeValue; /* Base Unicode value of the UVS */ - GlyphID glyphID; /* Glyph ID of the UVS */ + HBGlyphID glyphID; /* Glyph ID of the UVS */ public: DEFINE_SIZE_STATIC (5); }; -struct NonDefaultUVS : SortedArrayOf +struct NonDefaultUVS : SortedArray32Of { void collect_unicodes (hb_set_t *out) const { - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - out->add (arrayZ[i].glyphID); + for (const auto& a : as_array ()) + out->add (a.unicodeValue); + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + for (const auto& a : as_array ()) + { + hb_codepoint_t unicode = a.unicodeValue; + hb_codepoint_t glyphid = a.glyphID; + unicodes->add (unicode); + mapping->set (unicode, glyphid); + } + } + + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const + { + + as_array () + | hb_filter (unicodes, &UVSMapping::unicodeValue) + | hb_map (&UVSMapping::glyphID) + | hb_sink (glyphset) + ; + } + + NonDefaultUVS* copy (hb_serialize_context_t *c, + const hb_set_t *unicodes, + const hb_set_t *glyphs_requested, + const hb_map_t *glyph_map) const + { + NonDefaultUVS *out = c->start_embed (); + if (unlikely (!out)) return nullptr; + + auto it = + + as_array () + | hb_filter ([&] (const UVSMapping& _) + { + return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID); + }) + ; + + if (!it) return nullptr; + + HBUINT32 len; + len = it.len (); + if (unlikely (!c->copy (len))) return nullptr; + + for (const UVSMapping& _ : it) + { + UVSMapping mapping; + mapping.unicodeValue = _.unicodeValue; + mapping.glyphID = glyph_map->get (_.glyphID); + c->copy (mapping); + } + + return out; } public: @@ -729,17 +964,37 @@ struct VariationSelectorRecord return GLYPH_VARIANT_NOT_FOUND; } + VariationSelectorRecord(const VariationSelectorRecord& other) + { + *this = other; + } + + void operator= (const VariationSelectorRecord& other) + { + varSelector = other.varSelector; + HBUINT32 offset = other.defaultUVS; + defaultUVS = offset; + offset = other.nonDefaultUVS; + nonDefaultUVS = offset; + } + void collect_unicodes (hb_set_t *out, const void *base) const { (base+defaultUVS).collect_unicodes (out); (base+nonDefaultUVS).collect_unicodes (out); } - int cmp (const hb_codepoint_t &variation_selector) const + void collect_mapping (const void *base, + hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const { - return varSelector.cmp (variation_selector); + (base+defaultUVS).collect_unicodes (unicodes); + (base+nonDefaultUVS).collect_mapping (unicodes, mapping); } + int cmp (const hb_codepoint_t &variation_selector) const + { return varSelector.cmp (variation_selector); } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -748,10 +1003,49 @@ struct VariationSelectorRecord nonDefaultUVS.sanitize (c, base)); } + hb_pair_t + copy (hb_serialize_context_t *c, + const hb_set_t *unicodes, + const hb_set_t *glyphs_requested, + const hb_map_t *glyph_map, + const void *base) const + { + auto snap = c->snapshot (); + auto *out = c->embed (*this); + if (unlikely (!out)) return hb_pair (0, 0); + + out->defaultUVS = 0; + out->nonDefaultUVS = 0; + + unsigned non_default_uvs_objidx = 0; + if (nonDefaultUVS != 0) + { + c->push (); + if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map)) + non_default_uvs_objidx = c->pop_pack (); + else c->pop_discard (); + } + + unsigned default_uvs_objidx = 0; + if (defaultUVS != 0) + { + c->push (); + if (c->copy (base+defaultUVS, unicodes)) + default_uvs_objidx = c->pop_pack (); + else c->pop_discard (); + } + + + if (!default_uvs_objidx && !non_default_uvs_objidx) + c->revert (snap); + + return hb_pair (default_uvs_objidx, non_default_uvs_objidx); + } + HBUINT24 varSelector; /* Variation selector. */ - LOffsetTo + Offset32To defaultUVS; /* Offset to Default UVS Table. May be 0. */ - LOffsetTo + Offset32To nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ public: DEFINE_SIZE_STATIC (11); @@ -762,20 +1056,121 @@ struct CmapSubtableFormat14 glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const - { - return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); - } + { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); } void collect_variation_selectors (hb_set_t *out) const { - unsigned int count = record.len; - for (unsigned int i = 0; i < count; i++) - out->add (record.arrayZ[i].varSelector); + for (const auto& a : record.as_array ()) + out->add (a.varSelector); } void collect_variation_unicodes (hb_codepoint_t variation_selector, hb_set_t *out) const + { record.bsearch (variation_selector).collect_unicodes (out, this); } + + void serialize (hb_serialize_context_t *c, + const hb_set_t *unicodes, + const hb_set_t *glyphs_requested, + const hb_map_t *glyph_map, + const void *base) + { + auto snap = c->snapshot (); + unsigned table_initpos = c->length (); + const char* init_tail = c->tail; + + if (unlikely (!c->extend_min (*this))) return; + this->format = 14; + + auto src_tbl = reinterpret_cast (base); + + /* + * Some versions of OTS require that offsets are in order. Due to the use + * of push()/pop_pack() serializing the variation records in order results + * in the offsets being in reverse order (first record has the largest + * offset). While this is perfectly valid, it will cause some versions of + * OTS to consider this table bad. + * + * So to prevent this issue we serialize the variation records in reverse + * order, so that the offsets are ordered from small to large. Since + * variation records are supposed to be in increasing order of varSelector + * we then have to reverse the order of the written variation selector + * records after everything is finalized. + */ + hb_vector_t> obj_indices; + for (int i = src_tbl->record.len - 1; i >= 0; i--) + { + hb_pair_t result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base); + if (result.first || result.second) + obj_indices.push (result); + } + + if (c->length () - table_initpos == CmapSubtableFormat14::min_size) + { + c->revert (snap); + return; + } + + if (unlikely (!c->check_success (!obj_indices.in_error ()))) + return; + + int tail_len = init_tail - c->tail; + c->check_assign (this->length, c->length () - table_initpos + tail_len, + HB_SERIALIZE_ERROR_INT_OVERFLOW); + c->check_assign (this->record.len, + (c->length () - table_initpos - CmapSubtableFormat14::min_size) / + VariationSelectorRecord::static_size, + HB_SERIALIZE_ERROR_INT_OVERFLOW); + + /* Correct the incorrect write order by reversing the order of the variation + records array. */ + _reverse_variation_records (); + + /* Now that records are in the right order, we can set up the offsets. */ + _add_links_to_variation_records (c, obj_indices); + } + + void _reverse_variation_records () { - record.bsearch (variation_selector).collect_unicodes (out, this); + record.as_array ().reverse (); + } + + void _add_links_to_variation_records (hb_serialize_context_t *c, + const hb_vector_t>& obj_indices) + { + for (unsigned i = 0; i < obj_indices.length; i++) + { + /* + * Since the record array has been reversed (see comments in copy()) + * but obj_indices has not been, the indices at obj_indices[i] + * are for the variation record at record[j]. + */ + int j = obj_indices.length - 1 - i; + c->add_link (record[j].defaultUVS, obj_indices[i].first); + c->add_link (record[j].nonDefaultUVS, obj_indices[i].second); + } + } + + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const + { + + hb_iter (record) + | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS) + | hb_map (&VariationSelectorRecord::nonDefaultUVS) + | hb_map (hb_add (this)) + | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); }) + ; + } + + void collect_unicodes (hb_set_t *out) const + { + for (const VariationSelectorRecord& _ : record) + _.collect_unicodes (out, this); + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + for (const VariationSelectorRecord& _ : record) + _.collect_mapping (this, unicodes, mapping); } bool sanitize (hb_sanitize_context_t *c) const @@ -788,7 +1183,7 @@ struct CmapSubtableFormat14 protected: HBUINT16 format; /* Format number is set to 14. */ HBUINT32 length; /* Byte length of this subtable. */ - SortedArrayOf + SortedArray32Of record; /* Variation selector records; sorted * in increasing order of `varSelector'. */ public: @@ -813,29 +1208,48 @@ struct CmapSubtable default: return false; } } - void collect_unicodes (hb_set_t *out) const + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const { switch (u.format) { case 0: u.format0 .collect_unicodes (out); return; case 4: u.format4 .collect_unicodes (out); return; case 6: u.format6 .collect_unicodes (out); return; case 10: u.format10.collect_unicodes (out); return; - case 12: u.format12.collect_unicodes (out); return; - case 13: u.format13.collect_unicodes (out); return; + case 12: u.format12.collect_unicodes (out, num_glyphs); return; + case 13: u.format13.collect_unicodes (out, num_glyphs); return; + case 14: + default: return; + } + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping, /* OUT */ + unsigned num_glyphs = UINT_MAX) const + { + switch (u.format) { + case 0: u.format0 .collect_mapping (unicodes, mapping); return; + case 4: u.format4 .collect_mapping (unicodes, mapping); return; + case 6: u.format6 .collect_mapping (unicodes, mapping); return; + case 10: u.format10.collect_mapping (unicodes, mapping); return; + case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return; + case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return; case 14: default: return; } } template + hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it, - unsigned format) + unsigned format, + const hb_subset_plan_t *plan, + const void *base) { switch (format) { - case 4: u.format4.serialize (c, it); return; - case 12: u.format12.serialize (c, it); return; + case 4: return u.format4.serialize (c, it); + case 12: return u.format12.serialize (c, it); + case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base); default: return; } } @@ -892,14 +1306,16 @@ struct EncodingRecord } template + hb_requires (hb_is_iterator (Iterator))> EncodingRecord* copy (hb_serialize_context_t *c, - Iterator it, - unsigned format, - void *base, - /* INOUT */ unsigned *objidx) const + Iterator it, + unsigned format, + const void *base, + const hb_subset_plan_t *plan, + /* INOUT */ unsigned *objidx) const { TRACE_SERIALIZE (this); + auto snap = c->snapshot (); auto *out = c->embed (this); if (unlikely (!out)) return_trace (nullptr); out->subtable = 0; @@ -908,18 +1324,24 @@ struct EncodingRecord { CmapSubtable *cmapsubtable = c->push (); unsigned origin_length = c->length (); - cmapsubtable->serialize (c, it, format); + cmapsubtable->serialize (c, it, format, plan, &(base+subtable)); if (c->length () - origin_length > 0) *objidx = c->pop_pack (); else c->pop_discard (); } - c->add_link (out->subtable, *objidx, base); + if (*objidx == 0) + { + c->revert (snap); + return_trace (nullptr); + } + + c->add_link (out->subtable, *objidx); return_trace (out); } HBUINT16 platformID; /* Platform ID. */ HBUINT16 encodingID; /* Platform-specific encoding ID. */ - LOffsetTo + Offset32To subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ public: DEFINE_SIZE_STATIC (8); @@ -929,27 +1351,73 @@ struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; - template + template void serialize (hb_serialize_context_t *c, - Iterator it, - const EncodingRecord *unicode_bmp, - const EncodingRecord *unicode_ucs4, - const EncodingRecord *ms_bmp, - const EncodingRecord *ms_ucs4) + Iterator it, + EncodingRecIter encodingrec_iter, + const void *base, + const hb_subset_plan_t *plan) { if (unlikely (!c->extend_min ((*this)))) return; this->version = 0; - unsigned numTables = (unicode_bmp ? 1 : 0) + (unicode_ucs4 ? 1 : 0) + (ms_bmp ? 1 : 0) + (ms_ucs4 ? 1 : 0); - if (unlikely (!c->check_assign(this->encodingRecord.len, numTables))) return; + unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; - unsigned format4objidx = 0, format12objidx = 0; - if (unicode_bmp) c->copy (unicode_bmp, it, 4u, this, &format4objidx); - if (unicode_ucs4) c->copy (unicode_ucs4, it, 12u, this, &format12objidx); - if (ms_bmp) c->copy (ms_bmp, it, 4u, this, &format4objidx); - if (ms_ucs4) c->copy (ms_ucs4, it, 12u, this, &format12objidx); + for (const EncodingRecord& _ : encodingrec_iter) + { + unsigned format = (base+_.subtable).u.format; + if (!plan->glyphs_requested->is_empty ()) + { + hb_set_t unicodes_set; + hb_map_t cp_glyphid_map; + (base+_.subtable).collect_mapping (&unicodes_set, &cp_glyphid_map); + + auto table_iter = + + hb_zip (unicodes_set.iter(), unicodes_set.iter() | hb_map(cp_glyphid_map)) + | hb_filter (plan->_glyphset, hb_second) + | hb_filter ([plan] (const hb_pair_t& p) + { + return plan->unicodes->has (p.first) || + plan->glyphs_requested->has (p.second); + }) + | hb_map ([plan] (const hb_pair_t& p_org) + { + return hb_pair_t (p_org.first, plan->glyph_map->get(p_org.second)); + }) + ; + + if (format == 4) c->copy (_, table_iter, 4u, base, plan, &format4objidx); + else if (format == 12) c->copy (_, table_iter, 12u, base, plan, &format12objidx); + else if (format == 14) c->copy (_, table_iter, 14u, base, plan, &format14objidx); + } + /* when --gids option is not used, we iterate input unicodes instead of + * all codepoints in each subtable, which is more efficient */ + else + { + hb_set_t unicodes_set; + (base+_.subtable).collect_unicodes (&unicodes_set); + if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx); + else if (format == 12) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx); + else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); + } + } + + c->check_assign(this->encodingRecord.len, + (c->length () - cmap::min_size)/EncodingRecord::static_size, + HB_SERIALIZE_ERROR_INT_OVERFLOW); + } + + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const + { + + hb_iter (encodingRecord) + | hb_map (&EncodingRecord::subtable) + | hb_map (hb_add (this)) + | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; }) + | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); }) + ; } bool subset (hb_subset_context_t *c) const @@ -959,31 +1427,53 @@ struct cmap cmap *cmap_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false); - const EncodingRecord *unicode_bmp = find_encodingrec (0, 3); - const EncodingRecord *unicode_ucs4 = find_encodingrec (0, 4); - const EncodingRecord *ms_bmp = find_encodingrec (3, 1); - const EncodingRecord *ms_ucs4 = find_encodingrec (3, 10); - bool has_format12 = find_subtable (12); + auto encodingrec_iter = + + hb_iter (encodingRecord) + | hb_filter ([&] (const EncodingRecord& _) + { + if ((_.platformID == 0 && _.encodingID == 3) || + (_.platformID == 0 && _.encodingID == 4) || + (_.platformID == 3 && _.encodingID == 1) || + (_.platformID == 3 && _.encodingID == 10) || + (this + _.subtable).u.format == 14) + return true; + + return false; + }) + ; + + if (unlikely (!encodingrec_iter.len ())) return_trace (false); - if (unlikely (!unicode_bmp && !ms_bmp)) return_trace (false); - if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); + const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr; + bool has_format12 = false; + + for (const EncodingRecord& _ : encodingrec_iter) + { + unsigned format = (this + _.subtable).u.format; + if (format == 12) has_format12 = true; + + const EncodingRecord *table = hb_addressof (_); + if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table; + else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table; + else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table; + else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table; + } + if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false); + if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); auto it = + hb_iter (c->plan->unicodes) | hb_map ([&] (hb_codepoint_t _) - { - hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; - c->plan->new_gid_for_codepoint (_, &new_gid); - return hb_pair_t (_, new_gid); - }) + { + hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; + c->plan->new_gid_for_codepoint (_, &new_gid); + return hb_pair_t (_, new_gid); + }) | hb_filter ([&] (const hb_pair_t _) - { - return (_.second != HB_MAP_VALUE_INVALID); - }) + { return (_.second != HB_MAP_VALUE_INVALID); }) ; - - cmap_prime->serialize (c->serializer, it, unicode_bmp, unicode_ucs4, ms_bmp, ms_ucs4); + cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan); return_trace (true); } @@ -1034,9 +1524,9 @@ struct cmap this->get_glyph_data = subtable; if (unlikely (symbol)) - { this->get_glyph_funcZ = get_glyph_from_symbol; - } else { + else + { switch (subtable->u.format) { /* Accelerate format 4 and format 12. */ default: @@ -1046,20 +1536,20 @@ struct cmap this->get_glyph_funcZ = get_glyph_from; break; case 4: - { - this->format4_accel.init (&subtable->u.format4); - this->get_glyph_data = &this->format4_accel; - this->get_glyph_funcZ = this->format4_accel.get_glyph_func; - } + { + this->format4_accel.init (&subtable->u.format4); + this->get_glyph_data = &this->format4_accel; + this->get_glyph_funcZ = this->format4_accel.get_glyph_func; break; } + } } } void fini () { this->table.destroy (); } bool get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph) const { if (unlikely (!this->get_glyph_funcZ)) return false; return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); @@ -1102,19 +1592,16 @@ struct cmap return get_nominal_glyph (unicode, glyph); } - void collect_unicodes (hb_set_t *out) const - { - subtable->collect_unicodes (out); - } + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const + { subtable->collect_unicodes (out, num_glyphs); } + void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping, + unsigned num_glyphs = UINT_MAX) const + { subtable->collect_mapping (unicodes, mapping, num_glyphs); } void collect_variation_selectors (hb_set_t *out) const - { - subtable_uvs->collect_variation_selectors (out); - } + { subtable_uvs->collect_variation_selectors (out); } void collect_variation_unicodes (hb_codepoint_t variation_selector, hb_set_t *out) const - { - subtable_uvs->collect_variation_unicodes (variation_selector, out); - } + { subtable_uvs->collect_variation_unicodes (variation_selector, out); } protected: typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, @@ -1161,6 +1648,7 @@ struct cmap CmapSubtableFormat4::accelerator_t format4_accel; + public: hb_blob_ptr_t table; }; @@ -1181,7 +1669,7 @@ struct cmap } const EncodingRecord *find_encodingrec (unsigned int platform_id, - unsigned int encoding_id) const + unsigned int encoding_id) const { EncodingRecord key; key.platformID = platform_id; @@ -1213,9 +1701,9 @@ struct cmap } protected: - HBUINT16 version; /* Table version number (0). */ - SortedArrayOf - encodingRecord; /* Encoding tables. */ + HBUINT16 version; /* Table version number (0). */ + SortedArray16Of + encodingRecord; /* Encoding tables. */ public: DEFINE_SIZE_ARRAY (4, encodingRecord); }; diff --git a/src/hb-ot-color-cbdt-table.hh b/src/hb-ot-color-cbdt-table.hh index 7955cf65162bed9aeeb018cbdd8d35363f034755..265d8309daaee9fef0594a4edb5792851a24da8e 100644 --- a/src/hb-ot-color-cbdt-table.hh +++ b/src/hb-ot-color-cbdt-table.hh @@ -21,7 +21,7 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Google Author(s): Seigo Nonaka + * Google Author(s): Seigo Nonaka, Calder Kitagawa */ #ifndef HB_OT_COLOR_CBDT_TABLE_HH @@ -43,6 +43,35 @@ namespace OT { +struct cblc_bitmap_size_subset_context_t +{ + const char *cbdt; + unsigned int cbdt_length; + hb_vector_t *cbdt_prime; + unsigned int size; /* INOUT + * Input: old size of IndexSubtable + * Output: new size of IndexSubtable + */ + unsigned int num_tables; /* INOUT + * Input: old number of subtables. + * Output: new number of subtables. + */ + hb_codepoint_t start_glyph; /* OUT */ + hb_codepoint_t end_glyph; /* OUT */ +}; + +static inline bool +_copy_data_to_cbdt (hb_vector_t *cbdt_prime, + const void *data, + unsigned length) +{ + unsigned int new_len = cbdt_prime->length + length; + if (unlikely (!cbdt_prime->alloc (new_len))) return false; + memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); + cbdt_prime->length = new_len; + return true; +} + struct SmallGlyphMetrics { bool sanitize (hb_sanitize_context_t *c) const @@ -51,12 +80,12 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const { - extents->x_bearing = bearingX; - extents->y_bearing = bearingY; - extents->width = width; - extents->height = - (hb_position_t) height; + extents->x_bearing = font->em_scale_x (bearingX); + extents->y_bearing = font->em_scale_y (bearingY); + extents->width = font->em_scale_x (width); + extents->height = font->em_scale_y (-static_cast(height)); } HBUINT8 height; @@ -65,7 +94,7 @@ struct SmallGlyphMetrics HBINT8 bearingY; HBUINT8 advance; public: - DEFINE_SIZE_STATIC(5); + DEFINE_SIZE_STATIC (5); }; struct BigGlyphMetrics : SmallGlyphMetrics @@ -74,7 +103,7 @@ struct BigGlyphMetrics : SmallGlyphMetrics HBINT8 vertBearingY; HBUINT8 vertAdvance; public: - DEFINE_SIZE_STATIC(8); + DEFINE_SIZE_STATIC (8); }; struct SBitLineMetrics @@ -98,7 +127,7 @@ struct SBitLineMetrics HBINT8 padding1; HBINT8 padding2; public: - DEFINE_SIZE_STATIC(12); + DEFINE_SIZE_STATIC (12); }; @@ -118,7 +147,7 @@ struct IndexSubtableHeader HBUINT16 imageFormat; HBUINT32 imageDataOffset; public: - DEFINE_SIZE_STATIC(8); + DEFINE_SIZE_STATIC (8); }; template @@ -143,11 +172,23 @@ struct IndexSubtableFormat1Or3 return true; } + bool add_offset (hb_serialize_context_t *c, + unsigned int offset, + unsigned int *size /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + Offset embedded_offset; + embedded_offset = offset; + *size += sizeof (OffsetType); + auto *o = c->embed (embedded_offset); + return_trace ((bool) o); + } + IndexSubtableHeader header; UnsizedArrayOf> - offsetArrayZ; + offsetArrayZ; public: - DEFINE_SIZE_ARRAY(8, offsetArrayZ); + DEFINE_SIZE_ARRAY (8, offsetArrayZ); }; struct IndexSubtableFormat1 : IndexSubtableFormat1Or3 {}; @@ -159,35 +200,153 @@ struct IndexSubtable { TRACE_SANITIZE (this); if (!u.header.sanitize (c)) return_trace (false); - switch (u.header.indexFormat) { + switch (u.header.indexFormat) + { case 1: return_trace (u.format1.sanitize (c, glyph_count)); case 3: return_trace (u.format3.sanitize (c, glyph_count)); default:return_trace (true); } } + bool + finish_subtable (hb_serialize_context_t *c, + unsigned int cbdt_prime_len, + unsigned int num_glyphs, + unsigned int *size /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + + unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset; + switch (u.header.indexFormat) + { + case 1: return_trace (u.format1.add_offset (c, local_offset, size)); + case 3: { + if (!u.format3.add_offset (c, local_offset, size)) + return_trace (false); + if (!(num_glyphs & 0x01)) // Pad to 32-bit alignment if needed. + return_trace (u.format3.add_offset (c, 0, size)); + return_trace (true); + } + // TODO: implement 2, 4, 5. + case 2: case 4: // No-op. + case 5: // Pad to 32-bit aligned. + default: return_trace (false); + } + } + + bool + fill_missing_glyphs (hb_serialize_context_t *c, + unsigned int cbdt_prime_len, + unsigned int num_missing, + unsigned int *size /* OUT (accumulated) */, + unsigned int *num_glyphs /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + + unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset; + switch (u.header.indexFormat) + { + case 1: { + for (unsigned int i = 0; i < num_missing; i++) + { + if (unlikely (!u.format1.add_offset (c, local_offset, size))) + return_trace (false); + *num_glyphs += 1; + } + return_trace (true); + } + case 3: { + for (unsigned int i = 0; i < num_missing; i++) + { + if (unlikely (!u.format3.add_offset (c, local_offset, size))) + return_trace (false); + *num_glyphs += 1; + } + return_trace (true); + } + // TODO: implement 2, 4, 5. + case 2: // Add empty space in cbdt_prime?. + case 4: case 5: // No-op as sparse is supported. + default: return_trace (false); + } + } + + bool + copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx, + const char *cbdt, unsigned int cbdt_length, + hb_vector_t *cbdt_prime /* INOUT */, + IndexSubtable *subtable_prime /* INOUT */, + unsigned int *size /* OUT (accumulated) */) const + { + TRACE_SERIALIZE (this); + + unsigned int offset, length, format; + if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false); + if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false); + + auto *header_prime = subtable_prime->get_header (); + unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset; + if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false); + + return_trace (subtable_prime->add_offset (c, new_local_offset, size)); + } + + bool + add_offset (hb_serialize_context_t *c, unsigned int local_offset, + unsigned int *size /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + switch (u.header.indexFormat) + { + case 1: return_trace (u.format1.add_offset (c, local_offset, size)); + case 3: return_trace (u.format3.add_offset (c, local_offset, size)); + // TODO: Implement tables 2, 4, 5 + case 2: // Should be a no-op. + case 4: case 5: // Handle sparse cases. + default: return_trace (false); + } + } + bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const { - switch (u.header.indexFormat) { + switch (u.header.indexFormat) + { case 2: case 5: /* TODO */ case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */ default:return (false); } } - bool get_image_data (unsigned int idx, - unsigned int *offset, - unsigned int *length, - unsigned int *format) const + bool + get_image_data (unsigned int idx, unsigned int *offset, + unsigned int *length, unsigned int *format) const { *format = u.header.imageFormat; - switch (u.header.indexFormat) { + switch (u.header.indexFormat) + { case 1: return u.format1.get_image_data (idx, offset, length); case 3: return u.format3.get_image_data (idx, offset, length); default: return false; } } + const IndexSubtableHeader* get_header () const { return &u.header; } + + void populate_header (unsigned index_format, + unsigned image_format, + unsigned int image_data_offset, + unsigned int *size) + { + u.header.indexFormat = index_format; + u.header.imageFormat = image_format; + u.header.imageDataOffset = image_data_offset; + switch (u.header.indexFormat) + { + case 1: *size += IndexSubtableFormat1::min_size; break; + case 3: *size += IndexSubtableFormat3::min_size; break; + } + } + protected: union { IndexSubtableHeader header; @@ -209,12 +368,135 @@ struct IndexSubtableRecord offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); } - bool get_extents (hb_glyph_extents_t *extents, - const void *base) const + const IndexSubtable* get_subtable (const void *base) const { - return (base+offsetToSubtable).get_extents (extents); + return &(base+offsetToSubtable); } + bool add_new_subtable (hb_subset_context_t* c, + cblc_bitmap_size_subset_context_t *bitmap_size_context, + IndexSubtableRecord *record, + const hb_vector_t> *lookup, /* IN */ + const void *base, + unsigned int *start /* INOUT */) const + { + TRACE_SERIALIZE (this); + + auto *subtable = c->serializer->start_embed (); + if (unlikely (!subtable)) return_trace (false); + if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false); + + auto *old_subtable = get_subtable (base); + auto *old_header = old_subtable->get_header (); + + subtable->populate_header (old_header->indexFormat, + old_header->imageFormat, + bitmap_size_context->cbdt_prime->length, + &bitmap_size_context->size); + + unsigned int num_glyphs = 0; + bool early_exit = false; + for (unsigned int i = *start; i < lookup->length; i++) + { + hb_codepoint_t new_gid = (*lookup)[i].first; + const IndexSubtableRecord *next_record = (*lookup)[i].second; + const IndexSubtable *next_subtable = next_record->get_subtable (base); + auto *next_header = next_subtable->get_header (); + if (next_header != old_header) + { + *start = i; + early_exit = true; + break; + } + unsigned int num_missing = record->add_glyph_for_subset (new_gid); + if (unlikely (!subtable->fill_missing_glyphs (c->serializer, + bitmap_size_context->cbdt_prime->length, + num_missing, + &bitmap_size_context->size, + &num_glyphs))) + return_trace (false); + + hb_codepoint_t old_gid = 0; + c->plan->old_gid_for_new_gid (new_gid, &old_gid); + if (old_gid < next_record->firstGlyphIndex) + return_trace (false); + + unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex; + if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer, + old_idx, + bitmap_size_context->cbdt, + bitmap_size_context->cbdt_length, + bitmap_size_context->cbdt_prime, + subtable, + &bitmap_size_context->size))) + return_trace (false); + num_glyphs += 1; + } + if (!early_exit) + *start = lookup->length; + if (unlikely (!subtable->finish_subtable (c->serializer, + bitmap_size_context->cbdt_prime->length, + num_glyphs, + &bitmap_size_context->size))) + return_trace (false); + return_trace (true); + } + + bool add_new_record (hb_subset_context_t *c, + cblc_bitmap_size_subset_context_t *bitmap_size_context, + const hb_vector_t> *lookup, /* IN */ + const void *base, + unsigned int *start, /* INOUT */ + hb_vector_t* records /* INOUT */) const + { + TRACE_SERIALIZE (this); + auto snap = c->serializer->snapshot (); + unsigned int old_size = bitmap_size_context->size; + unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length; + + // Set to invalid state to indicate filling glyphs is not yet started. + if (unlikely (!c->serializer->check_success (records->resize (records->length + 1)))) + return_trace (false); + + (*records)[records->length - 1].firstGlyphIndex = 1; + (*records)[records->length - 1].lastGlyphIndex = 0; + bitmap_size_context->size += IndexSubtableRecord::min_size; + + c->serializer->push (); + + if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start))) + { + c->serializer->pop_discard (); + c->serializer->revert (snap); + bitmap_size_context->cbdt_prime->shrink (old_cbdt_prime_length); + bitmap_size_context->size = old_size; + records->resize (records->length - 1); + return_trace (false); + } + + bitmap_size_context->num_tables += 1; + return_trace (true); + } + + unsigned int add_glyph_for_subset (hb_codepoint_t gid) + { + if (firstGlyphIndex > lastGlyphIndex) + { + firstGlyphIndex = gid; + lastGlyphIndex = gid; + return 0; + } + // TODO maybe assert? this shouldn't occur. + if (lastGlyphIndex > gid) + return 0; + unsigned int num_missing = (unsigned int) (gid - lastGlyphIndex - 1); + lastGlyphIndex = gid; + return num_missing; + } + + bool get_extents (hb_glyph_extents_t *extents, const void *base) const + { return (base+offsetToSubtable).get_extents (extents); } + bool get_image_data (unsigned int gid, const void *base, unsigned int *offset, @@ -226,11 +508,11 @@ struct IndexSubtableRecord offset, length, format); } - GlyphID firstGlyphIndex; - GlyphID lastGlyphIndex; - LOffsetTo offsetToSubtable; + HBGlyphID firstGlyphIndex; + HBGlyphID lastGlyphIndex; + Offset32To offsetToSubtable; public: - DEFINE_SIZE_STATIC(8); + DEFINE_SIZE_STATIC (8); }; struct IndexSubtableArray @@ -243,6 +525,79 @@ struct IndexSubtableArray return_trace (indexSubtablesZ.sanitize (c, count, this)); } + void + build_lookup (hb_subset_context_t *c, cblc_bitmap_size_subset_context_t *bitmap_size_context, + hb_vector_t> *lookup /* OUT */) const + { + bool start_glyph_is_set = false; + for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++) + { + hb_codepoint_t old_gid; + if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue; + + const IndexSubtableRecord* record = find_table (old_gid, bitmap_size_context->num_tables); + if (unlikely (!record)) continue; + + // Don't add gaps to the lookup. The best way to determine if a glyph is a + // gap is that it has no image data. + unsigned int offset, length, format; + if (unlikely (!record->get_image_data (old_gid, this, &offset, &length, &format))) continue; + + lookup->push (hb_pair_t (new_gid, record)); + + if (!start_glyph_is_set) + { + bitmap_size_context->start_glyph = new_gid; + start_glyph_is_set = true; + } + + bitmap_size_context->end_glyph = new_gid; + } + } + + bool + subset (hb_subset_context_t *c, + cblc_bitmap_size_subset_context_t *bitmap_size_context) const + { + TRACE_SUBSET (this); + + auto *dst = c->serializer->start_embed (); + if (unlikely (!dst)) return_trace (false); + + hb_vector_t> lookup; + build_lookup (c, bitmap_size_context, &lookup); + if (unlikely (!c->serializer->propagate_error (lookup))) + return false; + + bitmap_size_context->size = 0; + bitmap_size_context->num_tables = 0; + hb_vector_t records; + for (unsigned int start = 0; start < lookup.length;) + { + if (unlikely (!lookup[start].second->add_new_record (c, bitmap_size_context, &lookup, this, &start, &records))) + { + // Discard any leftover pushes to the serializer from successful records. + for (unsigned int i = 0; i < records.length; i++) + c->serializer->pop_discard (); + return_trace (false); + } + } + + /* Workaround to ensure offset ordering is from least to greatest when + * resolving links. */ + hb_vector_t objidxs; + for (unsigned int i = 0; i < records.length; i++) + objidxs.push (c->serializer->pop_pack ()); + for (unsigned int i = 0; i < records.length; i++) + { + IndexSubtableRecord* record = c->serializer->embed (records[i]); + if (unlikely (!record)) return_trace (false); + c->serializer->add_link (record->offsetToSubtable, objidxs[records.length - 1 - i]); + } + return_trace (true); + } + public: const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const { @@ -251,7 +606,7 @@ struct IndexSubtableArray unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex; unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex; if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex) - return &indexSubtablesZ[i]; + return &indexSubtablesZ[i]; } return nullptr; } @@ -274,30 +629,64 @@ struct BitmapSizeTable vertical.sanitize (c)); } - const IndexSubtableRecord *find_table (hb_codepoint_t glyph, - const void *base, - const void **out_base) const + const IndexSubtableRecord * + find_table (hb_codepoint_t glyph, const void *base, const void **out_base) const { *out_base = &(base+indexSubtableArrayOffset); return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables); } + bool + subset (hb_subset_context_t *c, const void *base, + const char *cbdt, unsigned int cbdt_length, + hb_vector_t *cbdt_prime /* INOUT */) const + { + TRACE_SUBSET (this); + auto *out_table = c->serializer->embed (this); + if (unlikely (!out_table)) return_trace (false); + + cblc_bitmap_size_subset_context_t bitmap_size_context; + bitmap_size_context.cbdt = cbdt; + bitmap_size_context.cbdt_length = cbdt_length; + bitmap_size_context.cbdt_prime = cbdt_prime; + bitmap_size_context.size = indexTablesSize; + bitmap_size_context.num_tables = numberOfIndexSubtables; + bitmap_size_context.start_glyph = 1; + bitmap_size_context.end_glyph = 0; + + if (!out_table->indexSubtableArrayOffset.serialize_subset (c, + indexSubtableArrayOffset, + base, + &bitmap_size_context)) + return_trace (false); + if (!bitmap_size_context.size || + !bitmap_size_context.num_tables || + bitmap_size_context.start_glyph > bitmap_size_context.end_glyph) + return_trace (false); + + out_table->indexTablesSize = bitmap_size_context.size; + out_table->numberOfIndexSubtables = bitmap_size_context.num_tables; + out_table->startGlyphIndex = bitmap_size_context.start_glyph; + out_table->endGlyphIndex = bitmap_size_context.end_glyph; + return_trace (true); + } + protected: - LNNOffsetTo + NNOffset32To indexSubtableArrayOffset; HBUINT32 indexTablesSize; HBUINT32 numberOfIndexSubtables; HBUINT32 colorRef; SBitLineMetrics horizontal; SBitLineMetrics vertical; - GlyphID startGlyphIndex; - GlyphID endGlyphIndex; + HBGlyphID startGlyphIndex; + HBGlyphID endGlyphIndex; HBUINT8 ppemX; HBUINT8 ppemY; HBUINT8 bitDepth; HBINT8 flags; public: - DEFINE_SIZE_STATIC(48); + DEFINE_SIZE_STATIC (48); }; @@ -308,24 +697,24 @@ struct BitmapSizeTable struct GlyphBitmapDataFormat17 { SmallGlyphMetrics glyphMetrics; - LArrayOf data; + Array32Of data; public: - DEFINE_SIZE_ARRAY(9, data); + DEFINE_SIZE_ARRAY (9, data); }; struct GlyphBitmapDataFormat18 { BigGlyphMetrics glyphMetrics; - LArrayOf data; + Array32Of data; public: - DEFINE_SIZE_ARRAY(12, data); + DEFINE_SIZE_ARRAY (12, data); }; struct GlyphBitmapDataFormat19 { - LArrayOf data; + Array32Of data; public: - DEFINE_SIZE_ARRAY(4, data); + DEFINE_SIZE_ARRAY (4, data); }; struct CBLC @@ -342,12 +731,50 @@ struct CBLC sizeTables.sanitize (c, this)); } + static bool + sink_cbdt (hb_subset_context_t *c, hb_vector_t* cbdt_prime) + { + hb_blob_t *cbdt_prime_blob = hb_blob_create (cbdt_prime->arrayZ, + cbdt_prime->length, + HB_MEMORY_MODE_WRITABLE, + cbdt_prime->arrayZ, + free); + cbdt_prime->init (); // Leak arrayZ to the blob. + bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob); + hb_blob_destroy (cbdt_prime_blob); + return ret; + } + + bool + subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table, + const char *cbdt /* IN */, unsigned int cbdt_length, + CBLC *cblc_prime /* INOUT */, hb_vector_t *cbdt_prime /* INOUT */) const + { + TRACE_SUBSET (this); + cblc_prime->sizeTables.len++; + + auto snap = c->serializer->snapshot (); + auto cbdt_prime_len = cbdt_prime->length; + + if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime)) + { + cblc_prime->sizeTables.len--; + c->serializer->revert (snap); + cbdt_prime->shrink (cbdt_prime_len); + return_trace (false); + } + return_trace (true); + } + + // Implemented in cc file as it depends on definition of CBDT. + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + protected: const BitmapSizeTable &choose_strike (hb_font_t *font) const { unsigned count = sizeTables.len; if (unlikely (!count)) - return Null(BitmapSizeTable); + return Null (BitmapSizeTable); unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem); if (!requested_ppem) @@ -371,9 +798,9 @@ struct CBLC protected: FixedVersion<> version; - LArrayOf sizeTables; + Array32Of sizeTables; public: - DEFINE_SIZE_ARRAY(8, sizeTables); + DEFINE_SIZE_ARRAY (8, sizeTables); }; struct CBDT @@ -384,8 +811,8 @@ struct CBDT { void init (hb_face_t *face) { - cblc = hb_sanitize_context_t().reference_table (face); - cbdt = hb_sanitize_context_t().reference_table (face); + cblc = hb_sanitize_context_t ().reference_table (face); + cbdt = hb_sanitize_context_t ().reference_table (face); upem = hb_face_get_upem (face); } @@ -396,8 +823,8 @@ struct CBDT this->cbdt.destroy (); } - bool get_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + bool + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -412,33 +839,27 @@ struct CBDT if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) return false; + unsigned int cbdt_len = cbdt.get_length (); + if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + return false; + + switch (image_format) { - unsigned int cbdt_len = cbdt.get_length (); - if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + case 17: { + if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return false; - - switch (image_format) - { - case 17: { - if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) - return false; - const GlyphBitmapDataFormat17& glyphFormat17 = - StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (extents); - break; - } - case 18: { - if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) - return false; - const GlyphBitmapDataFormat18& glyphFormat18 = - StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (extents); - break; - } - default: - // TODO: Support other image formats. - return false; - } + auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); + glyphFormat17.glyphMetrics.get_extents (font, extents); + break; + } + case 18: { + if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) + return false; + auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); + glyphFormat18.glyphMetrics.get_extents (font, extents); + break; + } + default: return false; /* TODO: Support other image formats. */ } /* Convert to font units. */ @@ -452,8 +873,8 @@ struct CBDT return true; } - hb_blob_t* reference_png (hb_font_t *font, - hb_codepoint_t glyph) const + hb_blob_t* + reference_png (hb_font_t *font, hb_codepoint_t glyph) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -465,44 +886,41 @@ struct CBDT if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) return hb_blob_get_empty (); + unsigned int cbdt_len = cbdt.get_length (); + if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + return hb_blob_get_empty (); + + switch (image_format) + { + case 17: { - unsigned int cbdt_len = cbdt.get_length (); - if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return hb_blob_get_empty (); - - switch (image_format) - { - case 17: { - if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) - return hb_blob_get_empty (); - const GlyphBitmapDataFormat17& glyphFormat17 = - StructAtOffset (this->cbdt, image_offset); - return hb_blob_create_sub_blob (cbdt.get_blob (), - image_offset + GlyphBitmapDataFormat17::min_size, - glyphFormat17.data.len); - } - case 18: { - if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) - return hb_blob_get_empty (); - const GlyphBitmapDataFormat18& glyphFormat18 = - StructAtOffset (this->cbdt, image_offset); - return hb_blob_create_sub_blob (cbdt.get_blob (), - image_offset + GlyphBitmapDataFormat18::min_size, - glyphFormat18.data.len); - } - case 19: { - if (unlikely (image_length < GlyphBitmapDataFormat19::min_size)) - return hb_blob_get_empty (); - const GlyphBitmapDataFormat19& glyphFormat19 = - StructAtOffset (this->cbdt, image_offset); - return hb_blob_create_sub_blob (cbdt.get_blob (), - image_offset + GlyphBitmapDataFormat19::min_size, - glyphFormat19.data.len); - } - } + auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat17::min_size, + glyphFormat17.data.len); + } + case 18: + { + if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) + return hb_blob_get_empty (); + auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat18::min_size, + glyphFormat18.data.len); + } + case 19: + { + if (unlikely (image_length < GlyphBitmapDataFormat19::min_size)) + return hb_blob_get_empty (); + auto &glyphFormat19 = StructAtOffset (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat19::min_size, + glyphFormat19.data.len); + } + default: return hb_blob_get_empty (); /* TODO: Support other image formats. */ } - - return hb_blob_get_empty (); } bool has_data () const { return cbdt.get_length (); } @@ -525,9 +943,41 @@ struct CBDT FixedVersion<> version; UnsizedArrayOf dataZ; public: - DEFINE_SIZE_ARRAY(4, dataZ); + DEFINE_SIZE_ARRAY (4, dataZ); }; +inline bool +CBLC::subset (hb_subset_context_t *c) const +{ + TRACE_SUBSET (this); + + auto *cblc_prime = c->serializer->start_embed (); + + // Use a vector as a secondary buffer as the tables need to be built in parallel. + hb_vector_t cbdt_prime; + + if (unlikely (!cblc_prime)) return_trace (false); + if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false); + cblc_prime->version = version; + + hb_blob_t* cbdt_blob = hb_sanitize_context_t ().reference_table (c->plan->source); + unsigned int cbdt_length; + CBDT* cbdt = (CBDT *) hb_blob_get_data (cbdt_blob, &cbdt_length); + if (unlikely (cbdt_length < CBDT::min_size)) + { + hb_blob_destroy (cbdt_blob); + return_trace (false); + } + _copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size); + + for (const BitmapSizeTable& table : + sizeTables.iter ()) + subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime); + + hb_blob_destroy (cbdt_blob); + + return_trace (CBLC::sink_cbdt (c, &cbdt_prime)); +} + struct CBDT_accelerator_t : CBDT::accelerator_t {}; } /* namespace OT */ diff --git a/src/hb-ot-color-colr-table.hh b/src/hb-ot-color-colr-table.hh index 3447b144dd64253795c10c9b8290d073e4d28ea8..c792147095aa1fb96e6ed2c1d64cba759e2fdd6d 100644 --- a/src/hb-ot-color-colr-table.hh +++ b/src/hb-ot-color-colr-table.hh @@ -1,5 +1,6 @@ /* * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2020 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -20,12 +21,15 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa */ #ifndef HB_OT_COLOR_COLR_TABLE_HH #define HB_OT_COLOR_COLR_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" /* * COLR -- Color @@ -36,7 +40,6 @@ namespace OT { - struct LayerRecord { operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } @@ -47,8 +50,8 @@ struct LayerRecord return_trace (c->check_struct (this)); } - protected: - GlyphID glyphId; /* Glyph ID of layer glyph */ + public: + HBGlyphID glyphId; /* Glyph ID of layer glyph */ Index colorIdx; /* Index value to use with a * selected color palette. * An index value of 0xFFFF @@ -75,7 +78,7 @@ struct BaseGlyphRecord } public: - GlyphID glyphId; /* Glyph ID of reference glyph */ + HBGlyphID glyphId; /* Glyph ID of reference glyph */ HBUINT16 firstLayerIdx; /* Index (from beginning of * the Layer Records) to the * layer record. There will be @@ -87,6 +90,467 @@ struct BaseGlyphRecord DEFINE_SIZE_STATIC (6); }; +template +struct Variable +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + T value; + VarIdx varIdx; + public: + DEFINE_SIZE_STATIC (4 + T::static_size); +}; + +template +struct NoVariable +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + T value; + public: + DEFINE_SIZE_STATIC (T::static_size); +}; + +// Color structures + +template class Var> +struct ColorIndex +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT16 paletteIndex; + Var alpha; + public: + DEFINE_SIZE_STATIC (2 + Var::static_size); +}; + +template class Var> +struct ColorStop +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + Var stopOffset; + ColorIndex color; + public: + DEFINE_SIZE_STATIC (Var::static_size + ColorIndex::static_size); +}; + +struct Extend : HBUINT8 +{ + enum { + EXTEND_PAD = 0, + EXTEND_REPEAT = 1, + EXTEND_REFLECT = 2, + }; + public: + DEFINE_SIZE_STATIC (1); +}; + +template class Var> +struct ColorLine +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + stops.sanitize (c)); + } + + Extend extend; + Array16Of> stops; + public: + DEFINE_SIZE_ARRAY_SIZED (3, stops); +}; + +// Composition modes + +// Compositing modes are taken from https://www.w3.org/TR/compositing-1/ +// NOTE: a brief audit of major implementations suggests most support most +// or all of the specified modes. +struct CompositeMode : HBUINT8 +{ + enum { + // Porter-Duff modes + // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators + COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear + COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src + COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst + COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover + COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover + COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin + COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin + COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout + COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout + COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop + COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop + COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor + COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus + + // Blend modes + // https://www.w3.org/TR/compositing-1/#blending + COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen + COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay + COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken + COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten + COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge + COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn + COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight + COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight + COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference + COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion + COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply + + // Modes that, uniquely, do not operate on components + // https://www.w3.org/TR/compositing-1/#blendingnonseparable + COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue + COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation + COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor + COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity + }; + public: + DEFINE_SIZE_STATIC (1); +}; + +template class Var> +struct Affine2x3 +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + Var xx; + Var yx; + Var xy; + Var yy; + Var dx; + Var dy; + public: + DEFINE_SIZE_STATIC (6 * Var::static_size); +}; + +struct PaintColrLayers +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT8 format; /* format = 1 */ + HBUINT8 numLayers; + HBUINT32 firstLayerIndex; /* index into COLRv1::layersV1 */ + public: + DEFINE_SIZE_STATIC (6); +}; + +template class Var> +struct PaintSolid +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ + ColorIndex color; + public: + DEFINE_SIZE_STATIC (1 + ColorIndex::static_size); +}; + +template class Var> +struct PaintLinearGradient +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); + } + + HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ + Offset24To> colorLine; /* Offset (from beginning of PaintLinearGradient + * table) to ColorLine subtable. */ + Var x0; + Var y0; + Var x1; + Var y1; + Var x2; + Var y2; + public: + DEFINE_SIZE_STATIC (4 + 6 * Var::static_size); +}; + +template class Var> +struct PaintRadialGradient +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); + } + + HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ + Offset24To> colorLine; /* Offset (from beginning of PaintRadialGradient + * table) to ColorLine subtable. */ + Var x0; + Var y0; + Var radius0; + Var x1; + Var y1; + Var radius1; + public: + DEFINE_SIZE_STATIC (4 + 6 * Var::static_size); +}; + +template class Var> +struct PaintSweepGradient +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); + } + + HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ + Offset24To> colorLine; /* Offset (from beginning of PaintSweepGradient + * table) to ColorLine subtable. */ + Var centerX; + Var centerY; + Var startAngle; + Var endAngle; + public: + DEFINE_SIZE_STATIC (2 * Var::static_size + 2 * Var::static_size); +}; + +struct Paint; +// Paint a non-COLR glyph, filled as indicated by paint. +struct PaintGlyph +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && paint.sanitize (c, this)); + } + + HBUINT8 format; /* format = 10 */ + Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ + HBUINT16 gid; + public: + DEFINE_SIZE_STATIC (6); +}; + +struct PaintColrGlyph +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + HBUINT8 format; /* format = 11 */ + HBUINT16 gid; + public: + DEFINE_SIZE_STATIC (3); +}; + +template class Var> +struct PaintTransform +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ + Offset24To src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ + Affine2x3 transform; + public: + DEFINE_SIZE_STATIC (4 + Affine2x3::static_size); +}; + +template class Var> +struct PaintTranslate +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ + Offset24To src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ + Var dx; + Var dy; + public: + DEFINE_SIZE_STATIC (4 + Var::static_size); +}; + +template class Var> +struct PaintRotate +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ + Offset24To src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ + Var angle; + Var centerX; + Var centerY; + public: + DEFINE_SIZE_STATIC (4 + 3 * Var::static_size); +}; + +template class Var> +struct PaintSkew +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && src.sanitize (c, this)); + } + + HBUINT8 format; /* format = 18(noVar) or 19 (Var) */ + Offset24To src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ + Var xSkewAngle; + Var ySkewAngle; + Var centerX; + Var centerY; + public: + DEFINE_SIZE_STATIC (4 + 4 * Var::static_size); +}; + +struct PaintComposite +{ + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + src.sanitize (c, this) && + backdrop.sanitize (c, this)); + } + + HBUINT8 format; /* format = 20 */ + Offset24To src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ + CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ + Offset24To backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */ + public: + DEFINE_SIZE_STATIC (8); +}; + +struct Paint +{ + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.paintformat1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.paintformat2, hb_forward (ds)...)); + case 3: return_trace (c->dispatch (u.paintformat3, hb_forward (ds)...)); + case 4: return_trace (c->dispatch (u.paintformat4, hb_forward (ds)...)); + case 5: return_trace (c->dispatch (u.paintformat5, hb_forward (ds)...)); + case 6: return_trace (c->dispatch (u.paintformat6, hb_forward (ds)...)); + case 7: return_trace (c->dispatch (u.paintformat7, hb_forward (ds)...)); + case 8: return_trace (c->dispatch (u.paintformat8, hb_forward (ds)...)); + case 9: return_trace (c->dispatch (u.paintformat9, hb_forward (ds)...)); + case 10: return_trace (c->dispatch (u.paintformat10, hb_forward (ds)...)); + case 11: return_trace (c->dispatch (u.paintformat11, hb_forward (ds)...)); + case 12: return_trace (c->dispatch (u.paintformat12, hb_forward (ds)...)); + case 13: return_trace (c->dispatch (u.paintformat13, hb_forward (ds)...)); + case 14: return_trace (c->dispatch (u.paintformat14, hb_forward (ds)...)); + case 15: return_trace (c->dispatch (u.paintformat15, hb_forward (ds)...)); + case 16: return_trace (c->dispatch (u.paintformat16, hb_forward (ds)...)); + case 17: return_trace (c->dispatch (u.paintformat17, hb_forward (ds)...)); + case 18: return_trace (c->dispatch (u.paintformat18, hb_forward (ds)...)); + case 19: return_trace (c->dispatch (u.paintformat19, hb_forward (ds)...)); + case 20: return_trace (c->dispatch (u.paintformat20, hb_forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + protected: + union { + HBUINT8 format; + PaintColrLayers paintformat1; + PaintSolid paintformat2; + PaintSolid paintformat3; + PaintLinearGradient paintformat4; + PaintLinearGradient paintformat5; + PaintRadialGradient paintformat6; + PaintRadialGradient paintformat7; + PaintSweepGradient paintformat8; + PaintSweepGradient paintformat9; + PaintGlyph paintformat10; + PaintColrGlyph paintformat11; + PaintTransform paintformat12; + PaintTransform paintformat13; + PaintTranslate paintformat14; + PaintTranslate paintformat15; + PaintRotate paintformat16; + PaintRotate paintformat17; + PaintSkew paintformat18; + PaintSkew paintformat19; + PaintComposite paintformat20; + } u; +}; + +struct BaseGlyphV1Record +{ + int cmp (hb_codepoint_t g) const + { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && paint.sanitize (c, this))); + } + + public: + HBGlyphID glyphId; /* Glyph ID of reference glyph */ + Offset32To paint; /* Offset (from beginning of BaseGlyphV1Record) to Paint, + * Typically PaintColrLayers */ + public: + DEFINE_SIZE_STATIC (6); +}; + +typedef SortedArray32Of BaseGlyphV1List; + +struct LayerV1List : Array32OfOffset32To +{ + const Paint& get_paint (unsigned i) const + { return this+(*this)[i]; } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (Array32OfOffset32To::sanitize (c, this)); + } +}; + struct COLR { static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; @@ -112,24 +576,169 @@ struct COLR return glyph_layers.length; } + struct accelerator_t + { + accelerator_t () {} + ~accelerator_t () { fini (); } + + void init (hb_face_t *face) + { colr = hb_sanitize_context_t ().reference_table (face); } + + void fini () { this->colr.destroy (); } + + bool is_valid () { return colr.get_blob ()->length; } + + void closure_glyphs (hb_codepoint_t glyph, + hb_set_t *related_ids /* OUT */) const + { colr->closure_glyphs (glyph, related_ids); } + + private: + hb_blob_ptr_t colr; + }; + + void closure_glyphs (hb_codepoint_t glyph, + hb_set_t *related_ids /* OUT */) const + { + const BaseGlyphRecord *record = get_base_glyph_record (glyph); + if (!record) return; + + auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, + record->numLayers); + if (!glyph_layers.length) return; + related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this) && - (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && - (this+layersZ).sanitize (c, numLayers))); + return_trace (c->check_struct (this) && + (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && + (this+layersZ).sanitize (c, numLayers) && + (version == 0 || (version == 1 && + baseGlyphsV1List.sanitize (c, this) && + layersV1.sanitize (c, this) && + varStore.sanitize (c, this)))); + } + + template + bool serialize (hb_serialize_context_t *c, + unsigned version, + BaseIterator base_it, + LayerIterator layer_it) + { + TRACE_SERIALIZE (this); + if (unlikely (base_it.len () != layer_it.len ())) + return_trace (false); + + if (unlikely (!c->extend_min (this))) return_trace (false); + this->version = version; + numLayers = 0; + numBaseGlyphs = base_it.len (); + baseGlyphsZ = COLR::min_size; + layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size; + + for (const hb_item_type _ : + base_it.iter ()) + { + auto* record = c->embed (_); + if (unlikely (!record)) return_trace (false); + record->firstLayerIdx = numLayers; + numLayers += record->numLayers; + } + + for (const hb_item_type& _ : + layer_it.iter ()) + _.as_array ().copy (c); + + return_trace (true); + } + + const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const + { + if ((unsigned int) gid == 0) // Ignore notdef. + return nullptr; + const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); + if ((record && (hb_codepoint_t) record->glyphId != gid)) + record = nullptr; + return record; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; + + auto base_it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) + { + hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); + + const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); + if (unlikely (!old_record)) + return hb_pair_t (false, Null (BaseGlyphRecord)); + + BaseGlyphRecord new_record = {}; + new_record.glyphId = new_gid; + new_record.numLayers = old_record->numLayers; + return hb_pair_t (true, new_record); + }) + | hb_filter (hb_first) + | hb_map_retains_sorting (hb_second) + ; + + auto layer_it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map (reverse_glyph_map) + | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) + { + const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); + hb_vector_t out_layers; + + if (unlikely (!old_record || + old_record->firstLayerIdx >= numLayers || + old_record->firstLayerIdx + old_record->numLayers > numLayers)) + return hb_pair_t> (false, out_layers); + + auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, + old_record->numLayers); + out_layers.resize (layers.length); + for (unsigned int i = 0; i < layers.length; i++) { + out_layers[i] = layers[i]; + hb_codepoint_t new_gid = 0; + if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) + return hb_pair_t> (false, out_layers); + out_layers[i].glyphId = new_gid; + } + + return hb_pair_t> (true, out_layers); + }) + | hb_filter (hb_first) + | hb_map_retains_sorting (hb_second) + ; + + if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ())) + return_trace (false); + + COLR *colr_prime = c->serializer->start_embed (); + return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it)); } protected: HBUINT16 version; /* Table version number (starts at 0). */ HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ - LNNOffsetTo> + NNOffset32To> baseGlyphsZ; /* Offset to Base Glyph records. */ - LNNOffsetTo> + NNOffset32To> layersZ; /* Offset to Layer Records. */ HBUINT16 numLayers; /* Number of Layer Records. */ + // Version-1 additions + Offset32To baseGlyphsV1List; + Offset32To layersV1; + Offset32To varStore; public: - DEFINE_SIZE_STATIC (14); + DEFINE_SIZE_MIN (14); }; } /* namespace OT */ diff --git a/src/hb-ot-color-cpal-table.hh b/src/hb-ot-color-cpal-table.hh index 9ec2957ea2cea9eb70d399c2dfe5763462c6dca1..2fa99dead74715a115642268c5ac6a9fc7a2d791 100644 --- a/src/hb-ot-color-cpal-table.hh +++ b/src/hb-ot-color-cpal-table.hh @@ -87,15 +87,15 @@ struct CPALV1Tail } protected: - LNNOffsetTo> + NNOffset32To> paletteFlagsZ; /* Offset from the beginning of CPAL table to * the Palette Type Array. Set to 0 if no array * is provided. */ - LNNOffsetTo> + NNOffset32To> paletteLabelsZ; /* Offset from the beginning of CPAL table to * the palette labels array. Set to 0 if no * array is provided. */ - LNNOffsetTo> + NNOffset32To> colorLabelsZ; /* Offset from the beginning of CPAL table to * the color labels array. Set to 0 * if no array is provided. */ @@ -115,7 +115,7 @@ struct CPAL { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); } unsigned int get_palette_count () const { return numPalettes; } - unsigned int get_color_count () const { return numColors; } + unsigned int get_color_count () const { return numColors; } hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const { return v1 ().get_palette_flags (this, palette_index, numPalettes); } @@ -142,12 +142,9 @@ struct CPAL numColors); if (color_count) { - hb_array_t segment_colors = palette_colors.sub_array (start_offset, *color_count); - /* Always return numColors colors per palette even if it has out-of-bounds start index. */ - unsigned int count = hb_min ((unsigned) hb_max ((int) (numColors - start_offset), 0), *color_count); - *color_count = count; - for (unsigned int i = 0; i < count; i++) - colors[i] = segment_colors[i]; /* Bound-checked read. */ + + palette_colors.sub_array (start_offset, color_count) + | hb_sink (hb_array (colors, *color_count)) + ; } return numColors; } @@ -155,7 +152,7 @@ struct CPAL private: const CPALV1Tail& v1 () const { - if (version == 0) return Null(CPALV1Tail); + if (version == 0) return Null (CPALV1Tail); return StructAfter (*this); } @@ -176,7 +173,7 @@ struct CPAL HBUINT16 numPalettes; /* Number of palettes in the table. */ HBUINT16 numColorRecords; /* Total number of color records, combined for * all palettes. */ - LNNOffsetTo> + NNOffset32To> colorRecordsZ; /* Offset from the beginning of CPAL table to * the first ColorRecord. */ UnsizedArrayOf diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh index 8a915a6619f4bdf11fabf19ca6a379777e3ad6e9..af1e4a5dbeb03add0b8317c5d55ebd94d37a6f53 100644 --- a/src/hb-ot-color-sbix-table.hh +++ b/src/hb-ot-color-sbix-table.hh @@ -1,5 +1,6 @@ /* * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2020 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -20,12 +21,15 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa */ #ifndef HB_OT_COLOR_SBIX_TABLE_HH #define HB_OT_COLOR_SBIX_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" /* * sbix -- Standard Bitmap Graphics @@ -40,6 +44,20 @@ namespace OT { struct SBIXGlyph { + SBIXGlyph* copy (hb_serialize_context_t *c, unsigned int data_length) const + { + TRACE_SERIALIZE (this); + SBIXGlyph* new_glyph = c->start_embed (); + if (unlikely (!new_glyph)) return_trace (nullptr); + if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr); + + new_glyph->xOffset = xOffset; + new_glyph->yOffset = yOffset; + new_glyph->graphicType = graphicType; + data.copy (c, data_length); + return_trace (new_glyph); + } + HBINT16 xOffset; /* The horizontal (x-axis) offset from the left * edge of the graphic to the glyph’s origin. * That is, the x-coordinate of the point on the @@ -62,6 +80,9 @@ struct SBIXGlyph struct SBIXStrike { + static unsigned int get_size (unsigned num_glyphs) + { return min_size + num_glyphs * HBUINT32::static_size; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -116,16 +137,59 @@ struct SBIXStrike return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length); } + bool subset (hb_subset_context_t *c, unsigned int available_len) const + { + TRACE_SUBSET (this); + unsigned int num_output_glyphs = c->plan->num_output_glyphs (); + + auto* out = c->serializer->start_embed (); + if (unlikely (!out)) return_trace (false); + auto snap = c->serializer->snapshot (); + if (unlikely (!c->serializer->extend (*out, num_output_glyphs + 1))) return_trace (false); + out->ppem = ppem; + out->resolution = resolution; + HBUINT32 head; + head = get_size (num_output_glyphs + 1); + + bool has_glyphs = false; + for (unsigned new_gid = 0; new_gid < num_output_glyphs; new_gid++) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid) || + unlikely (imageOffsetsZ[old_gid].is_null () || + imageOffsetsZ[old_gid + 1].is_null () || + imageOffsetsZ[old_gid + 1] <= imageOffsetsZ[old_gid] || + imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid] <= SBIXGlyph::min_size) || + (unsigned int) imageOffsetsZ[old_gid + 1] > available_len) + { + out->imageOffsetsZ[new_gid] = head; + continue; + } + has_glyphs = true; + unsigned int delta = imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid]; + unsigned int glyph_data_length = delta - SBIXGlyph::min_size; + if (!(this+imageOffsetsZ[old_gid]).copy (c->serializer, glyph_data_length)) + return_trace (false); + out->imageOffsetsZ[new_gid] = head; + head += delta; + } + if (has_glyphs) + out->imageOffsetsZ[num_output_glyphs] = head; + else + c->serializer->revert (snap); + return_trace (has_glyphs); + } + public: HBUINT16 ppem; /* The PPEM size for which this strike was designed. */ HBUINT16 resolution; /* The device pixel density (in PPI) for which this * strike was designed. (E.g., 96 PPI, 192 PPI.) */ protected: - UnsizedArrayOf> + UnsizedArrayOf> imageOffsetsZ; /* Offset from the beginning of the strike data header * to bitmap data for an individual glyph ID. */ public: - DEFINE_SIZE_STATIC (8); + DEFINE_SIZE_ARRAY (4, imageOffsetsZ); }; struct sbix @@ -140,7 +204,7 @@ struct sbix { void init (hb_face_t *face) { - table = hb_sanitize_context_t().reference_table (face); + table = hb_sanitize_context_t ().reference_table (face); num_glyphs = face->get_num_glyphs (); } void fini () { table.destroy (); } @@ -173,11 +237,11 @@ struct sbix { unsigned count = table->strikes.len; if (unlikely (!count)) - return Null(SBIXStrike); + return Null (SBIXStrike); unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem); if (!requested_ppem) - requested_ppem = 1<<30; /* Choose largest strike. */ + requested_ppem = 1<<30; /* Choose largest strike. */ /* TODO Add DPI sensitivity as well? */ unsigned int best_i = 0; unsigned int best_ppem = table->get_strike (0).ppem; @@ -201,7 +265,7 @@ struct sbix HBUINT8 signature[8]; struct { - struct + struct { HBUINT32 length; Tag type; @@ -226,7 +290,7 @@ struct sbix /* Following code is safe to call even without data. * But faster to short-circuit. */ if (!has_data ()) - return false; + return false; int x_offset = 0, y_offset = 0; unsigned int strike_ppem = 0; @@ -237,16 +301,23 @@ struct sbix extents->x_bearing = x_offset; extents->y_bearing = png.IHDR.height + y_offset; extents->width = png.IHDR.width; - extents->height = -png.IHDR.height; + extents->height = -1 * png.IHDR.height; /* Convert to font units. */ if (strike_ppem) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = roundf (extents->x_bearing * scale); - extents->y_bearing = roundf (extents->y_bearing * scale); - extents->width = roundf (extents->width * scale); - extents->height = roundf (extents->height * scale); + extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); + extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); + extents->width = font->em_scalef_x (extents->width * scale); + extents->height = font->em_scalef_y (extents->height * scale); + } + else + { + extents->x_bearing = font->em_scale_x (extents->x_bearing); + extents->y_bearing = font->em_scale_y (extents->y_bearing); + extents->width = font->em_scale_x (extents->width); + extents->height = font->em_scale_y (extents->height); } hb_blob_destroy (blob); @@ -268,11 +339,68 @@ struct sbix strikes.sanitize (c, this))); } + bool + add_strike (hb_subset_context_t *c, unsigned i) const + { + if (strikes[i].is_null () || c->source_blob->length < (unsigned) strikes[i]) + return false; + + return (this+strikes[i]).subset (c, c->source_blob->length - (unsigned) strikes[i]); + } + + bool serialize_strike_offsets (hb_subset_context_t *c) const + { + TRACE_SERIALIZE (this); + + auto *out = c->serializer->start_embed> (); + if (unlikely (!out)) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_vector_t*> new_strikes; + hb_vector_t objidxs; + for (int i = strikes.len - 1; i >= 0; --i) + { + auto* o = out->serialize_append (c->serializer); + if (unlikely (!o)) return_trace (false); + *o = 0; + auto snap = c->serializer->snapshot (); + c->serializer->push (); + bool ret = add_strike (c, i); + if (!ret) + { + c->serializer->pop_discard (); + out->pop (); + c->serializer->revert (snap); + } + else + { + objidxs.push (c->serializer->pop_pack ()); + new_strikes.push (o); + } + } + for (unsigned int i = 0; i < new_strikes.length; ++i) + c->serializer->add_link (*new_strikes[i], objidxs[new_strikes.length - 1 - i]); + + return_trace (true); + } + + bool subset (hb_subset_context_t* c) const + { + TRACE_SUBSET (this); + + sbix *sbix_prime = c->serializer->start_embed (); + if (unlikely (!sbix_prime)) return_trace (false); + if (unlikely (!c->serializer->embed (this->version))) return_trace (false); + if (unlikely (!c->serializer->embed (this->flags))) return_trace (false); + + return_trace (serialize_strike_offsets (c)); + } + protected: HBUINT16 version; /* Table version number — set to 1 */ HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines. * Bits 2 to 15: reserved (set to 0). */ - LOffsetLArrayOf + Array32OfOffset32To strikes; /* Offsets from the beginning of the 'sbix' * table to data for each individual bitmap strike. */ public: diff --git a/src/hb-ot-color-svg-table.hh b/src/hb-ot-color-svg-table.hh index 926d61e0faf6741292012e8ad2fd039daf0b5bfd..e022ef43b79927a29730a1c9a85a2af14c9d649b 100644 --- a/src/hb-ot-color-svg-table.hh +++ b/src/hb-ot-color-svg-table.hh @@ -62,7 +62,7 @@ struct SVGDocumentIndexEntry * this index entry. */ HBUINT16 endGlyphID; /* The last glyph ID in the range described by * this index entry. Must be >= startGlyphID. */ - LNNOffsetTo> + NNOffset32To> svgDoc; /* Offset from the beginning of the SVG Document Index * to an SVG document. Must be non-zero. */ HBUINT32 svgDocLength; /* Length of the SVG document. @@ -80,7 +80,7 @@ struct SVG struct accelerator_t { void init (hb_face_t *face) - { table = hb_sanitize_context_t().reference_table (face); } + { table = hb_sanitize_context_t ().reference_table (face); } void fini () { table.destroy (); } hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const @@ -107,7 +107,7 @@ struct SVG protected: HBUINT16 version; /* Table version (starting at 0). */ - LOffsetTo> + Offset32To> svgDocEntries; /* Offset (relative to the start of the SVG table) to the * SVG Documents Index. Must be non-zero. */ /* Array of SVG Document Index Entries. */ diff --git a/src/hb-ot-color.cc b/src/hb-ot-color.cc index 0e7203a88bf23a3a2d2a5d3ee011e9057270765e..4170b71317d7c880555f16ca9ff895fc54f2bb5b 100644 --- a/src/hb-ot-color.cc +++ b/src/hb-ot-color.cc @@ -37,9 +37,6 @@ #include "hb-ot-color-sbix-table.hh" #include "hb-ot-color-svg-table.hh" -#include -#include - /** * SECTION:hb-ot-color @@ -64,7 +61,7 @@ * * Tests whether a face includes a `CPAL` color-palette table. * - * Return value: true if data found, false otherwise + * Return value: %true if data found, %false otherwise * * Since: 2.1.0 */ @@ -195,7 +192,7 @@ hb_ot_color_palette_get_colors (hb_face_t *face, * * Tests whether a face includes any `COLR` color layers. * - * Return value: true if data found, false otherwise + * Return value: %true if data found, %false otherwise * * Since: 2.1.0 */ @@ -242,7 +239,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, * * Tests whether a face includes any `SVG` glyph images. * - * Return value: true if data found, false otherwise. + * Return value: %true if data found, %false otherwise. * * Since: 2.1.0 */ @@ -280,7 +277,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph) * * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables). * - * Return value: true if data found, false otherwise + * Return value: %true if data found, %false otherwise * * Since: 2.1.0 */ diff --git a/src/hb-ot-color.h b/src/hb-ot-color.h index 63ef20a1a081c1a24bcc30cf9f91615d505336dc..c23ce4de44f3f9a29f9ec17de1044f07d3ad15db 100644 --- a/src/hb-ot-color.h +++ b/src/hb-ot-color.h @@ -26,7 +26,7 @@ * Google Author(s): Sascha Brawer, Behdad Esfahbod */ -#ifndef HB_OT_H_IN +#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -66,6 +66,8 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face, * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color * palette is appropriate to use when displaying the font on a dark background such as black. * + * Flags that describe the properties of color palette. + * * Since: 2.1.0 */ typedef enum { /*< flags >*/ @@ -95,13 +97,14 @@ hb_ot_color_has_layers (hb_face_t *face); /** * hb_ot_color_layer_t: + * @glyph: the glyph ID of the layer + * @color_index: the palette color index of the layer * * Pairs of glyph and color index. * * Since: 2.1.0 **/ -typedef struct hb_ot_color_layer_t -{ +typedef struct hb_ot_color_layer_t { hb_codepoint_t glyph; unsigned int color_index; } hb_ot_color_layer_t; diff --git a/src/hb-ot-deprecated.h b/src/hb-ot-deprecated.h index bc72f8a7016fe719411582d1f0342f99157d64ae..ce6b6fef11a51acb789f787ad1a8a66b9da6917a 100644 --- a/src/hb-ot-deprecated.h +++ b/src/hb-ot-deprecated.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_OT_H_IN +#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -41,6 +41,13 @@ HB_BEGIN_DECLS /* https://github.com/harfbuzz/harfbuzz/issues/1734 */ +/** + * HB_MATH_GLYPH_PART_FLAG_EXTENDER: + * + * Use #HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER instead. + * + * Deprecated: 2.5.1 + */ #define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER @@ -71,6 +78,8 @@ hb_ot_tag_from_language (hb_language_t language); /** * HB_OT_VAR_NO_AXIS_INDEX: * + * Do not use. + * * Since: 1.4.2 * Deprecated: 2.2.0 */ @@ -78,12 +87,18 @@ hb_ot_tag_from_language (hb_language_t language); /** * hb_ot_var_axis_t: + * @tag: axis tag + * @name_id: axis name identifier + * @min_value: minimum value of the axis + * @default_value: default value of the axis + * @max_value: maximum value of the axis + * + * Use #hb_ot_var_axis_info_t instead. * * Since: 1.4.2 * Deprecated: 2.2.0 */ -typedef struct hb_ot_var_axis_t -{ +typedef struct hb_ot_var_axis_t { hb_tag_t tag; hb_ot_name_id_t name_id; float min_value; diff --git a/src/hb-ot-face-table-list.hh b/src/hb-ot-face-table-list.hh index 30bab5cb54dda4dec2c8b3d0d7587409b3a2aadc..367e143fdfb9033467a3309de6060d96375c48f6 100644 --- a/src/hb-ot-face-table-list.hh +++ b/src/hb-ot-face-table-list.hh @@ -53,13 +53,13 @@ HB_OT_ACCELERATOR (OT, cmap) HB_OT_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) HB_OT_TABLE (OT, OS2) -#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) +#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE) HB_OT_ACCELERATOR (OT, post) #endif #ifndef HB_NO_NAME HB_OT_ACCELERATOR (OT, name) #endif -#ifndef HB_NO_STAT +#ifndef HB_NO_STYLE HB_OT_TABLE (OT, STAT) #endif #ifndef HB_NO_META @@ -84,6 +84,7 @@ HB_OT_TABLE (OT, VORG) #ifndef HB_NO_VAR HB_OT_TABLE (OT, fvar) HB_OT_TABLE (OT, avar) +HB_OT_ACCELERATOR (OT, gvar) HB_OT_TABLE (OT, MVAR) #endif @@ -112,7 +113,6 @@ HB_OT_TABLE (AAT, mort) HB_OT_TABLE (AAT, kerx) HB_OT_TABLE (AAT, ankr) HB_OT_TABLE (AAT, trak) -HB_OT_TABLE (AAT, lcar) HB_OT_TABLE (AAT, ltag) HB_OT_TABLE (AAT, feat) // HB_OT_TABLE (AAT, opbd) diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 7d6213572b1ed6126e012c092b5d3af90f4f07f1..fae7b5b65af8b017b75cff0a94ac0719a2a416e7 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -160,11 +160,11 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, #endif hb_glyph_extents_t extents = {0}; - if (ot_face->glyf->get_extents (glyph, &extents)) + if (ot_face->glyf->get_extents (font, glyph, &extents)) { const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - hb_position_t tsb = vmtx.get_side_bearing (glyph); - *y = font->em_scale_y (extents.y_bearing + tsb); + hb_position_t tsb = vmtx.get_side_bearing (font, glyph); + *y = extents.y_bearing + font->em_scale_y (tsb); return true; } @@ -183,48 +183,51 @@ hb_ot_get_glyph_extents (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - bool ret = false; #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) - if (!ret) ret = ot_face->sbix->get_extents (font, glyph, extents); + if (ot_face->sbix->get_extents (font, glyph, extents)) return true; #endif - if (!ret) ret = ot_face->glyf->get_extents (glyph, extents); + if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF - if (!ret) ret = ot_face->cff1->get_extents (glyph, extents); - if (!ret) ret = ot_face->cff2->get_extents (font, glyph, extents); + if (ot_face->cff1->get_extents (font, glyph, extents)) return true; + if (ot_face->cff2->get_extents (font, glyph, extents)) return true; #endif #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) - if (!ret) ret = ot_face->CBDT->get_extents (font, glyph, extents); + if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; #endif // TODO Hook up side-bearings variations. - extents->x_bearing = font->em_scale_x (extents->x_bearing); - extents->y_bearing = font->em_scale_y (extents->y_bearing); - extents->width = font->em_scale_x (extents->width); - extents->height = font->em_scale_y (extents->height); - return ret; + return false; } #ifndef HB_NO_OT_FONT_GLYPH_NAMES static hb_bool_t hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t glyph, - char *name, unsigned int size, - void *user_data HB_UNUSED) + void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - return ot_face->post->get_glyph_name (glyph, name, size); + if (ot_face->post->get_glyph_name (glyph, name, size)) return true; +#ifndef HB_NO_OT_FONT_CFF + if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true; +#endif + return false; } static hb_bool_t hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, - void *font_data, - const char *name, int len, - hb_codepoint_t *glyph, - void *user_data HB_UNUSED) + void *font_data, + const char *name, int len, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - return ot_face->post->get_glyph_from_name (name, len, glyph); + if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true; +#ifndef HB_NO_OT_FONT_CFF + if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true; +#endif + return false; } #endif @@ -303,6 +306,9 @@ _hb_ot_get_font_funcs () /** * hb_ot_font_set_funcs: + * @font: #hb_font_t to work upon + * + * Sets the font functions to use when working with @font. * * Since: 0.9.28 **/ @@ -315,5 +321,19 @@ hb_ot_font_set_funcs (hb_font_t *font) nullptr); } +#ifndef HB_NO_VAR +int +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +{ + return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical); +} + +unsigned +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +{ + return font->face->table.glyf->get_advance_var (font, glyph, is_vertical); +} +#endif + #endif diff --git a/src/hb-ot-font.h b/src/hb-ot-font.h index 80eaa54b1add7333d975fbee27c00bc777f3e046..e7959d1ae28eae6104e6c9e79183fc81947a1a98 100644 --- a/src/hb-ot-font.h +++ b/src/hb-ot-font.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod, Roozbeh Pournader */ -#ifndef HB_OT_H_IN +#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif diff --git a/src/hb-ot-gasp-table.hh b/src/hb-ot-gasp-table.hh index 94fff58a158b4abf45fd365944c6aa91c9ec41da..f2a9cad464b29f71439a36fe557f8af4e79ebdbb 100644 --- a/src/hb-ot-gasp-table.hh +++ b/src/hb-ot-gasp-table.hh @@ -48,8 +48,8 @@ struct GaspRange } public: - HBUINT16 rangeMaxPPEM; /* Upper limit of range, in PPEM */ - HBUINT16 rangeGaspBehavior; + HBUINT16 rangeMaxPPEM; /* Upper limit of range, in PPEM */ + HBUINT16 rangeGaspBehavior; /* Flags describing desired rasterizer behavior. */ public: DEFINE_SIZE_STATIC (4); @@ -71,7 +71,7 @@ struct gasp protected: HBUINT16 version; /* Version number (set to 1) */ - ArrayOf + Array16Of gaspRanges; /* Number of records to follow * Sorted by ppem */ public: diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 76efdc9b8ebf931229876da3b5212ada92508bf2..5352156f0246d30f1b7d9480bebb6c5a5dd5c702 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -1,5 +1,7 @@ /* * Copyright © 2015 Google, Inc. + * Copyright © 2019 Adobe Inc. + * Copyright © 2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -22,6 +24,7 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter + * Adobe Author(s): Michiharu Ariza */ #ifndef HB_OT_GLYF_TABLE_HH @@ -29,6 +32,9 @@ #include "hb-open-type.hh" #include "hb-ot-head-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-var-gvar-table.hh" +#include "hb-draw.hh" namespace OT { @@ -53,11 +59,12 @@ struct loca } protected: - UnsizedArrayOf dataZ; /* Location data. */ + UnsizedArrayOf + dataZ; /* Location data. */ public: - DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always - * check the size externally, allow Null() object of it by - * defining it _MIN instead. */ + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it _MIN instead. */ }; @@ -75,8 +82,7 @@ struct glyf bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); - /* We don't check for anything specific here. The users of the - * struct do all the hard work... */ + /* Runtime checks as eager sanitizing each glyph is costy */ return_trace (true); } @@ -85,7 +91,10 @@ struct glyf static bool _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets) { - unsigned max_offset = + padded_offsets | hb_reduce(hb_add, 0); + unsigned max_offset = + + padded_offsets + | hb_reduce (hb_add, 0) + ; unsigned num_offsets = padded_offsets.len () + 1; bool use_short_loca = max_offset < 0x1FFFF; unsigned entry_size = use_short_loca ? 2 : 4; @@ -93,21 +102,23 @@ struct glyf if (unlikely (!loca_prime_data)) return false; - DEBUG_MSG(SUBSET, nullptr, "loca entry_size %d num_offsets %d max_offset %d size %d", entry_size, num_offsets, max_offset, entry_size * num_offsets); + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d " + "max_offset %d size %d", + entry_size, num_offsets, max_offset, entry_size * num_offsets); if (use_short_loca) - _write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); else - _write_loca (padded_offsets, 0, hb_array ((HBUINT32*) loca_prime_data, num_offsets)); + _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); - hb_blob_t * loca_blob = hb_blob_create (loca_prime_data, - entry_size * num_offsets, - HB_MEMORY_MODE_WRITABLE, - loca_prime_data, - free); + hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, + entry_size * num_offsets, + HB_MEMORY_MODE_WRITABLE, + loca_prime_data, + free); bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) - && _add_head_and_set_loca_version(plan, use_short_loca); + && _add_head_and_set_loca_version (plan, use_short_loca); hb_blob_destroy (loca_blob); return result; @@ -122,30 +133,42 @@ struct glyf unsigned int offset = 0; dest << 0; + it - | hb_map ([=, &offset] (unsigned int padded_size) { - offset += padded_size; - DEBUG_MSG(SUBSET, nullptr, "loca entry offset %d", offset); - return offset >> right_shift; - }) + | hb_map ([=, &offset] (unsigned int padded_size) + { + offset += padded_size; + DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); + return offset >> right_shift; + }) | hb_sink (dest) ; } - // requires source of SubsetGlyph complains the identifier isn't declared + /* requires source of SubsetGlyph complains the identifier isn't declared */ template - bool serialize(hb_serialize_context_t *c, - Iterator it, - const hb_subset_plan_t *plan) + bool serialize (hb_serialize_context_t *c, + Iterator it, + const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); - - + it - | hb_apply ([=] (const SubsetGlyph& _) { _.serialize (c, plan); }) - ; - + unsigned init_len = c->length (); + for (const auto &_ : it) _.serialize (c, plan); + + /* As a special case when all glyph in the font are empty, add a zero byte + * to the table, so that OTS doesn’t reject it, and to make the table work + * on Windows as well. + * See https://github.com/khaledhosny/ots/issues/52 */ + if (init_len == c->length ()) + { + HBUINT8 empty_byte; + empty_byte = 0; + c->copy (empty_byte); + } return_trace (true); } + /* Byte region(s) per glyph to output + unpadded, hints removed if so requested + If we fail to process a glyph we produce an empty (0-length) glyph */ bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -153,9 +176,6 @@ struct glyf glyf *glyf_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); - // Byte region(s) per glyph to output - // unpadded, hints removed if so requested - // If we fail to process a glyph we produce an empty (0-length) glyph hb_vector_t glyphs; _populate_subset_glyphs (c->plan, &glyphs); @@ -166,86 +186,41 @@ struct glyf | hb_map (&SubsetGlyph::padded_size) ; - if (c->serializer->in_error ()) return_trace (false); - return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, padded_offsets))); + if (unlikely (c->serializer->in_error ())) return_trace (false); + return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, + padded_offsets))); } template void - _populate_subset_glyphs (const hb_subset_plan_t * plan, - hb_vector_t * glyphs /* OUT */) const + _populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_vector_t *glyphs /* OUT */) const { OT::glyf::accelerator_t glyf; glyf.init (plan->source); + hb_range (plan->num_output_glyphs ()) - | hb_map ([&] (hb_codepoint_t new_gid) { - SubsetGlyph subset_glyph = {0}; - subset_glyph.new_gid = new_gid; + | hb_map ([&] (hb_codepoint_t new_gid) + { + SubsetGlyph subset_glyph = {0}; + subset_glyph.new_gid = new_gid; - // should never fail: all old gids should be mapped - if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) return subset_glyph; + /* should never fail: all old gids should be mapped */ + if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) + return subset_glyph; - subset_glyph.source_glyph = glyf.bytes_for_glyph ((const char *) this, subset_glyph.old_gid); - if (plan->drop_hints) subset_glyph.drop_hints (glyf); - else subset_glyph.dest_start = subset_glyph.source_glyph; + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); + if (plan->drop_hints) subset_glyph.drop_hints_bytes (); + else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); - return subset_glyph; - }) + return subset_glyph; + }) | hb_sink (glyphs) ; - glyf.fini(); - } - - static void - _fix_component_gids (const hb_subset_plan_t *plan, - hb_bytes_t glyph) - { - OT::glyf::CompositeGlyphHeader::Iterator iterator; - if (OT::glyf::CompositeGlyphHeader::get_iterator (&glyph, - glyph.length, - &iterator)) - { - do - { - hb_codepoint_t new_gid; - if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex, - &new_gid)) - continue; - ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex = new_gid; - } while (iterator.move_to_next ()); - } - } - - static void - _zero_instruction_length (hb_bytes_t glyph) - { - const GlyphHeader &glyph_header = StructAtOffset (&glyph, 0); - int16_t num_contours = (int16_t) glyph_header.numberOfContours; - if (num_contours <= 0) return; // only for simple glyphs - - const HBUINT16 &instruction_length = StructAtOffset (&glyph, GlyphHeader::static_size + 2 * num_contours); - (HBUINT16 &) instruction_length = 0; + glyf.fini (); } - static bool _remove_composite_instruction_flag (hb_bytes_t glyph) - { - const GlyphHeader &glyph_header = StructAtOffset (&glyph, 0); - if (glyph_header.numberOfContours >= 0) return true; // only for composites - - /* remove WE_HAVE_INSTRUCTIONS from flags in dest */ - OT::glyf::CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false; - const OT::glyf::CompositeGlyphHeader *composite_header; - do { - composite_header = composite_it.current; - OT::HBUINT16 *flags = const_cast (&composite_header->flags); - *flags = (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS; - } while (composite_it.move_to_next ()); - return true; -} - static bool _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) { @@ -264,212 +239,285 @@ struct glyf return success; } - struct GlyphHeader - { - HBINT16 numberOfContours; /* If the number of contours is - * greater than or equal to zero, - * this is a simple glyph; if negative, - * this is a composite glyph. */ - FWORD xMin; /* Minimum x for coordinate data. */ - FWORD yMin; /* Minimum y for coordinate data. */ - FWORD xMax; /* Maximum x for coordinate data. */ - FWORD yMax; /* Maximum y for coordinate data. */ - - DEFINE_SIZE_STATIC (10); - }; - - struct CompositeGlyphHeader + struct CompositeGlyphChain { - enum composite_glyph_flag_t { - ARG_1_AND_2_ARE_WORDS = 0x0001, - ARGS_ARE_XY_VALUES = 0x0002, - ROUND_XY_TO_GRID = 0x0004, - WE_HAVE_A_SCALE = 0x0008, - MORE_COMPONENTS = 0x0020, - WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, - WE_HAVE_A_TWO_BY_TWO = 0x0080, - WE_HAVE_INSTRUCTIONS = 0x0100, - USE_MY_METRICS = 0x0200, - OVERLAP_COMPOUND = 0x0400, - SCALED_COMPONENT_OFFSET = 0x0800, - UNSCALED_COMPONENT_OFFSET = 0x1000 + protected: + enum composite_glyph_flag_t + { + ARG_1_AND_2_ARE_WORDS = 0x0001, + ARGS_ARE_XY_VALUES = 0x0002, + ROUND_XY_TO_GRID = 0x0004, + WE_HAVE_A_SCALE = 0x0008, + MORE_COMPONENTS = 0x0020, + WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, + WE_HAVE_A_TWO_BY_TWO = 0x0080, + WE_HAVE_INSTRUCTIONS = 0x0100, + USE_MY_METRICS = 0x0200, + OVERLAP_COMPOUND = 0x0400, + SCALED_COMPONENT_OFFSET = 0x0800, + UNSCALED_COMPONENT_OFFSET = 0x1000 }; - HBUINT16 flags; - GlyphID glyphIndex; - + public: unsigned int get_size () const { unsigned int size = min_size; - // arg1 and 2 are int16 + /* arg1 and 2 are int16 */ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; - // arg1 and 2 are int8 + /* arg1 and 2 are int8 */ else size += 2; - // One x 16 bit (scale) + /* One x 16 bit (scale) */ if (flags & WE_HAVE_A_SCALE) size += 2; - // Two x 16 bit (xscale, yscale) + /* Two x 16 bit (xscale, yscale) */ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; - // Four x 16 bit (xscale, scale01, scale10, yscale) + /* Four x 16 bit (xscale, scale01, scale10, yscale) */ else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; return size; } - // TODO rewrite using new iterator framework if possible - struct Iterator + void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; } + hb_codepoint_t get_glyph_index () const { return glyphIndex; } + + void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; } + bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; } + + bool has_more () const { return flags & MORE_COMPONENTS; } + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } + void get_anchor_points (unsigned int &point1, unsigned int &point2) const { - const char *glyph_start; - const char *glyph_end; - const CompositeGlyphHeader *current; + const HBUINT8 *p = &StructAfter (glyphIndex); + if (flags & ARG_1_AND_2_ARE_WORDS) + { + point1 = ((const HBUINT16 *) p)[0]; + point2 = ((const HBUINT16 *) p)[1]; + } + else + { + point1 = p[0]; + point2 = p[1]; + } + } - bool move_to_next () + void transform_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + if (get_transformation (matrix, trans)) { - if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) + if (scaled_offsets ()) { - const CompositeGlyphHeader *possible = - &StructAfter (*current); - if (!in_range (possible)) - return false; - current = possible; - return true; + points.translate (trans); + points.transform (matrix); + } + else + { + points.transform (matrix); + points.translate (trans); } - return false; } + } - bool in_range (const CompositeGlyphHeader *composite) const - { - return (const char *) composite >= glyph_start - && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end - && ((const char *) composite + composite->get_size ()) <= glyph_end; - } - }; + protected: + bool scaled_offsets () const + { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } - static bool get_iterator (const char * glyph_data, - unsigned int length, - CompositeGlyphHeader::Iterator *iterator /* OUT */) + bool get_transformation (float (&matrix)[4], contour_point_t &trans) const { - if (length < GlyphHeader::static_size) - return false; /* Empty glyph; zero extents. */ + matrix[0] = matrix[3] = 1.f; + matrix[1] = matrix[2] = 0.f; - const GlyphHeader &glyph_header = StructAtOffset (glyph_data, 0); - if (glyph_header.numberOfContours < 0) + int tx, ty; + const HBINT8 *p = &StructAfter (glyphIndex); + if (flags & ARG_1_AND_2_ARE_WORDS) { - const CompositeGlyphHeader *possible = - &StructAfter (glyph_header); - - iterator->glyph_start = glyph_data; - iterator->glyph_end = (const char *) glyph_data + length; - if (!iterator->in_range (possible)) - return false; - iterator->current = possible; - return true; + tx = *(const HBINT16 *) p; + p += HBINT16::static_size; + ty = *(const HBINT16 *) p; + p += HBINT16::static_size; } + else + { + tx = *p++; + ty = *p++; + } + if (is_anchored ()) tx = ty = 0; - return false; + trans.init ((float) tx, (float) ty); + + { + const F2DOT14 *points = (const F2DOT14 *) p; + if (flags & WE_HAVE_A_SCALE) + { + matrix[0] = matrix[3] = points[0].to_float (); + return true; + } + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + { + matrix[0] = points[0].to_float (); + matrix[3] = points[1].to_float (); + return true; + } + else if (flags & WE_HAVE_A_TWO_BY_TWO) + { + matrix[0] = points[0].to_float (); + matrix[1] = points[1].to_float (); + matrix[2] = points[2].to_float (); + matrix[3] = points[3].to_float (); + return true; + } + } + return tx || ty; } + protected: + HBUINT16 flags; + HBGlyphID glyphIndex; + public: DEFINE_SIZE_MIN (4); }; - struct accelerator_t + struct composite_iter_t : hb_iter_with_fallback_t { - void init (hb_face_t *face) + typedef const CompositeGlyphChain *__item_t__; + composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (current_) + { if (!check_range (current)) current = nullptr; } + composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {} + + const CompositeGlyphChain &__item__ () const { return *current; } + bool __more__ () const { return current; } + void __next__ () { - memset (this, 0, sizeof (accelerator_t)); - - const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) - /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ - return; - short_offset = 0 == head.indexToLocFormat; + if (!current->has_more ()) { current = nullptr; return; } - loca_table = hb_sanitize_context_t ().reference_table (face); - glyf_table = hb_sanitize_context_t ().reference_table (face); - - num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; + const CompositeGlyphChain *possible = &StructAfter (*current); + if (!check_range (possible)) { current = nullptr; return; } + current = possible; } + bool operator != (const composite_iter_t& o) const + { return glyph != o.glyph || current != o.current; } - void fini () + bool check_range (const CompositeGlyphChain *composite) const { - loca_table.destroy (); - glyf_table.destroy (); + return glyph.check_range (composite, CompositeGlyphChain::min_size) + && glyph.check_range (composite, composite->get_size ()); } - /* - * Returns true if the referenced glyph is a valid glyph and a composite glyph. - * If true is returned a pointer to the composite glyph will be written into - * composite. - */ - bool get_composite (hb_codepoint_t glyph, - CompositeGlyphHeader::Iterator *composite /* OUT */) const - { - if (unlikely (!num_glyphs)) - return false; + private: + hb_bytes_t glyph; + __item_t__ current; + }; - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; /* glyph not found */ + enum phantom_point_index_t + { + PHANTOM_LEFT = 0, + PHANTOM_RIGHT = 1, + PHANTOM_TOP = 2, + PHANTOM_BOTTOM = 3, + PHANTOM_COUNT = 4 + }; - return CompositeGlyphHeader::get_iterator ((const char *) this->glyf_table + start_offset, - end_offset - start_offset, - composite); - } + struct accelerator_t; - enum simple_glyph_flag_t { - FLAG_ON_CURVE = 0x01, - FLAG_X_SHORT = 0x02, - FLAG_Y_SHORT = 0x04, - FLAG_REPEAT = 0x08, - FLAG_X_SAME = 0x10, - FLAG_Y_SAME = 0x20, + struct Glyph + { + enum simple_glyph_flag_t + { + FLAG_ON_CURVE = 0x01, + FLAG_X_SHORT = 0x02, + FLAG_Y_SHORT = 0x04, + FLAG_REPEAT = 0x08, + FLAG_X_SAME = 0x10, + FLAG_Y_SAME = 0x20, FLAG_RESERVED1 = 0x40, FLAG_RESERVED2 = 0x80 }; - /* based on FontTools _g_l_y_f.py::trim */ - bool remove_padding (unsigned int start_offset, - unsigned int *end_offset) const + private: + struct GlyphHeader { - if (*end_offset - start_offset < GlyphHeader::static_size) return true; + bool has_data () const { return numberOfContours; } - const char *glyph = ((const char *) glyf_table) + start_offset; - const char * const glyph_end = glyph + (*end_offset - start_offset); - const GlyphHeader &glyph_header = StructAtOffset (glyph, 0); - int16_t num_contours = (int16_t) glyph_header.numberOfContours; + bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, + hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ + /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ + extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid)); + extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); + extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); + extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); - if (num_contours < 0) - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ return true; - else if (num_contours > 0) + } + + HBINT16 numberOfContours; + /* If the number of contours is + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ + FWORD xMin; /* Minimum x for coordinate data. */ + FWORD yMin; /* Minimum y for coordinate data. */ + FWORD xMax; /* Maximum x for coordinate data. */ + FWORD yMax; /* Maximum y for coordinate data. */ + public: + DEFINE_SIZE_STATIC (10); + }; + + struct SimpleGlyph + { + const GlyphHeader &header; + hb_bytes_t bytes; + SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + unsigned int instruction_len_offset () const + { return GlyphHeader::static_size + 2 * header.numberOfContours; } + + unsigned int length (unsigned int instruction_len) const + { return instruction_len_offset () + 2 + instruction_len; } + + unsigned int instructions_length () const + { + unsigned int instruction_length_offset = instruction_len_offset (); + if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; + + const HBUINT16 &instructionLength = StructAtOffset (&bytes, instruction_length_offset); + /* Out of bounds of the current glyph */ + if (unlikely (length (instructionLength) > bytes.length)) return 0; + return instructionLength; + } + + const Glyph trim_padding () const { + /* based on FontTools _g_l_y_f.py::trim */ + const char *glyph = bytes.arrayZ; + const char *glyph_end = glyph + bytes.length; /* simple glyph w/contours, possibly trimmable */ - glyph += GlyphHeader::static_size + 2 * num_contours; + glyph += instruction_len_offset (); - if (unlikely (glyph + 2 >= glyph_end)) return false; - uint16_t nCoordinates = (uint16_t) StructAtOffset (glyph - 2, 0) + 1; - uint16_t nInstructions = (uint16_t) StructAtOffset (glyph, 0); + if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); + unsigned int num_coordinates = StructAtOffset (glyph - 2, 0) + 1; + unsigned int num_instructions = StructAtOffset (glyph, 0); - glyph += 2 + nInstructions; - if (unlikely (glyph + 2 >= glyph_end)) return false; + glyph += 2 + num_instructions; - unsigned int coordBytes = 0; - unsigned int coordsWithFlags = 0; + unsigned int coord_bytes = 0; + unsigned int coords_with_flags = 0; while (glyph < glyph_end) { - uint8_t flag = (uint8_t) *glyph; + uint8_t flag = *glyph; glyph++; unsigned int repeat = 1; if (flag & FLAG_REPEAT) { - if (glyph >= glyph_end) - { - DEBUG_MSG(SUBSET, nullptr, "Bad flag"); - return false; - } - repeat = ((uint8_t) *glyph) + 1; + if (unlikely (glyph >= glyph_end)) return Glyph (); + repeat = *glyph + 1; glyph++; } @@ -481,243 +529,728 @@ struct glyf if (flag & FLAG_Y_SHORT) yBytes = 1; else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; - coordBytes += (xBytes + yBytes) * repeat; - coordsWithFlags += repeat; - if (coordsWithFlags >= nCoordinates) - break; + coord_bytes += (xBytes + yBytes) * repeat; + coords_with_flags += repeat; + if (coords_with_flags >= num_coordinates) break; } - if (coordsWithFlags != nCoordinates) + if (unlikely (coords_with_flags != num_coordinates)) return Glyph (); + return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph))); + } + + /* zero instruction length */ + void drop_hints () + { + GlyphHeader &glyph_header = const_cast (header); + (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; + } + + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + unsigned int instructions_len = instructions_length (); + unsigned int glyph_length = length (instructions_len); + dest_start = bytes.sub_array (0, glyph_length - instructions_len); + dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); + } + + static bool read_points (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const hb_bytes_t &bytes, + void (* setter) (contour_point_t &_, float v), + const simple_glyph_flag_t short_flag, + const simple_glyph_flag_t same_flag) + { + float v = 0; + for (unsigned i = 0; i < points_.length; i++) { - DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags); - return false; + uint8_t flag = points_[i].flag; + if (flag & short_flag) + { + if (unlikely (!bytes.check_range (p))) return false; + if (flag & same_flag) + v += *p++; + else + v -= *p++; + } + else + { + if (!(flag & same_flag)) + { + if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false; + v += *(const HBINT16 *) p; + p += HBINT16::static_size; + } + } + setter (points_[i], v); + } + return true; + } + + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + bool phantom_only = false) const + { + const HBUINT16 *endPtsOfContours = &StructAfter (header); + int num_contours = header.numberOfContours; + if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false; + unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; + + points_.resize (num_points); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + if (phantom_only) return true; + + for (int i = 0; i < num_contours; i++) + points_[endPtsOfContours[i]].is_end_point = true; + + /* Skip instructions */ + const HBUINT8 *p = &StructAtOffset (&endPtsOfContours[num_contours + 1], + endPtsOfContours[num_contours]); + + /* Read flags */ + for (unsigned int i = 0; i < num_points; i++) + { + if (unlikely (!bytes.check_range (p))) return false; + uint8_t flag = *p++; + points_[i].flag = flag; + if (flag & FLAG_REPEAT) + { + if (unlikely (!bytes.check_range (p))) return false; + unsigned int repeat_count = *p++; + while ((repeat_count-- > 0) && (++i < num_points)) + points_[i].flag = flag; + } } - glyph += coordBytes; - if (glyph < glyph_end) - *end_offset -= glyph_end - glyph; + /* Read x & y coordinates */ + return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; }, + FLAG_X_SHORT, FLAG_X_SAME) + && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; }, + FLAG_Y_SHORT, FLAG_Y_SAME); } - return true; - } + }; - bool get_offsets (hb_codepoint_t glyph, - unsigned int *start_offset /* OUT */, - unsigned int *end_offset /* OUT */) const + struct CompositeGlyph { - if (unlikely (glyph >= num_glyphs)) - return false; + const GlyphHeader &header; + hb_bytes_t bytes; + CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} - if (short_offset) + composite_iter_t get_iterator () const + { return composite_iter_t (bytes, &StructAfter (header)); } + + unsigned int instructions_length (hb_bytes_t bytes) const { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; - *start_offset = 2 * offsets[glyph]; - *end_offset = 2 * offsets[glyph + 1]; + unsigned int start = bytes.length; + unsigned int end = bytes.length; + const CompositeGlyphChain *last = nullptr; + for (auto &item : get_iterator ()) + last = &item; + if (unlikely (!last)) return 0; + + if (last->has_instructions ()) + start = (char *) last - &bytes + last->get_size (); + if (unlikely (start > end)) return 0; + return end - start; } - else + + /* Trimming for composites not implemented. + * If removing hints it falls out of that. */ + const Glyph trim_padding () const { return Glyph (bytes); } + + void drop_hints () { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + for (const auto &_ : get_iterator ()) + const_cast (_).drop_instructions_flag (); + } - *start_offset = offsets[glyph]; - *end_offset = offsets[glyph + 1]; + /* Chop instructions off the end */ + void drop_hints_bytes (hb_bytes_t &dest_start) const + { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } + }; + + enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + + public: + composite_iter_t get_composite_iterator () const + { + if (type != COMPOSITE) return composite_iter_t (); + return CompositeGlyph (*header, bytes).get_iterator (); + } + + const Glyph trim_padding () const + { + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); + case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + default: return bytes; } + } - if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ()) - return false; + void drop_hints () + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; + default: return; + } + } - return true; + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; + default: return; + } } - bool get_instruction_length (hb_bytes_t glyph, - unsigned int * length /* OUT */) const + /* Note: Recursively calls itself. + * all_points includes phantom points + */ + bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, + contour_point_vector_t &all_points /* OUT */, + bool phantom_only = false, + unsigned int depth = 0) const { - /* Empty glyph; no instructions. */ - if (glyph.length < GlyphHeader::static_size) + if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; + contour_point_vector_t points; + + switch (type) { + case COMPOSITE: { - *length = 0; - // only 0 byte glyphs are healthy when missing GlyphHeader - return glyph.length == 0; + /* pseudo component points for each component in composite glyph */ + unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ()); + if (unlikely (!points.resize (num_points))) return false; + for (unsigned i = 0; i < points.length; i++) + points[i].init (); + break; } - const GlyphHeader &glyph_header = StructAtOffset (&glyph, 0); - int16_t num_contours = (int16_t) glyph_header.numberOfContours; - if (num_contours < 0) - { - unsigned int start = glyph.length; - unsigned int end = glyph.length; - unsigned int glyph_offset = &glyph - glyf_table; - CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!CompositeGlyphHeader::get_iterator (&glyph, glyph.length, &composite_it))) return false; - const CompositeGlyphHeader *last; - do { - last = composite_it.current; - } while (composite_it.move_to_next ()); - - if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) - start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size () - glyph_offset; - if (unlikely (start > end)) - { - DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside %d byte buffer", start, glyph.length); + case SIMPLE: + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) return false; - } - *length = end - start; + break; } - else + + /* Init phantom points */ + if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; + hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { - unsigned int instruction_length_offset = GlyphHeader::static_size + 2 * num_contours; - if (unlikely (instruction_length_offset + 2 > glyph.length)) - { - DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength."); - return false; - } + for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init (); + int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid); + int v_orig = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid); + unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); + unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid); + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_orig; + phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; + } - const HBUINT16 &instruction_length = StructAtOffset (&glyph, instruction_length_offset); - if (unlikely (instruction_length_offset + instruction_length > glyph.length)) // Out of bounds of the current glyph +#ifndef HB_NO_VAR + if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()))) + return false; +#endif + + switch (type) { + case SIMPLE: + all_points.extend (points.as_array ()); + break; + case COMPOSITE: + { + unsigned int comp_index = 0; + for (auto &item : get_composite_iterator ()) { - DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries."); - return false; + contour_point_vector_t comp_points; + if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ()) + .get_points (font, glyf_accelerator, comp_points, + phantom_only, depth + 1) + || comp_points.length < PHANTOM_COUNT)) + return false; + + /* Copy phantom points from component if USE_MY_METRICS flag set */ + if (item.is_use_my_metrics ()) + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + + /* Apply component transformation & translation */ + item.transform_points (comp_points); + + /* Apply translation from gvar */ + comp_points.translate (points[comp_index]); + + if (item.is_anchored ()) + { + unsigned int p1, p2; + item.get_anchor_points (p1, p2); + if (likely (p1 < all_points.length && p2 < comp_points.length)) + { + contour_point_t delta; + delta.init (all_points[p1].x - comp_points[p2].x, + all_points[p1].y - comp_points[p2].y); + + comp_points.translate (delta); + } + } + + all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); + + comp_index++; } - *length = (uint16_t) instruction_length; + + all_points.extend (phantoms); + } break; + default: + all_points.extend (phantoms); } + + if (depth == 0) /* Apply at top level */ + { + /* Undocumented rasterizer behavior: + * Shift points horizontally by the updated left side bearing + */ + contour_point_t delta; + delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); + if (delta.x) all_points.translate (delta); + } + return true; } - bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, + hb_glyph_extents_t *extents) const { - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; + if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + return header->get_extents (font, glyf_accelerator, gid, extents); + } - if (end_offset - start_offset < GlyphHeader::static_size) - return true; /* Empty glyph; zero extents. */ + hb_bytes_t get_bytes () const { return bytes; } - const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); + Glyph (hb_bytes_t bytes_ = hb_bytes_t (), + hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_), + header (bytes.as ()) + { + int num_contours = header->numberOfContours; + if (unlikely (num_contours == 0)) type = EMPTY; + else if (num_contours > 0) type = SIMPLE; + else type = COMPOSITE; /* negative numbers */ + } - extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); - extents->y_bearing = hb_max (glyph_header.yMin, glyph_header.yMax); - extents->width = hb_max (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; - extents->height = hb_min (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; + protected: + hb_bytes_t bytes; + hb_codepoint_t gid; + const GlyphHeader *header; + unsigned type; + }; - return true; + struct accelerator_t + { + void init (hb_face_t *face_) + { + short_offset = false; + num_glyphs = 0; + loca_table = nullptr; + glyf_table = nullptr; +#ifndef HB_NO_VAR + gvar = nullptr; +#endif + hmtx = nullptr; + vmtx = nullptr; + face = face_; + const OT::head &head = *face->table.head; + if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) + /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ + return; + short_offset = 0 == head.indexToLocFormat; + + loca_table = hb_sanitize_context_t ().reference_table (face); + glyf_table = hb_sanitize_context_t ().reference_table (face); +#ifndef HB_NO_VAR + gvar = face->table.gvar; +#endif + hmtx = face->table.hmtx; + vmtx = face->table.vmtx; + + num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; + num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); } - hb_bytes_t bytes_for_glyph (const char * glyf, hb_codepoint_t gid) - { - unsigned int start_offset, end_offset; - if (unlikely (!(get_offsets (gid, &start_offset, &end_offset) && - remove_padding (start_offset, &end_offset)))) + void fini () { - DEBUG_MSG(SUBSET, nullptr, "Unable to get offset or remove padding for %d", gid); - return hb_bytes_t (); + loca_table.destroy (); + glyf_table.destroy (); } - hb_bytes_t glyph = hb_bytes_t (glyf + start_offset, end_offset - start_offset); - if (glyph.length == 0) return glyph; - if (unlikely (glyph.length < GlyphHeader::static_size)) + + protected: + template + bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const { - DEBUG_MSG(SUBSET, nullptr, "Glyph size smaller than minimum header %d", gid); - return hb_bytes_t (); + if (gid >= num_glyphs) return false; + + /* Making this alloc free is not that easy + https://github.com/harfbuzz/harfbuzz/issues/2095 + mostly because of gvar handling in VF fonts, + perhaps a separate path for non-VF fonts can be considered */ + contour_point_vector_t all_points; + + bool phantom_only = !consumer.is_consuming_contour_points (); + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) + return false; + + if (consumer.is_consuming_contour_points ()) + { + for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) + consumer.consume_point (all_points[point_index]); + consumer.points_end (); + } + + /* Where to write phantoms, nullptr if not requested */ + contour_point_t *phantoms = consumer.get_phantoms_sink (); + if (phantoms) + for (unsigned i = 0; i < PHANTOM_COUNT; ++i) + phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i]; + + return true; } - return glyph; - } - private: - bool short_offset; - unsigned int num_glyphs; - hb_blob_ptr_t loca_table; - hb_blob_ptr_t glyf_table; - }; +#ifndef HB_NO_VAR + struct points_aggregator_t + { + hb_font_t *font; + hb_glyph_extents_t *extents; + contour_point_t *phantoms; + struct contour_bounds_t + { + contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } - struct SubsetGlyph - { - hb_codepoint_t new_gid; - hb_codepoint_t old_gid; - hb_bytes_t source_glyph; - hb_bytes_t dest_start; // region of source_glyph to copy first - hb_bytes_t dest_end; // region of source_glyph to copy second + void add (const contour_point_t &p) + { + min_x = hb_min (min_x, p.x); + min_y = hb_min (min_y, p.y); + max_x = hb_max (max_x, p.x); + max_y = hb_max (max_y, p.y); + } + bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } - bool serialize (hb_serialize_context_t *c, - const hb_subset_plan_t *plan) const - { - TRACE_SERIALIZE (this); + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) + { + if (unlikely (empty ())) + { + extents->width = 0; + extents->x_bearing = 0; + extents->height = 0; + extents->y_bearing = 0; + return; + } + extents->x_bearing = font->em_scalef_x (min_x); + extents->width = font->em_scalef_x (max_x) - extents->x_bearing; + extents->y_bearing = font->em_scalef_y (max_y); + extents->height = font->em_scalef_y (min_y) - extents->y_bearing; + } - hb_bytes_t dest_glyph = dest_start.copy(c); - dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy(c).length); - unsigned int pad_length = padding (); - DEBUG_MSG(SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + protected: + float min_x, min_y, max_x, max_y; + } bounds; - HBUINT8 pad; - pad = 0; - while (pad_length > 0) + points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) + { + font = font_; + extents = extents_; + phantoms = phantoms_; + if (extents) bounds = contour_bounds_t (); + } + + void consume_point (const contour_point_t &point) { bounds.add (point); } + void points_end () { bounds.get_extents (font, extents); } + + bool is_consuming_contour_points () { return extents; } + contour_point_t *get_phantoms_sink () { return phantoms; } + }; + + public: + unsigned + get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { - c->embed(pad); - pad_length--; + if (unlikely (gid >= num_glyphs)) return 0; + + bool success = false; + + contour_point_t phantoms[PHANTOM_COUNT]; + if (likely (font->num_coords == gvar->get_axis_count ())) + success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); + + if (unlikely (!success)) + return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid); + + float result = is_vertical + ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y + : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x; + return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); } - if (dest_glyph.length) + int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { - _fix_component_gids (plan, dest_glyph); - if (plan->drop_hints) - { - _zero_instruction_length (dest_glyph); - c->check_success (_remove_composite_instruction_flag (dest_glyph)); - } + if (unlikely (gid >= num_glyphs)) return 0; + + hb_glyph_extents_t extents; + + contour_point_t phantoms[PHANTOM_COUNT]; + if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) + return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid); + + return is_vertical + ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing + : floorf (phantoms[PHANTOM_LEFT].x); } +#endif - return_trace (true); - } + public: + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + if (unlikely (gid >= num_glyphs)) return false; - void drop_hints (const OT::glyf::accelerator_t& glyf) +#ifndef HB_NO_VAR + if (font->num_coords && font->num_coords == gvar->get_axis_count ()) + return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); +#endif + return glyph_for_gid (gid).get_extents (font, *this, extents); + } + + const Glyph + glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const { - if (source_glyph.length == 0) return; + if (unlikely (gid >= num_glyphs)) return Glyph (); - unsigned int instruction_length = 0; - if (!glyf.get_instruction_length (source_glyph, &instruction_length)) - { - DEBUG_MSG(SUBSET, nullptr, "Unable to read instruction length for new_gid %d", new_gid); - return ; - } + unsigned int start_offset, end_offset; - const GlyphHeader& header = StructAtOffset (&source_glyph, 0); - int16_t num_contours = (int16_t) header.numberOfContours; - DEBUG_MSG(SUBSET, nullptr, "new_gid %d (%d contours) drop %d instruction bytes from %d byte source glyph", new_gid, num_contours, instruction_length, source_glyph.length); - if (num_contours < 0) + if (short_offset) { - // composite, just chop instructions off the end - dest_start = hb_bytes_t (&source_glyph, source_glyph.length - instruction_length); + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; + start_offset = 2 * offsets[gid]; + end_offset = 2 * offsets[gid + 1]; } else { - // simple glyph - dest_start = hb_bytes_t (&source_glyph, GlyphHeader::static_size + 2 * header.numberOfContours + 2); - dest_end = hb_bytes_t (&source_glyph + dest_start.length + instruction_length, - source_glyph.length - dest_start.length - instruction_length); -DEBUG_MSG(SUBSET, nullptr, "source_len %d start len %d instruction_len %d end len %d", source_glyph.length, dest_start.length, instruction_length, dest_end.length); + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + start_offset = offsets[gid]; + end_offset = offsets[gid + 1]; } + + if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) + return Glyph (); + + Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, + end_offset - start_offset), gid); + return needs_padding_removal ? glyph.trim_padding () : glyph; } - unsigned int length () const + void + add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain, + unsigned int depth = 0) const { - return dest_start.length + dest_end.length; + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return; + /* Check if is already visited */ + if (gids_to_retain->has (gid)) return; + + gids_to_retain->add (gid); + + for (auto &item : glyph_for_gid (gid).get_composite_iterator ()) + add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth); } - // pad to 2 to ensure 2-byte loca will be ok - unsigned int padding () const +#ifdef HB_EXPERIMENTAL_API + struct path_builder_t { - return length () % 2; - } + hb_font_t *font; + draw_helper_t *draw_helper; - unsigned int padded_size () const + struct optional_point_t + { + optional_point_t () { has_data = false; } + optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; } + + bool has_data; + float x; + float y; + + optional_point_t lerp (optional_point_t p, float t) + { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } + } first_oncurve, first_offcurve, last_offcurve; + + path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_) + { + font = font_; + draw_helper = &draw_helper_; + first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + } + + /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 + See also: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html + * https://stackoverflow.com/a/20772557 */ + void consume_point (const contour_point_t &point) + { + /* Skip empty contours */ + if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data)) + return; + + bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; + optional_point_t p (point.x, point.y); + if (!first_oncurve.has_data) + { + if (is_on_curve) + { + first_oncurve = p; + draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + } + else + { + if (first_offcurve.has_data) + { + optional_point_t mid = first_offcurve.lerp (p, .5f); + first_oncurve = mid; + last_offcurve = p; + draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + } + else + first_offcurve = p; + } + } + else + { + if (last_offcurve.has_data) + { + if (is_on_curve) + { + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + last_offcurve = optional_point_t (); + } + else + { + optional_point_t mid = last_offcurve.lerp (p, .5f); + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + last_offcurve = p; + } + } + else + { + if (is_on_curve) + draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + else + last_offcurve = p; + } + } + + if (point.is_end_point) + { + if (first_offcurve.has_data && last_offcurve.has_data) + { + optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + last_offcurve = optional_point_t (); + /* now check the rest */ + } + + if (first_offcurve.has_data && first_oncurve.has_data) + draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y), + font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + else if (last_offcurve.has_data && first_oncurve.has_data) + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + else if (first_oncurve.has_data) + draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + + /* Getting ready for the next contour */ + first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + draw_helper->end_path (); + } + } + void points_end () {} + + bool is_consuming_contour_points () { return true; } + contour_point_t *get_phantoms_sink () { return nullptr; } + }; + + bool + get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const + { return get_points (font, gid, path_builder_t (font, draw_helper)); } +#endif + +#ifndef HB_NO_VAR + const gvar_accelerator_t *gvar; +#endif + const hmtx_accelerator_t *hmtx; + const vmtx_accelerator_t *vmtx; + + private: + bool short_offset; + unsigned int num_glyphs; + hb_blob_ptr_t loca_table; + hb_blob_ptr_t glyf_table; + hb_face_t *face; + }; + + struct SubsetGlyph + { + hb_codepoint_t new_gid; + hb_codepoint_t old_gid; + Glyph source_glyph; + hb_bytes_t dest_start; /* region of source_glyph to copy first */ + hb_bytes_t dest_end; /* region of source_glyph to copy second */ + + bool serialize (hb_serialize_context_t *c, + const hb_subset_plan_t *plan) const { - return length () + padding (); + TRACE_SERIALIZE (this); + + hb_bytes_t dest_glyph = dest_start.copy (c); + dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); + unsigned int pad_length = padding (); + DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + + HBUINT8 pad; + pad = 0; + while (pad_length > 0) + { + c->embed (pad); + pad_length--; + } + + if (unlikely (!dest_glyph.length)) return_trace (true); + + /* update components gids */ + for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) + { + hb_codepoint_t new_gid; + if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid)) + const_cast (_).set_glyph_index (new_gid); + } + + if (plan->drop_hints) Glyph (dest_glyph).drop_hints (); + + return_trace (true); } + + void drop_hints_bytes () + { source_glyph.drop_hints_bytes (dest_start, dest_end); } + + unsigned int length () const { return dest_start.length + dest_end.length; } + /* pad to 2 to ensure 2-byte loca will be ok */ + unsigned int padding () const { return length () % 2; } + unsigned int padded_size () const { return length () + padding (); } }; protected: - UnsizedArrayOf dataZ; /* Glyphs data. */ + UnsizedArrayOf + dataZ; /* Glyphs data. */ public: - DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always - * check the size externally, allow Null() object of it by - * defining it _MIN instead. */ + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it _MIN instead. */ }; struct glyf_accelerator_t : glyf::accelerator_t {}; diff --git a/src/hb-ot-hdmx-table.hh b/src/hb-ot-hdmx-table.hh index 96c1d1f634f81e4ac3cae9cbf06205c82318ab16..590fa154ba135b7a3cbcf1c184425956bed6c67b 100644 --- a/src/hb-ot-hdmx-table.hh +++ b/src/hb-ot-hdmx-table.hh @@ -107,13 +107,10 @@ struct hdmx this->numRecords = it.len (); this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0); - + it - | hb_apply ([c] (const hb_item_type& _) { - c->start_embed ()->serialize (c, _.first, _.second); - }) - ; + for (const hb_item_type& _ : +it) + c->start_embed ()->serialize (c, _.first, _.second); - return_trace (c->successful); + return_trace (c->successful ()); } @@ -134,10 +131,10 @@ struct hdmx auto row = + hb_range (c->plan->num_output_glyphs ()) | hb_map (c->plan->reverse_glyph_map) - | hb_map ([=] (hb_codepoint_t _) + | hb_map ([this, c, device_record] (hb_codepoint_t _) { if (c->plan->is_empty_glyph (_)) - return Null(HBUINT8); + return Null (HBUINT8); return device_record->widthsZ.as_array (get_num_glyphs ()) [_]; }) ; @@ -164,10 +161,12 @@ struct hdmx } protected: - HBUINT16 version; /* Table version number (0) */ - HBUINT16 numRecords; /* Number of device records. */ - HBUINT32 sizeDeviceRecord; /* Size of a device record, 32-bit aligned. */ - DeviceRecord firstDeviceRecord; /* Array of device records. */ + HBUINT16 version; /* Table version number (0) */ + HBUINT16 numRecords; /* Number of device records. */ + HBUINT32 sizeDeviceRecord; + /* Size of a device record, 32-bit aligned. */ + DeviceRecord firstDeviceRecord; + /* Array of device records. */ public: DEFINE_SIZE_MIN (8); }; diff --git a/src/hb-ot-head-table.hh b/src/hb-ot-head-table.hh index 3c0bb3d6dddfa2677185ad85201c9b28a8abf25a..ac588e3af6d1e9da2e8d1c3dc80854359d7d54e9 100644 --- a/src/hb-ot-head-table.hh +++ b/src/hb-ot-head-table.hh @@ -43,7 +43,7 @@ namespace OT { struct head { - friend struct OffsetTable; + friend struct OpenTypeOffsetTable; static constexpr hb_tag_t tableTag = HB_OT_TAG_head; @@ -54,6 +54,18 @@ struct head return 16 <= upem && upem <= 16384 ? upem : 1000; } + bool serialize (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace ((bool) c->embed (this)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace (serialize (c->serializer)); + } + enum mac_style_flag_t { BOLD = 1u<<0, ITALIC = 1u<<1, diff --git a/src/hb-ot-hhea-table.hh b/src/hb-ot-hhea-table.hh index 778b6c513233eb99bdb890215db1238ffc5d7e33..d9c9bd35377e918133dde679fd95c958fe00400a 100644 --- a/src/hb-ot-hhea-table.hh +++ b/src/hb-ot-hhea-table.hh @@ -54,35 +54,38 @@ struct _hea } public: - FixedVersion<>version; /* 0x00010000u for version 1.0. */ - FWORD ascender; /* Typographic ascent. */ - FWORD descender; /* Typographic descent. */ - FWORD lineGap; /* Typographic line gap. */ - UFWORD advanceMax; /* Maximum advance width/height value in - * metrics table. */ - FWORD minLeadingBearing; /* Minimum left/top sidebearing value in - * metrics table. */ - FWORD minTrailingBearing; /* Minimum right/bottom sidebearing value; - * calculated as Min(aw - lsb - - * (xMax - xMin)) for horizontal. */ - FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)), - * vertical: minLeadingBearing+(yMax-yMin). */ - HBINT16 caretSlopeRise; /* Used to calculate the slope of the - * cursor (rise/run); 1 for vertical caret, - * 0 for horizontal.*/ - HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */ - HBINT16 caretOffset; /* The amount by which a slanted - * highlight on a glyph needs - * to be shifted to produce the - * best appearance. Set to 0 for - * non-slanted fonts. */ - HBINT16 reserved1; /* Set to 0. */ - HBINT16 reserved2; /* Set to 0. */ - HBINT16 reserved3; /* Set to 0. */ - HBINT16 reserved4; /* Set to 0. */ - HBINT16 metricDataFormat; /* 0 for current format. */ - HBUINT16 numberOfLongMetrics; /* Number of LongMetric entries in metric - * table. */ + FixedVersion<>version; /* 0x00010000u for version 1.0. */ + FWORD ascender; /* Typographic ascent. */ + FWORD descender; /* Typographic descent. */ + FWORD lineGap; /* Typographic line gap. */ + UFWORD advanceMax; /* Maximum advance width/height value in + * metrics table. */ + FWORD minLeadingBearing; + /* Minimum left/top sidebearing value in + * metrics table. */ + FWORD minTrailingBearing; + /* Minimum right/bottom sidebearing value; + * calculated as Min(aw - lsb - + * (xMax - xMin)) for horizontal. */ + FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)), + * vertical: minLeadingBearing+(yMax-yMin). */ + HBINT16 caretSlopeRise; /* Used to calculate the slope of the + * cursor (rise/run); 1 for vertical caret, + * 0 for horizontal.*/ + HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */ + HBINT16 caretOffset; /* The amount by which a slanted + * highlight on a glyph needs + * to be shifted to produce the + * best appearance. Set to 0 for + * non-slanted fonts. */ + HBINT16 reserved1; /* Set to 0. */ + HBINT16 reserved2; /* Set to 0. */ + HBINT16 reserved3; /* Set to 0. */ + HBINT16 reserved4; /* Set to 0. */ + HBINT16 metricDataFormat;/* 0 for current format. */ + HBUINT16 numberOfLongMetrics; + /* Number of LongMetric entries in metric + * table. */ public: DEFINE_SIZE_STATIC (36); }; diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 11a588e3814ed3e2bd0efdc9aacda930a5f4acfa..403832993823e9b951f4b0afbeff56748a2a76fe 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -42,6 +42,13 @@ #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') +HB_INTERNAL int +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); + +HB_INTERNAL unsigned +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); + + namespace OT { @@ -53,6 +60,7 @@ struct LongMetric DEFINE_SIZE_STATIC (4); }; + template struct hmtxvmtx { @@ -66,7 +74,7 @@ struct hmtxvmtx bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + unsigned int num_hmetrics) const { hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); @@ -87,31 +95,29 @@ struct hmtxvmtx } template + hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, - Iterator it, - unsigned num_advances) + Iterator it, + unsigned num_advances) { unsigned idx = 0; - + it - | hb_apply ([c, &idx, num_advances] (const hb_item_type& _) - { - if (idx < num_advances) - { - LongMetric lm; - lm.advance = _.first; - lm.sb = _.second; - if (unlikely (!c->embed (&lm))) return; - } - else - { - FWORD *sb = c->allocate_size (FWORD::static_size); - if (unlikely (!sb)) return; - *sb = _.second; - } - idx++; - }) - ; + for (auto _ : it) + { + if (idx < num_advances) + { + LongMetric lm; + lm.advance = _.first; + lm.sb = _.second; + if (unlikely (!c->embed (&lm))) return; + } + else + { + FWORD *sb = c->allocate_size (FWORD::static_size); + if (unlikely (!sb)) return; + *sb = _.second; + } + idx++; + } } bool subset (hb_subset_context_t *c) const @@ -128,27 +134,24 @@ struct hmtxvmtx auto it = + hb_range (c->plan->num_output_glyphs ()) | hb_map ([c, &_mtx] (unsigned _) - { - hb_codepoint_t old_gid; - if (c->plan->old_gid_for_new_gid (_, &old_gid)) - return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid)); - else - return hb_pair (0u, 0u); - }) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (_, &old_gid)) + return hb_pair (0u, 0); + return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid)); + }) ; table_prime->serialize (c->serializer, it, num_advances); _mtx.fini (); - if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ())) + if (unlikely (c->serializer->in_error ())) return_trace (false); // Amend header num hmetrics if (unlikely (!subset_update_header (c->plan, num_advances))) - { return_trace (false); - } return_trace (true); } @@ -158,13 +161,13 @@ struct hmtxvmtx friend struct hmtxvmtx; void init (hb_face_t *face, - unsigned int default_advance_ = 0) + unsigned int default_advance_ = 0) { default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics; - table = hb_sanitize_context_t().reference_table (face, T::tableTag); + table = hb_sanitize_context_t ().reference_table (face, T::tableTag); /* Cap num_metrics() and num_advances() based on table length. */ unsigned int len = table.get_length (); @@ -181,7 +184,7 @@ struct hmtxvmtx table = hb_blob_get_empty (); } - var_table = hb_sanitize_context_t().reference_table (face, T::variationsTag); + var_table = hb_sanitize_context_t ().reference_table (face, T::variationsTag); } void fini () @@ -190,19 +193,35 @@ struct hmtxvmtx var_table.destroy (); } - /* TODO Add variations version. */ - unsigned int get_side_bearing (hb_codepoint_t glyph) const + int get_side_bearing (hb_codepoint_t glyph) const { if (glyph < num_advances) - return table->longMetricZ[glyph].sb; + return table->longMetricZ[glyph].sb; if (unlikely (glyph >= num_metrics)) - return 0; + return 0; const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; return bearings[glyph - num_advances]; } + int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const + { + int side_bearing = get_side_bearing (glyph); + +#ifndef HB_NO_VAR + if (unlikely (glyph >= num_metrics) || !font->num_coords) + return side_bearing; + + if (var_table.get_length ()) + return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + + return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); +#else + return side_bearing; +#endif + } + unsigned int get_advance (hb_codepoint_t glyph) const { if (unlikely (glyph >= num_metrics)) @@ -223,23 +242,30 @@ struct hmtxvmtx hb_font_t *font) const { unsigned int advance = get_advance (glyph); - if (likely (glyph < num_metrics)) - { - advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! - } + +#ifndef HB_NO_VAR + if (unlikely (glyph >= num_metrics) || !font->num_coords) + return advance; + + if (var_table.get_length ()) + return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?! + + return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); +#else return advance; +#endif } unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const { unsigned int num_advances = plan->num_output_glyphs (); unsigned int last_advance = _advance_for_new_gid (plan, - num_advances - 1); + num_advances - 1); while (num_advances > 1 && - last_advance == _advance_for_new_gid (plan, - num_advances - 2)) + last_advance == _advance_for_new_gid (plan, + num_advances - 2)) { - num_advances--; + num_advances--; } return num_advances; @@ -247,11 +273,11 @@ struct hmtxvmtx private: unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, - hb_codepoint_t new_gid) const + hb_codepoint_t new_gid) const { hb_codepoint_t old_gid; if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) - return 0; + return 0; return get_advance (old_gid); } @@ -267,27 +293,29 @@ struct hmtxvmtx }; protected: - UnsizedArrayOflongMetricZ;/* Paired advance width and leading - * bearing values for each glyph. The - * value numOfHMetrics comes from - * the 'hhea' table. If the font is - * monospaced, only one entry need - * be in the array, but that entry is - * required. The last entry applies to - * all subsequent glyphs. */ -/*UnsizedArrayOf leadingBearingX;*//* Here the advance is assumed - * to be the same as the advance - * for the last entry above. The - * number of entries in this array is - * derived from numGlyphs (from 'maxp' - * table) minus numberOfLongMetrics. - * This generally is used with a run - * of monospaced glyphs (e.g., Kanji - * fonts or Courier fonts). Only one - * run is allowed and it must be at - * the end. This allows a monospaced - * font to vary the side bearing - * values for each glyph. */ + UnsizedArrayOf + longMetricZ; /* Paired advance width and leading + * bearing values for each glyph. The + * value numOfHMetrics comes from + * the 'hhea' table. If the font is + * monospaced, only one entry need + * be in the array, but that entry is + * required. The last entry applies to + * all subsequent glyphs. */ +/*UnsizedArrayOf leadingBearingX;*/ + /* Here the advance is assumed + * to be the same as the advance + * for the last entry above. The + * number of entries in this array is + * derived from numGlyphs (from 'maxp' + * table) minus numberOfLongMetrics. + * This generally is used with a run + * of monospaced glyphs (e.g., Kanji + * fonts or Courier fonts). Only one + * run is allowed and it must be at + * the end. This allows a monospaced + * font to vary the side bearing + * values for each glyph. */ public: DEFINE_SIZE_ARRAY (0, longMetricZ); }; diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh index 7dfb207b2dc484fee2a14f5b85adb7cf9c47b75e..3563cab8bd8cf91fc90548d9e343008618aa966d 100644 --- a/src/hb-ot-kern-table.hh +++ b/src/hb-ot-kern-table.hh @@ -86,21 +86,26 @@ struct KernSubTableFormat3 } protected: - KernSubTableHeader header; - HBUINT16 glyphCount; /* The number of glyphs in this font. */ - HBUINT8 kernValueCount; /* The number of kerning values. */ - HBUINT8 leftClassCount; /* The number of left-hand classes. */ - HBUINT8 rightClassCount;/* The number of right-hand classes. */ - HBUINT8 flags; /* Set to zero (reserved for future use). */ - UnsizedArrayOf kernValueZ; /* The kerning values. - * Length kernValueCount. */ + KernSubTableHeader + header; + HBUINT16 glyphCount; /* The number of glyphs in this font. */ + HBUINT8 kernValueCount; /* The number of kerning values. */ + HBUINT8 leftClassCount; /* The number of left-hand classes. */ + HBUINT8 rightClassCount;/* The number of right-hand classes. */ + HBUINT8 flags; /* Set to zero (reserved for future use). */ + UnsizedArrayOf + kernValueZ; /* The kerning values. + * Length kernValueCount. */ #if 0 - UnsizedArrayOfleftClass; /* The left-hand classes. - * Length glyphCount. */ - UnsizedArrayOfrightClass; /* The right-hand classes. - * Length glyphCount. */ - UnsizedArrayOfkernIndex; /* The indices into the kernValue array. - * Length leftClassCount * rightClassCount */ + UnsizedArrayOf + leftClass; /* The left-hand classes. + * Length glyphCount. */ + UnsizedArrayOf + rightClass; /* The right-hand classes. + * Length glyphCount. */ + UnsizedArrayOfkernIndex; + /* The indices into the kernValue array. + * Length leftClassCount * rightClassCount */ #endif public: DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ); @@ -167,8 +172,8 @@ struct KernOTSubTableHeader static constexpr bool apple = false; typedef AAT::ObsoleteTypes Types; - unsigned int tuple_count () const { return 0; } - bool is_horizontal () const { return (coverage & Horizontal); } + unsigned tuple_count () const { return 0; } + bool is_horizontal () const { return (coverage & Horizontal); } enum Coverage { @@ -222,8 +227,8 @@ struct KernAATSubTableHeader static constexpr bool apple = true; typedef AAT::ObsoleteTypes Types; - unsigned int tuple_count () const { return 0; } - bool is_horizontal () const { return !(coverage & Vertical); } + unsigned tuple_count () const { return 0; } + bool is_horizontal () const { return !(coverage & Vertical); } enum Coverage { @@ -246,8 +251,8 @@ struct KernAATSubTableHeader HBUINT8 coverage; /* Coverage bits. */ HBUINT8 format; /* Subtable format. */ HBUINT16 tupleIndex; /* The tuple index (used for variations fonts). - * This value specifies which tuple this subtable covers. - * Note: We don't implement. */ + * This value specifies which tuple this subtable covers. + * Note: We don't implement. */ public: DEFINE_SIZE_STATIC (8); }; @@ -275,8 +280,8 @@ struct kern { static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; - bool has_data () const { return u.version32; } - unsigned int get_type () const { return u.major; } + bool has_data () const { return u.version32; } + unsigned get_type () const { return u.major; } bool has_state_machine () const { diff --git a/src/hb-ot-layout-base-table.hh b/src/hb-ot-layout-base-table.hh index 7c00a1313ebec691a3135a6e3bfc17f98c2d4917..492947751e6bbf3483affd91f68cd5b703ba3598 100644 --- a/src/hb-ot-layout-base-table.hh +++ b/src/hb-ot-layout-base-table.hh @@ -73,7 +73,7 @@ struct BaseCoordFormat2 protected: HBUINT16 format; /* Format identifier--format = 2 */ FWORD coordinate; /* X or Y value, in design units */ - GlyphID referenceGlyph; /* Glyph ID of control glyph */ + HBGlyphID referenceGlyph; /* Glyph ID of control glyph */ HBUINT16 coordPoint; /* Index of contour point on the * reference glyph */ public: @@ -103,7 +103,7 @@ struct BaseCoordFormat3 protected: HBUINT16 format; /* Format identifier--format = 3 */ FWORD coordinate; /* X or Y value, in design units */ - OffsetTo + Offset16To deviceTable; /* Offset to Device table for X or * Y value, from beginning of * BaseCoord table (may be NULL). */ @@ -173,11 +173,11 @@ struct FeatMinMaxRecord protected: Tag tag; /* 4-byte feature identification tag--must * match feature tag in FeatureList */ - OffsetTo + Offset16To minCoord; /* Offset to BaseCoord table that defines * the minimum extent value, from beginning * of MinMax table (may be NULL) */ - OffsetTo + Offset16To maxCoord; /* Offset to BaseCoord table that defines * the maximum extent value, from beginning * of MinMax table (may be NULL) */ @@ -212,15 +212,15 @@ struct MinMax } protected: - OffsetTo + Offset16To minCoord; /* Offset to BaseCoord table that defines * minimum extent value, from the beginning * of MinMax table (may be NULL) */ - OffsetTo + Offset16To maxCoord; /* Offset to BaseCoord table that defines * maximum extent value, from the beginning * of MinMax table (may be NULL) */ - SortedArrayOf + SortedArray16Of featMinMaxRecords; /* Array of FeatMinMaxRecords, in alphabetical * order by featureTableTag */ @@ -247,7 +247,7 @@ struct BaseValues Index defaultIndex; /* Index number of default baseline for this * script — equals index position of baseline tag * in baselineTags array of the BaseTagList */ - OffsetArrayOf + Array16OfOffset16To baseCoords; /* Number of BaseCoord tables defined — should equal * baseTagCount in the BaseTagList * @@ -275,7 +275,7 @@ struct BaseLangSysRecord protected: Tag baseLangSysTag; /* 4-byte language system identification tag */ - OffsetTo + Offset16To minMax; /* Offset to MinMax table, from beginning * of BaseScript table */ public: @@ -305,13 +305,13 @@ struct BaseScript } protected: - OffsetTo + Offset16To baseValues; /* Offset to BaseValues table, from beginning * of BaseScript table (may be NULL) */ - OffsetTo + Offset16To defaultMinMax; /* Offset to MinMax table, from beginning of * BaseScript table (may be NULL) */ - SortedArrayOf + SortedArray16Of baseLangSysRecords; /* Number of BaseLangSysRecords * defined — may be zero (0) */ @@ -339,7 +339,7 @@ struct BaseScriptRecord protected: Tag baseScriptTag; /* 4-byte script identification tag */ - OffsetTo + Offset16To baseScript; /* Offset to BaseScript table, from beginning * of BaseScriptList */ @@ -364,7 +364,7 @@ struct BaseScriptList } protected: - SortedArrayOf + SortedArray16Of baseScriptRecords; public: @@ -379,12 +379,20 @@ struct Axis const BaseCoord **coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (!base_script.has_data ()) return false; + if (!base_script.has_data ()) + { + *coord = nullptr; + return false; + } if (likely (coord)) { unsigned int tag_index = 0; - (this+baseTagList).bfind (baseline_tag, &tag_index); + if (!(this+baseTagList).bfind (baseline_tag, &tag_index)) + { + *coord = nullptr; + return false; + } *coord = &base_script.get_base_coord (tag_index); } @@ -398,7 +406,11 @@ struct Axis const BaseCoord **max_coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (!base_script.has_data ()) return false; + if (!base_script.has_data ()) + { + *min_coord = *max_coord = nullptr; + return false; + } base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord); @@ -414,12 +426,12 @@ struct Axis } protected: - OffsetTo> + Offset16To> baseTagList; /* Offset to BaseTagList table, from beginning * of Axis table (may be NULL) * Array of 4-byte baseline identification tags — must * be in alphabetical order */ - OffsetTo + Offset16To baseScriptList; /* Offset to BaseScriptList table, from beginning * of Axis table * Array of BaseScriptRecords, in alphabetical order @@ -489,11 +501,11 @@ struct BASE protected: FixedVersion<>version; /* Version of the BASE table */ - OffsetTohAxis; /* Offset to horizontal Axis table, from beginning + Offset16TohAxis; /* Offset to horizontal Axis table, from beginning * of BASE table (may be NULL) */ - OffsetTovAxis; /* Offset to vertical Axis table, from beginning + Offset16TovAxis; /* Offset to vertical Axis table, from beginning * of BASE table (may be NULL) */ - LOffsetTo + Offset32To varStore; /* Offset to the table of Item Variation * Store--from beginning of BASE * header (may be NULL). Introduced diff --git a/src/hb-ot-layout-common.hh b/src/hb-ot-layout-common.hh index 0866760bdc7ef9ee79cb6f84f4a1e29c6dfeb9ad..0fc66d2cbd116de43097360cbbb7c3775ca8e528 100644 --- a/src/hb-ot-layout-common.hh +++ b/src/hb-ot-layout-common.hh @@ -33,6 +33,7 @@ #include "hb-ot-layout.hh" #include "hb-open-type.hh" #include "hb-set.hh" +#include "hb-bimap.hh" #ifndef HB_MAX_NESTING_LEVEL @@ -59,6 +60,18 @@ #define HB_MAX_LANGSYS 2000 #endif +#ifndef HB_MAX_FEATURES +#define HB_MAX_FEATURES 750 +#endif + +#ifndef HB_MAX_FEATURE_INDICES +#define HB_MAX_FEATURE_INDICES 1500 +#endif + +#ifndef HB_MAX_LOOKUP_INDICES +#define HB_MAX_LOOKUP_INDICES 20000 +#endif + namespace OT { @@ -66,6 +79,273 @@ namespace OT { #define NOT_COVERED ((unsigned int) -1) +template +static inline void Coverage_serialize (hb_serialize_context_t *c, + Iterator it); + +template +static inline void ClassDef_serialize (hb_serialize_context_t *c, + Iterator it); + +static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, + const hb_map_t &gid_klass_map, + hb_sorted_vector_t &glyphs, + const hb_set_t &klasses, + bool use_class_zero, + hb_map_t *klass_map /*INOUT*/); + + +struct hb_prune_langsys_context_t +{ + hb_prune_langsys_context_t (const void *table_, + hb_hashmap_t *script_langsys_map_, + const hb_map_t *duplicate_feature_map_, + hb_set_t *new_collected_feature_indexes_) + :table (table_), + script_langsys_map (script_langsys_map_), + duplicate_feature_map (duplicate_feature_map_), + new_feature_indexes (new_collected_feature_indexes_), + script_count (0),langsys_count (0) {} + + bool visitedScript (const void *s) + { + if (script_count++ > HB_MAX_SCRIPTS) + return true; + + return visited (s, visited_script); + } + + bool visitedLangsys (const void *l) + { + if (langsys_count++ > HB_MAX_LANGSYS) + return true; + + return visited (l, visited_langsys); + } + + private: + template + bool visited (const T *p, hb_set_t &visited_set) + { + hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table); + if (visited_set.has (delta)) + return true; + + visited_set.add (delta); + return false; + } + + public: + const void *table; + hb_hashmap_t *script_langsys_map; + const hb_map_t *duplicate_feature_map; + hb_set_t *new_feature_indexes; + + private: + hb_set_t visited_script; + hb_set_t visited_langsys; + unsigned script_count; + unsigned langsys_count; +}; + +struct hb_subset_layout_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "SUBSET_LAYOUT"; } + static return_t default_return_value () { return hb_empty_t (); } + + bool visitScript () + { + return script_count++ < HB_MAX_SCRIPTS; + } + + bool visitLangSys () + { + return langsys_count++ < HB_MAX_LANGSYS; + } + + bool visitFeatureIndex (int count) + { + feature_index_count += count; + return feature_index_count < HB_MAX_FEATURE_INDICES; + } + + bool visitLookupIndex() + { + lookup_index_count++; + return lookup_index_count < HB_MAX_LOOKUP_INDICES; + } + + hb_subset_context_t *subset_context; + const hb_tag_t table_tag; + const hb_map_t *lookup_index_map; + const hb_hashmap_t *script_langsys_map; + const hb_map_t *feature_index_map; + unsigned cur_script_index; + + hb_subset_layout_context_t (hb_subset_context_t *c_, + hb_tag_t tag_, + hb_map_t *lookup_map_, + hb_hashmap_t *script_langsys_map_, + hb_map_t *feature_index_map_) : + subset_context (c_), + table_tag (tag_), + lookup_index_map (lookup_map_), + script_langsys_map (script_langsys_map_), + feature_index_map (feature_index_map_), + cur_script_index (0xFFFFu), + script_count (0), + langsys_count (0), + feature_index_count (0), + lookup_index_count (0) + {} + + private: + unsigned script_count; + unsigned langsys_count; + unsigned feature_index_count; + unsigned lookup_index_count; +}; + +struct hb_collect_variation_indices_context_t : + hb_dispatch_context_t +{ + template + return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + hb_set_t *layout_variation_indices; + const hb_set_t *glyph_set; + const hb_map_t *gpos_lookups; + + hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, + const hb_set_t *glyph_set_, + const hb_map_t *gpos_lookups_) : + layout_variation_indices (layout_variation_indices_), + glyph_set (glyph_set_), + gpos_lookups (gpos_lookups_) {} +}; + +template +struct subset_offset_array_t +{ + subset_offset_array_t (hb_subset_context_t *subset_context_, + OutputArray& out_, + const void *base_) : subset_context (subset_context_), + out (out_), base (base_) {} + + template + bool operator () (T&& offset) + { + auto *o = out.serialize_append (subset_context->serializer); + if (unlikely (!o)) return false; + auto snap = subset_context->serializer->snapshot (); + bool ret = o->serialize_subset (subset_context, offset, base); + if (!ret) + { + out.pop (); + subset_context->serializer->revert (snap); + } + return ret; + } + + private: + hb_subset_context_t *subset_context; + OutputArray &out; + const void *base; +}; + + +template +struct subset_offset_array_arg_t +{ + subset_offset_array_arg_t (hb_subset_context_t *subset_context_, + OutputArray& out_, + const void *base_, + Arg &&arg_) : subset_context (subset_context_), out (out_), + base (base_), arg (arg_) {} + + template + bool operator () (T&& offset) + { + auto *o = out.serialize_append (subset_context->serializer); + if (unlikely (!o)) return false; + auto snap = subset_context->serializer->snapshot (); + bool ret = o->serialize_subset (subset_context, offset, base, arg); + if (!ret) + { + out.pop (); + subset_context->serializer->revert (snap); + } + return ret; + } + + private: + hb_subset_context_t *subset_context; + OutputArray &out; + const void *base; + Arg &&arg; +}; + +/* + * Helper to subset an array of offsets. Subsets the thing pointed to by each offset + * and discards the offset in the array if the subset operation results in an empty + * thing. + */ +struct +{ + template + subset_offset_array_t + operator () (hb_subset_context_t *subset_context, OutputArray& out, + const void *base) const + { return subset_offset_array_t (subset_context, out, base); } + + /* Variant with one extra argument passed to serialize_subset */ + template + subset_offset_array_arg_t + operator () (hb_subset_context_t *subset_context, OutputArray& out, + const void *base, Arg &&arg) const + { return subset_offset_array_arg_t (subset_context, out, base, arg); } +} +HB_FUNCOBJ (subset_offset_array); + +template +struct subset_record_array_t +{ + subset_record_array_t (hb_subset_layout_context_t *c_, OutputArray* out_, + const void *base_) : subset_layout_context (c_), + out (out_), base (base_) {} + + template + void + operator () (T&& record) + { + auto snap = subset_layout_context->subset_context->serializer->snapshot (); + bool ret = record.subset (subset_layout_context, base); + if (!ret) subset_layout_context->subset_context->serializer->revert (snap); + else out->len++; + } + + private: + hb_subset_layout_context_t *subset_layout_context; + OutputArray *out; + const void *base; +}; + +/* + * Helper to subset a RecordList/record array. Subsets each Record in the array and + * discards the record if the subset operation returns false. + */ +struct +{ + template + subset_record_array_t + operator () (hb_subset_layout_context_t *c, OutputArray* out, + const void *base) const + { return subset_record_array_t (c, out, base); } +} +HB_FUNCOBJ (subset_record_array); + /* * * OpenType Layout Common Table Formats @@ -87,6 +367,15 @@ struct Record { int cmp (hb_tag_t a) const { return tag.cmp (a); } + bool subset (hb_subset_layout_context_t *c, const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->subset_context->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag); + return_trace (ret); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -95,7 +384,7 @@ struct Record } Tag tag; /* 4-byte Tag identifier */ - OffsetTo + Offset16To offset; /* Offset from beginning of object holding * the Record */ public: @@ -103,11 +392,11 @@ struct Record }; template -struct RecordArrayOf : SortedArrayOf> +struct RecordArrayOf : SortedArray16Of> { - const OffsetTo& get_offset (unsigned int i) const + const Offset16To& get_offset (unsigned int i) const { return (*this)[i].offset; } - OffsetTo& get_offset (unsigned int i) + Offset16To& get_offset (unsigned int i) { return (*this)[i].offset; } const Tag& get_tag (unsigned int i) const { return (*this)[i].tag; } @@ -115,11 +404,12 @@ struct RecordArrayOf : SortedArrayOf> unsigned int *record_count /* IN/OUT */, hb_tag_t *record_tags /* OUT */) const { - if (record_count) { - const Record *arr = this->sub_array (start_offset, record_count); - unsigned int count = *record_count; - for (unsigned int i = 0; i < count; i++) - record_tags[i] = arr[i].tag; + if (record_count) + { + + this->sub_array (start_offset, record_count) + | hb_map (&Record::tag) + | hb_sink (hb_array (record_tags, *record_count)) + ; } return this->len; } @@ -135,14 +425,16 @@ struct RecordListOf : RecordArrayOf const Type& operator [] (unsigned int i) const { return this+this->get_offset (i); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const { TRACE_SUBSET (this); - auto *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - unsigned int count = this->len; - for (unsigned int i = 0; i < count; i++) - out->get_offset (i).serialize_subset (c, this->get_offset (i), this, out); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + this->iter () + | hb_apply (subset_record_array (l, out, this)) + ; return_trace (true); } @@ -153,11 +445,55 @@ struct RecordListOf : RecordArrayOf } }; +struct Feature; + +struct RecordListOfFeature : RecordListOf +{ + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + unsigned count = this->len; + + hb_zip (*this, hb_range (count)) + | hb_filter (l->feature_index_map, hb_second) + | hb_map (hb_first) + | hb_apply (subset_record_array (l, out, this)) + ; + return_trace (true); + } +}; + +struct Script; +struct RecordListOfScript : RecordListOf - * File-Date: 2019-04-03 + * + * File-Date: 2021-03-05 */ #ifndef HB_OT_TAG_TABLE_HH @@ -19,14 +19,18 @@ static const LangTag ot_languages[] = { {"aao", HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ {"aat", HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ + {"aba", HB_TAG_NONE }, /* Abé != Abaza */ {"abh", HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ + {"abs", HB_TAG('C','P','P',' ')}, /* Ambonese Malay -> Creoles */ {"abv", HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ {"acf", HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ + {"acf", HB_TAG('C','P','P',' ')}, /* Saint Lucian Creole French -> Creoles */ /*{"ach", HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ {"acm", HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ {"acq", HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ -/*{"acr", HB_TAG('A','C','R',' ')},*/ /* Achi */ + {"acr", HB_TAG('A','C','R',' ')}, /* Achi */ + {"acr", HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */ {"acw", HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ {"acx", HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ {"acy", HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ @@ -38,15 +42,21 @@ static const LangTag ot_languages[] = { {"aec", HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ {"afb", HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ + {"afk", HB_TAG_NONE }, /* Nanubae != Afrikaans */ + {"afs", HB_TAG('C','P','P',' ')}, /* Afro-Seminole Creole -> Creoles */ + {"agu", HB_TAG('M','Y','N',' ')}, /* Aguacateco -> Mayan */ + {"agw", HB_TAG_NONE }, /* Kahua != Agaw */ {"ahg", HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ {"aht", HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ + {"aig", HB_TAG('C','P','P',' ')}, /* Antigua and Barbuda Creole English -> Creoles */ {"aii", HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ {"aii", HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ /*{"aio", HB_TAG('A','I','O',' ')},*/ /* Aiton */ {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ {"ajp", HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ {"ak", HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ - {"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] -> Twi */ + {"akb", HB_TAG('A','K','B',' ')}, /* Batak Angkola */ + {"akb", HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */ {"aln", HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ {"als", HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ /*{"alt", HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ @@ -55,6 +65,8 @@ static const LangTag ot_languages[] = { {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ /*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {"aoa", HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ + {"apa", HB_TAG('A','T','H',' ')}, /* Apache [family] -> Athapaskan */ {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ @@ -64,16 +76,20 @@ static const LangTag ot_languages[] = { {"apw", HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ + {"ari", HB_TAG_NONE }, /* Arikara != Aari */ + {"ark", HB_TAG_NONE }, /* Arikapú != Rakhine */ {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ {"arq", HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ {"ars", HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ + {"ary", HB_TAG('A','R','A',' ')}, /* Moroccan Arabic -> Arabic */ {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ /*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */ /*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [family] -> Athapaskan */ {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ + {"auj", HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ {"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ {"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ {"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ @@ -86,17 +102,29 @@ static const LangTag ot_languages[] = { {"ayp", HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ {"ayr", HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ -/*{"azb", HB_TAG('A','Z','B',' ')},*/ /* South Azerbaijani -> Torki */ + {"azb", HB_TAG('A','Z','B',' ')}, /* South Azerbaijani -> Torki */ + {"azb", HB_TAG('A','Z','E',' ')}, /* South Azerbaijani -> Azerbaijani */ + {"azd", HB_TAG('N','A','H',' ')}, /* Eastern Durango Nahuatl -> Nahuatl */ {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ + {"azn", HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ + {"azz", HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ {"bad", HB_TAG('B','A','D','0')}, /* Banda [family] */ + {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */ + {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ /*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */ /*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */ -/*{"bbc", HB_TAG('B','B','C',' ')},*/ /* Batak Toba */ - {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic -> Arabic */ + {"bau", HB_TAG_NONE }, /* Bada (Nigeria) != Baulé */ + {"bbc", HB_TAG('B','B','C',' ')}, /* Batak Toba */ + {"bbc", HB_TAG('B','T','K',' ')}, /* Batak Toba -> Batak */ + {"bbj", HB_TAG('B','M','L',' ')}, /* Ghomálá' -> Bamileke */ + {"bbp", HB_TAG('B','A','D','0')}, /* West Central Banda -> Banda */ + {"bbr", HB_TAG_NONE }, /* Girawa != Berber */ + {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ {"bcc", HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ + {"bch", HB_TAG_NONE }, /* Bariai != Bench */ {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ @@ -107,6 +135,8 @@ static const LangTag ot_languages[] = { {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ /*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ {"ber", HB_TAG('B','B','R',' ')}, /* Berber [family] */ + {"bew", HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ + {"bfl", HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ {"bfu", HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ @@ -115,7 +145,8 @@ static const LangTag ot_languages[] = { /*{"bgc", HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ {"bgn", HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ {"bgp", HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ -/*{"bgq", HB_TAG('B','G','Q',' ')},*/ /* Bagri */ + {"bgq", HB_TAG('B','G','Q',' ')}, /* Bagri */ + {"bgq", HB_TAG('R','A','J',' ')}, /* Bagri -> Rajasthani */ {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ /*{"bhi", HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ @@ -123,58 +154,108 @@ static const LangTag ot_languages[] = { /*{"bho", HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ {"bhr", HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ + {"bi", HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */ /*{"bik", HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ + {"bil", HB_TAG_NONE }, /* Bile != Bilen */ {"bin", HB_TAG('E','D','O',' ')}, /* Edo */ + {"biu", HB_TAG('Q','I','N',' ')}, /* Biete -> Chin */ /*{"bjj", HB_TAG('B','J','J',' ')},*/ /* Kanauji */ {"bjn", HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ + {"bjo", HB_TAG('B','A','D','0')}, /* Mid-Southern Banda -> Banda */ {"bjq", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {"bjs", HB_TAG('C','P','P',' ')}, /* Bajan -> Creoles */ {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ + {"bkf", HB_TAG_NONE }, /* Beeke != Blackfoot */ + {"bko", HB_TAG('B','M','L',' ')}, /* Kwa' -> Bamileke */ {"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ -/*{"blk", HB_TAG('B','L','K',' ')},*/ /* Pa’o Karen */ + {"blg", HB_TAG('I','B','A',' ')}, /* Balau (retired code) -> Iban */ + {"bli", HB_TAG_NONE }, /* Bolia != Baluchi */ + {"blk", HB_TAG('B','L','K',' ')}, /* Pa’o Karen */ + {"blk", HB_TAG('K','R','N',' ')}, /* Pa'o Karen -> Karen */ {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ + {"blt", HB_TAG_NONE }, /* Tai Dam != Balti */ {"bm", HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ + {"bmb", HB_TAG_NONE }, /* Bembe != Bambara (Bamanankan) */ + {"bml", HB_TAG_NONE }, /* Bomboli != Bamileke */ {"bmm", HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ + {"bpd", HB_TAG('B','A','D','0')}, /* Banda-Banda -> Banda */ + {"bpl", HB_TAG('C','P','P',' ')}, /* Broome Pearling Lugger Pidgin -> Creoles */ + {"bpq", HB_TAG('C','P','P',' ')}, /* Banda Malay -> Creoles */ /*{"bpy", HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ + {"bqk", HB_TAG('B','A','D','0')}, /* Banda-Mbrès -> Banda */ {"br", HB_TAG('B','R','E',' ')}, /* Breton */ {"bra", HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ + {"brc", HB_TAG('C','P','P',' ')}, /* Berbice Creole Dutch -> Creoles */ /*{"brh", HB_TAG('B','R','H',' ')},*/ /* Brahui */ + {"bri", HB_TAG_NONE }, /* Mokpwe != Braj Bhasha */ + {"brm", HB_TAG_NONE }, /* Barambu != Burmese */ /*{"brx", HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ + {"bsh", HB_TAG_NONE }, /* Kati != Bashkir */ /*{"bsk", HB_TAG('B','S','K',' ')},*/ /* Burushaski */ {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ + {"btd", HB_TAG('B','T','D',' ')}, /* Batak Dairi (Pakpak) */ + {"btd", HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ + {"bti", HB_TAG_NONE }, /* Burate != Beti */ {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ +/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [family] */ + {"btm", HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ + {"btm", HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ -/*{"bts", HB_TAG('B','T','S',' ')},*/ /* Batak Simalungun */ + {"bts", HB_TAG('B','T','S',' ')}, /* Batak Simalungun */ + {"bts", HB_TAG('B','T','K',' ')}, /* Batak Simalungun -> Batak */ + {"btx", HB_TAG('B','T','X',' ')}, /* Batak Karo */ + {"btx", HB_TAG('B','T','K',' ')}, /* Batak Karo -> Batak */ + {"btz", HB_TAG('B','T','Z',' ')}, /* Batak Alas-Kluet */ + {"btz", HB_TAG('B','T','K',' ')}, /* Batak Alas-Kluet -> Batak */ /*{"bug", HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ {"bum", HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ {"bve", HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ {"bvu", HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ + {"bwe", HB_TAG('K','R','N',' ')}, /* Bwe Karen -> Karen */ {"bxk", HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ + {"bxo", HB_TAG('C','P','P',' ')}, /* Barikanchi -> Creoles */ {"bxp", HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ {"bxr", HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ {"byn", HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ -/*{"byv", HB_TAG('B','Y','V',' ')},*/ /* Medumba */ + {"byv", HB_TAG('B','Y','V',' ')}, /* Medumba */ + {"byv", HB_TAG('B','M','L',' ')}, /* Medumba -> Bamileke */ {"bzc", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {"bzj", HB_TAG('C','P','P',' ')}, /* Belize Kriol English -> Creoles */ + {"bzk", HB_TAG('C','P','P',' ')}, /* Nicaragua Creole English -> Creoles */ {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ + {"caa", HB_TAG('M','Y','N',' ')}, /* Chortí -> Mayan */ + {"cac", HB_TAG('M','Y','N',' ')}, /* Chuj -> Mayan */ {"caf", HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ {"caf", HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ -/*{"cak", HB_TAG('C','A','K',' ')},*/ /* Kaqchikel */ -/*{"cbk", HB_TAG('C','B','K',' ')},*/ /* Chavacano -> Zamboanga Chavacano */ + {"cak", HB_TAG('C','A','K',' ')}, /* Kaqchikel */ + {"cak", HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */ + {"cbk", HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */ + {"cbk", HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */ {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ + {"ccl", HB_TAG('C','P','P',' ')}, /* Cutchi-Swahili -> Creoles */ + {"ccm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Malay -> Creoles */ {"cco", HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ {"ccq", HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ - {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese Simplified */ + {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese, Simplified */ {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ /*{"ceb", HB_TAG('C','E','B',' ')},*/ /* Cebuano */ + {"cek", HB_TAG('Q','I','N',' ')}, /* Eastern Khumi Chin -> Chin */ + {"cey", HB_TAG('Q','I','N',' ')}, /* Ekai Chin -> Chin */ {"cfm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ + {"cfm", HB_TAG('Q','I','N',' ')}, /* Falam Chin -> Chin */ /*{"cgg", HB_TAG('C','G','G',' ')},*/ /* Chiga */ {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ + {"chf", HB_TAG('M','Y','N',' ')}, /* Tabasco Chontal -> Mayan */ + {"chg", HB_TAG_NONE }, /* Chagatai != Chaha Gurage */ + {"chh", HB_TAG_NONE }, /* Chinook != Chattisgarhi */ {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ + {"chn", HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ /*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */ {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ {"chp", HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ @@ -186,57 +267,85 @@ static const LangTag ot_languages[] = { {"ciw", HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ /*{"cja", HB_TAG('C','J','A',' ')},*/ /* Western Cham */ /*{"cjm", HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ - {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese Simplified */ + {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese, Simplified */ {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ + {"ckn", HB_TAG('Q','I','N',' ')}, /* Kaang Chin -> Chin */ + {"cks", HB_TAG('C','P','P',' ')}, /* Tayo -> Creoles */ {"ckt", HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ + {"ckz", HB_TAG('M','Y','N',' ')}, /* Cakchiquel-Quiché Mixed Language -> Mayan */ {"clc", HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ {"cle", HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ - {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese Simplified */ + {"clj", HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */ + {"clt", HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */ + {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */ {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ {"cnl", HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ + {"cnp", HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese, Simplified */ + {"cnr", HB_TAG('S','R','B',' ')}, /* Montenegrin -> Serbian */ {"cnt", HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ + {"cnu", HB_TAG('B','B','R',' ')}, /* Chenoua -> Berber */ {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ {"co", HB_TAG('C','O','S',' ')}, /* Corsican */ {"coa", HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ + {"cob", HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */ /*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */ {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [family] -> Creoles */ {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [family] -> Creoles */ + {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ /*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [family] -> Creoles */ - {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese Simplified */ + {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {"cqu", HB_TAG('Q','U','Z',' ')}, /* Chilean Quechua (retired code) -> Quechua */ {"cr", HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ - {"cr", HB_TAG('Y','C','R',' ')}, /* Cree [macrolanguage] -> Y-Cree */ {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ + {"cri", HB_TAG('C','P','P',' ')}, /* Sãotomense -> Creoles */ {"crj", HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ + {"crj", HB_TAG('Y','C','R',' ')}, /* Southern East Cree -> Y-Cree */ + {"crj", HB_TAG('C','R','E',' ')}, /* Southern East Cree -> Cree */ {"crk", HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ + {"crk", HB_TAG('Y','C','R',' ')}, /* Plains Cree -> Y-Cree */ + {"crk", HB_TAG('C','R','E',' ')}, /* Plains Cree -> Cree */ {"crl", HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ + {"crl", HB_TAG('Y','C','R',' ')}, /* Northern East Cree -> Y-Cree */ + {"crl", HB_TAG('C','R','E',' ')}, /* Northern East Cree -> Cree */ {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ + {"crm", HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [family] -> Creoles */ + {"crr", HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ + {"crs", HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ + {"crt", HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ {"crx", HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ {"csa", HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ /*{"csb", HB_TAG('C','S','B',' ')},*/ /* Kashubian */ {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ + {"csj", HB_TAG('Q','I','N',' ')}, /* Songlai Chin -> Chin */ + {"csl", HB_TAG_NONE }, /* Chinese Sign Language != Church Slavonic */ {"cso", HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ + {"csp", HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese, Simplified */ + {"csv", HB_TAG('Q','I','N',' ')}, /* Sumtu Chin -> Chin */ {"csw", HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ {"csw", HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ + {"csw", HB_TAG('C','R','E',' ')}, /* Swampy Cree -> Cree */ {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ {"ctc", HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ {"cte", HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ /*{"ctg", HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ + {"cth", HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */ {"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ + {"ctu", HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */ {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */ {"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ /*{"cuk", HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ @@ -244,56 +353,73 @@ static const LangTag ot_languages[] = { {"cvn", HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ {"cwd", HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ + {"cwd", HB_TAG('C','R','E',' ')}, /* Woods Cree -> Cree */ {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ - {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese Simplified */ - {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese Simplified */ + {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese, Simplified */ + {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese, Simplified */ {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ {"da", HB_TAG('D','A','N',' ')}, /* Danish */ +/*{"dag", HB_TAG('D','A','G',' ')},*/ /* Dagbani */ {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ /*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */ /*{"dax", HB_TAG('D','A','X',' ')},*/ /* Dayi */ + {"dcr", HB_TAG('C','P','P',' ')}, /* Negerhollands -> Creoles */ {"de", HB_TAG('D','E','U',' ')}, /* German */ {"den", HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ {"den", HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ -/*{"dgo", HB_TAG('D','G','O',' ')},*/ /* Dogri */ + {"dep", HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */ + {"dgo", HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */ + {"dgo", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */ {"dgr", HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ /*{"dhg", HB_TAG('D','H','G',' ')},*/ /* Dhangu */ + {"dhv", HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */ {"dib", HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ {"dik", HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ {"dip", HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ -/*{"diq", HB_TAG('D','I','Q',' ')},*/ /* Dimli */ + {"diq", HB_TAG('D','I','Q',' ')}, /* Dimli */ + {"diq", HB_TAG('Z','Z','A',' ')}, /* Dimli -> Zazaki */ {"diw", HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ + {"djk", HB_TAG('C','P','P',' ')}, /* Eastern Maroon Creole -> Creoles */ {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ {"dks", HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ /*{"dnj", HB_TAG('D','N','J',' ')},*/ /* Dan */ - {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */ + {"dnk", HB_TAG_NONE }, /* Dengka != Dinka */ + {"doi", HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) [macrolanguage] */ {"drh", HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ + {"dri", HB_TAG_NONE }, /* C'Lela != Dari */ {"drw", HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ + {"drw", HB_TAG('F','A','R',' ')}, /* Darwazi (retired code) -> Persian */ {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ {"dty", HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ /*{"duj", HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ + {"dun", HB_TAG_NONE }, /* Dusun Deyah != Dungan */ {"dup", HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ {"dv", HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ {"dv", HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {"dwk", HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ {"dwu", HB_TAG('D','U','J',' ')}, /* Dhuwal */ {"dwy", HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ {"dyu", HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ + {"dzn", HB_TAG_NONE }, /* Dzando != Dzongkha */ + {"ecr", HB_TAG_NONE }, /* Eteocretan != Eastern Cree */ {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ /*{"efi", HB_TAG('E','F','I',' ')},*/ /* Efik */ {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ + {"eky", HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */ {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ {"emk", HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ + {"emy", HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */ {"en", HB_TAG('E','N','G',' ')}, /* English */ {"enb", HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ - {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets -> Forest Nenets */ - {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets -> Tundra Nenets */ + {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets */ + {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets */ {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ {"esg", HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ @@ -303,13 +429,18 @@ static const LangTag ot_languages[] = { {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ + {"euq", HB_TAG_NONE }, /* Basque [family] != Basque */ {"eve", HB_TAG('E','V','N',' ')}, /* Even */ {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ {"eyo", HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ + {"fab", HB_TAG('C','P','P',' ')}, /* Fa d'Ambu -> Creoles */ {"fan", HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ -/*{"fat", HB_TAG('F','A','T',' ')},*/ /* Fanti */ + {"fan", HB_TAG('B','T','I',' ')}, /* Fang (Equatorial Guinea) -> Beti */ + {"far", HB_TAG_NONE }, /* Fataleka != Persian */ + {"fat", HB_TAG('F','A','T',' ')}, /* Fanti */ + {"fat", HB_TAG('A','K','A',' ')}, /* Fanti -> Akan */ {"fbl", HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ {"ffm", HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ @@ -318,9 +449,13 @@ static const LangTag ot_languages[] = { {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ {"flm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ {"flm", HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ -/*{"fmp", HB_TAG('F','M','P',' ')},*/ /* Fe’fe’ */ + {"fmp", HB_TAG('F','M','P',' ')}, /* Fe’fe’ */ + {"fmp", HB_TAG('B','M','L',' ')}, /* Fe'fe' -> Bamileke */ + {"fng", HB_TAG('C','P','P',' ')}, /* Fanagalo -> Creoles */ {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ /*{"fon", HB_TAG('F','O','N',' ')},*/ /* Fon */ + {"fos", HB_TAG_NONE }, /* Siraya != Faroese */ + {"fpe", HB_TAG('C','P','P',' ')}, /* Fernando Po Creole English -> Creoles */ {"fr", HB_TAG('F','R','A',' ')}, /* French */ /*{"frc", HB_TAG('F','R','C',' ')},*/ /* Cajun French */ /*{"frp", HB_TAG('F','R','P',' ')},*/ /* Arpitan */ @@ -328,60 +463,89 @@ static const LangTag ot_languages[] = { {"fuc", HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ {"fue", HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ {"fuf", HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ + {"fuf", HB_TAG('F','U','L',' ')}, /* Pular -> Fulah */ {"fuh", HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ {"fui", HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ {"fuq", HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ -/*{"fuv", HB_TAG('F','U','V',' ')},*/ /* Nigerian Fulfulde */ + {"fuv", HB_TAG('F','U','V',' ')}, /* Nigerian Fulfulde */ + {"fuv", HB_TAG('F','U','L',' ')}, /* Nigerian Fulfulde -> Fulah */ {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ + {"gac", HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */ + {"gad", HB_TAG_NONE }, /* Gaddang != Ga */ + {"gae", HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */ /*{"gag", HB_TAG('G','A','G',' ')},*/ /* Gagauz */ - {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese Simplified */ + {"gal", HB_TAG_NONE }, /* Galolen != Galician */ + {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */ + {"gar", HB_TAG_NONE }, /* Galeya != Garshuni */ + {"gaw", HB_TAG_NONE }, /* Nobonob != Garhwali */ {"gax", HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ {"gaz", HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ {"gce", HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ + {"gcf", HB_TAG('C','P','P',' ')}, /* Guadeloupean Creole French -> Creoles */ + {"gcl", HB_TAG('C','P','P',' ')}, /* Grenadian Creole English -> Creoles */ + {"gcr", HB_TAG('C','P','P',' ')}, /* Guianese Creole French -> Creoles */ {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ {"gda", HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ /*{"gez", HB_TAG('G','E','Z',' ')},*/ /* Geez */ {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ + {"gha", HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */ + {"ghk", HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */ + {"gho", HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */ + {"gib", HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */ /*{"gih", HB_TAG('G','I','H',' ')},*/ /* Githabul */ {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ {"gju", HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ -/*{"gkp", HB_TAG('G','K','P',' ')},*/ /* Guinea Kpelle -> Kpelle (Guinea) */ + {"gkp", HB_TAG('G','K','P',' ')}, /* Guinea Kpelle -> Kpelle (Guinea) */ + {"gkp", HB_TAG('K','P','L',' ')}, /* Guinea Kpelle -> Kpelle */ {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ /*{"glk", HB_TAG('G','L','K',' ')},*/ /* Gilaki */ + {"gmz", HB_TAG_NONE }, /* Mgbolizhia != Gumuz */ {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ + {"gnb", HB_TAG('Q','I','N',' ')}, /* Gangte -> Chin */ /*{"gnn", HB_TAG('G','N','N',' ')},*/ /* Gumatj */ {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ {"gnw", HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ /*{"gog", HB_TAG('G','O','G',' ')},*/ /* Gogo */ {"gom", HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ /*{"gon", HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ + {"goq", HB_TAG('C','P','P',' ')}, /* Gorap -> Creoles */ + {"gox", HB_TAG('B','A','D','0')}, /* Gobu -> Banda */ + {"gpe", HB_TAG('C','P','P',' ')}, /* Ghanaian Pidgin English -> Creoles */ + {"gro", HB_TAG_NONE }, /* Groma != Garo */ + {"grr", HB_TAG('B','B','R',' ')}, /* Taznatit -> Berber */ {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ {"gru", HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ + {"gua", HB_TAG_NONE }, /* Shiki != Guarani */ /*{"guc", HB_TAG('G','U','C',' ')},*/ /* Wayuu */ /*{"guf", HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ {"gug", HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ {"gui", HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ - {"guk", HB_TAG('G','U','K',' ')}, /* Gumuz (SIL fonts) */ + {"gul", HB_TAG('C','P','P',' ')}, /* Sea Island Creole English -> Creoles */ {"gun", HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ /*{"guz", HB_TAG('G','U','Z',' ')},*/ /* Gusii */ {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ {"gwi", HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ + {"gyn", HB_TAG('C','P','P',' ')}, /* Guyanese Creole English -> Creoles */ {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ {"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ {"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ - {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese Simplified */ + {"hai", HB_TAG_NONE }, /* Haida [macrolanguage] != Haitian (Haitian Creole) */ + {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese, Simplified */ + {"hal", HB_TAG_NONE }, /* Halang != Halam (Falam Chin) */ {"har", HB_TAG('H','R','I',' ')}, /* Harari */ /*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ /*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */ /*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ + {"hbn", HB_TAG_NONE }, /* Heiban != Hammer-Banna */ + {"hca", HB_TAG('C','P','P',' ')}, /* Andaman Creole Hindi -> Creoles */ {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ {"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ @@ -401,6 +565,7 @@ static const LangTag ot_languages[] = { /*{"hmn", HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ {"hmp", HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ {"hmq", HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ + {"hmr", HB_TAG('Q','I','N',' ')}, /* Hmar -> Chin */ {"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ {"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ {"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ @@ -410,17 +575,23 @@ static const LangTag ot_languages[] = { {"hnj", HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ {"hno", HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ + {"ho", HB_TAG('C','P','P',' ')}, /* Hiri Motu -> Creoles */ {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ {"hoi", HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ {"hoj", HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ + {"hoj", HB_TAG('R','A','J',' ')}, /* Hadothi -> Rajasthani */ {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ + {"hra", HB_TAG('Q','I','N',' ')}, /* Hrangkhol -> Chin */ {"hrm", HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ - {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese Simplified */ + {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */ {"ht", HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ + {"ht", HB_TAG('C','P','P',' ')}, /* Haitian -> Creoles */ {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ {"huj", HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ {"hup", HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ + {"hus", HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */ + {"hwc", HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */ {"hy", HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ {"hyw", HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ @@ -428,38 +599,65 @@ static const LangTag ot_languages[] = { {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ /*{"iba", HB_TAG('I','B','A',' ')},*/ /* Iban */ /*{"ibb", HB_TAG('I','B','B',' ')},*/ /* Ibibio */ + {"iby", HB_TAG('I','J','O',' ')}, /* Ibani -> Ijo */ + {"icr", HB_TAG('C','P','P',' ')}, /* Islander Creole English -> Creoles */ {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ + {"id", HB_TAG('M','L','Y',' ')}, /* Indonesian -> Malay */ {"ida", HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ + {"idb", HB_TAG('C','P','P',' ')}, /* Indo-Portuguese -> Creoles */ {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue */ {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ + {"ihb", HB_TAG('C','P','P',' ')}, /* Iha Based Pidgin -> Creoles */ {"ii", HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ + {"ije", HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ + {"ijn", HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ /*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [family] */ + {"ijs", HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ /*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ + {"in", HB_TAG('M','L','Y',' ')}, /* Indonesian (retired code) -> Malay */ {"ing", HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ {"io", HB_TAG('I','D','O',' ')}, /* Ido */ + {"iri", HB_TAG_NONE }, /* Rigwe != Irish */ {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ + {"ism", HB_TAG_NONE }, /* Masimasi != Inari Sami */ {"it", HB_TAG('I','T','A',' ')}, /* Italian */ + {"itz", HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ + {"ixl", HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ + {"jac", HB_TAG('M','Y','N',' ')}, /* Popti' -> Mayan */ {"jak", HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ -/*{"jam", HB_TAG('J','A','M',' ')},*/ /* Jamaican Creole English -> Jamaican Creole */ + {"jam", HB_TAG('J','A','M',' ')}, /* Jamaican Creole English -> Jamaican Creole */ + {"jam", HB_TAG('C','P','P',' ')}, /* Jamaican Creole English -> Creoles */ + {"jan", HB_TAG_NONE }, /* Jandai != Japanese */ {"jax", HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ + {"jbe", HB_TAG('B','B','R',' ')}, /* Judeo-Berber -> Berber */ + {"jbn", HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */ /*{"jbo", HB_TAG('J','B','O',' ')},*/ /* Lojban */ /*{"jct", HB_TAG('J','C','T',' ')},*/ /* Krymchak */ + {"jgo", HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */ {"ji", HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ + {"jii", HB_TAG_NONE }, /* Jiiddu != Yiddish */ + {"jkm", HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */ + {"jkp", HB_TAG('K','R','N',' ')}, /* Paku Karen -> Karen */ + {"jud", HB_TAG_NONE }, /* Worodougou != Ladino */ + {"jul", HB_TAG_NONE }, /* Jirel != Jula */ {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ + {"jvd", HB_TAG('C','P','P',' ')}, /* Javindo -> Creoles */ {"jw", HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ - {"kaa", HB_TAG('K','R','K',' ')}, /* Kara-Kalpak -> Karakalpak */ + {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ + {"kab", HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ + {"kac", HB_TAG_NONE }, /* Kachin != Kachchi */ {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ @@ -467,82 +665,139 @@ static const LangTag ot_languages[] = { {"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ {"kca", HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ {"kca", HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ + {"kcn", HB_TAG('C','P','P',' ')}, /* Nubi -> Creoles */ /*{"kde", HB_TAG('K','D','E',' ')},*/ /* Makonde */ {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ -/*{"kea", HB_TAG('K','E','A',' ')},*/ /* Kabuverdianu (Crioulo) */ -/*{"kek", HB_TAG('K','E','K',' ')},*/ /* Kekchi */ + {"kea", HB_TAG('K','E','A',' ')}, /* Kabuverdianu (Crioulo) */ + {"kea", HB_TAG('C','P','P',' ')}, /* Kabuverdianu -> Creoles */ + {"keb", HB_TAG_NONE }, /* Kélé != Kebena */ + {"kek", HB_TAG('K','E','K',' ')}, /* Kekchi */ + {"kek", HB_TAG('M','Y','N',' ')}, /* Kekchí -> Mayan */ {"kex", HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ {"kfa", HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ {"kfr", HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ {"kfx", HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ {"kg", HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ + {"kge", HB_TAG_NONE }, /* Komering != Khutsuri Georgian */ {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ {"khk", HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ + {"khn", HB_TAG_NONE }, /* Khandesi != Khamti Shan (Microsoft fonts) */ + {"khs", HB_TAG_NONE }, /* Kasua != Khanty-Shurishkar */ + {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan */ {"kht", HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ - {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */ + {"khv", HB_TAG_NONE }, /* Khvarshi != Khanty-Vakhi */ /*{"khw", HB_TAG('K','H','W',' ')},*/ /* Khowar */ {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ -/*{"kiu", HB_TAG('K','I','U',' ')},*/ /* Kirmanjki */ + {"kis", HB_TAG_NONE }, /* Kis != Kisii */ + {"kiu", HB_TAG('K','I','U',' ')}, /* Kirmanjki */ + {"kiu", HB_TAG('Z','Z','A',' ')}, /* Kirmanjki -> Zazaki */ {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama */ + {"kjb", HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */ /*{"kjd", HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ {"kjh", HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ -/*{"kjp", HB_TAG('K','J','P',' ')},*/ /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {"kjp", HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ + {"kjp", HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */ + {"kjt", HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */ /*{"kjz", HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ + {"kkn", HB_TAG_NONE }, /* Kon Keu != Kokni */ {"kkz", HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ {"kl", HB_TAG('G','R','N',' ')}, /* Greenlandic */ + {"klm", HB_TAG_NONE }, /* Migum != Kalmyk */ {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ {"km", HB_TAG('K','H','M',' ')}, /* Khmer */ {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ + {"kmn", HB_TAG_NONE }, /* Awtuw != Kumaoni */ + {"kmo", HB_TAG_NONE }, /* Kwoma != Komo */ {"kmr", HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ + {"kms", HB_TAG_NONE }, /* Kamasau != Komso */ + {"kmv", HB_TAG('C','P','P',' ')}, /* Karipúna Creole French -> Creoles */ {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ /*{"kmz", HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ {"knc", HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ {"kng", HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ + {"knj", HB_TAG('M','Y','N',' ')}, /* Western Kanjobal -> Mayan */ {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ + {"knr", HB_TAG_NONE }, /* Kaningra != Kanuri */ {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ + {"ko", HB_TAG('K','O','H',' ')}, /* Korean -> Korean Old Hangul */ + {"kod", HB_TAG_NONE }, /* Kodi != Kodagu */ + {"koh", HB_TAG_NONE }, /* Koyo != Korean Old Hangul */ {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ + {"koi", HB_TAG('K','O','M',' ')}, /* Komi-Permyak -> Komi */ /*{"kok", HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ + {"kop", HB_TAG_NONE }, /* Waube != Komi-Permyak */ /*{"kos", HB_TAG('K','O','S',' ')},*/ /* Kosraean */ {"koy", HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ + {"koz", HB_TAG_NONE }, /* Korak != Komi-Zyrian */ {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ + {"kpl", HB_TAG_NONE }, /* Kpala != Kpelle */ + {"kpp", HB_TAG('K','R','N',' ')}, /* Paku Karen (retired code) -> Karen */ {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ + {"kpv", HB_TAG('K','O','M',' ')}, /* Komi-Zyrian -> Komi */ {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ {"kqs", HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ {"krc", HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ {"krc", HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ -/*{"kri", HB_TAG('K','R','I',' ')},*/ /* Krio */ + {"kri", HB_TAG('K','R','I',' ')}, /* Krio */ + {"kri", HB_TAG('C','P','P',' ')}, /* Krio -> Creoles */ + {"krk", HB_TAG_NONE }, /* Kerek != Karakalpak */ /*{"krl", HB_TAG('K','R','L',' ')},*/ /* Karelian */ + {"krm", HB_TAG_NONE }, /* Krim (retired code) != Karaim */ + {"krn", HB_TAG_NONE }, /* Sapo != Karen */ {"krt", HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ {"ksh", HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ + {"ksi", HB_TAG_NONE }, /* Krisa != Khasi */ + {"ksm", HB_TAG_NONE }, /* Kumba != Kildin Sami */ {"kss", HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ -/*{"ksw", HB_TAG('K','S','W',' ')},*/ /* S’gaw Karen */ + {"ksw", HB_TAG('K','S','W',' ')}, /* S’gaw Karen */ + {"ksw", HB_TAG('K','R','N',' ')}, /* S'gaw Karen -> Karen */ {"ktb", HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ {"ktu", HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ {"ktw", HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ + {"kui", HB_TAG_NONE }, /* Kuikúro-Kalapálo != Kui */ + {"kul", HB_TAG_NONE }, /* Kulere != Kulvi */ /*{"kum", HB_TAG('K','U','M',' ')},*/ /* Kumyk */ {"kuu", HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ + {"kuw", HB_TAG('B','A','D','0')}, /* Kpagua -> Banda */ + {"kuy", HB_TAG_NONE }, /* Kuuku-Ya'u != Kuy */ {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ {"kvb", HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ + {"kvl", HB_TAG('K','R','N',' ')}, /* Kayaw -> Karen */ + {"kvq", HB_TAG('K','R','N',' ')}, /* Geba Karen -> Karen */ {"kvr", HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ + {"kvt", HB_TAG('K','R','N',' ')}, /* Lahta Karen -> Karen */ + {"kvu", HB_TAG('K','R','N',' ')}, /* Yinbaw Karen -> Karen */ + {"kvy", HB_TAG('K','R','N',' ')}, /* Yintale Karen -> Karen */ {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ + {"kww", HB_TAG('C','P','P',' ')}, /* Kwinti -> Creoles */ {"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ {"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ {"kxd", HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ - {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) */ + {"kxf", HB_TAG('K','R','N',' ')}, /* Manumanaw Karen -> Karen */ + {"kxk", HB_TAG('K','R','N',' ')}, /* Zayein Karen -> Karen */ + {"kxl", HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ + {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ -/*{"kyu", HB_TAG('K','Y','U',' ')},*/ /* Western Kayah */ + {"kyk", HB_TAG_NONE }, /* Kamayo != Koryak */ + {"kyu", HB_TAG('K','Y','U',' ')}, /* Western Kayah */ + {"kyu", HB_TAG('K','R','N',' ')}, /* Western Kayah -> Karen */ {"la", HB_TAG('L','A','T',' ')}, /* Latin */ + {"lac", HB_TAG('M','Y','N',' ')}, /* Lacandon -> Mayan */ {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ + {"lah", HB_TAG_NONE }, /* Lahnda [macrolanguage] != Lahuli */ + {"lak", HB_TAG_NONE }, /* Laka (Nigeria) != Lak */ + {"lam", HB_TAG_NONE }, /* Lamba != Lambani */ + {"laz", HB_TAG_NONE }, /* Aribwatsa != Laz */ {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ @@ -550,85 +805,129 @@ static const LangTag ot_languages[] = { {"lce", HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ {"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ {"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ + {"ldk", HB_TAG_NONE }, /* Leelau != Ladakhi */ /*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ {"li", HB_TAG('L','I','M',' ')}, /* Limburgish */ {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ /*{"lij", HB_TAG('L','I','J',' ')},*/ /* Ligurian */ + {"lir", HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */ /*{"lis", HB_TAG('L','I','S',' ')},*/ /* Lisu */ {"liw", HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ + {"liy", HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */ /*{"ljp", HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ {"lkb", HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ /*{"lki", HB_TAG('L','K','I',' ')},*/ /* Laki */ {"lko", HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ {"lks", HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ + {"lma", HB_TAG_NONE }, /* East Limba != Low Mari */ + {"lmb", HB_TAG_NONE }, /* Merei != Limbu */ {"lmn", HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ /*{"lmo", HB_TAG('L','M','O',' ')},*/ /* Lombard */ + {"lmw", HB_TAG_NONE }, /* Lake Miwok != Lomwe */ {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ + {"lna", HB_TAG('B','A','D','0')}, /* Langbashe -> Banda */ + {"lnl", HB_TAG('B','A','D','0')}, /* South Central Banda -> Banda */ {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ /*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ + {"lou", HB_TAG('C','P','P',' ')}, /* Louisiana Creole -> Creoles */ /*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ {"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ {"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ + {"lrt", HB_TAG('C','P','P',' ')}, /* Larantuka Malay -> Creoles */ + {"lsb", HB_TAG_NONE }, /* Burundian Sign Language != Lower Sorbian */ {"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ {"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ + {"lth", HB_TAG_NONE }, /* Thur != Lithuanian */ {"lto", HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ {"lts", HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ /*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ /*{"luo", HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ {"lus", HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ + {"lus", HB_TAG('Q','I','N',' ')}, /* Lushai -> Chin */ {"luy", HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ {"lv", HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ + {"lvi", HB_TAG_NONE }, /* Lavi != Latvian */ {"lvs", HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ {"lwg", HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ - {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese Traditional */ + {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese, Traditional */ {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ /*{"mad", HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ /*{"mag", HB_TAG('M','A','G',' ')},*/ /* Magahi */ {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ + {"maj", HB_TAG_NONE }, /* Jalapa De Díaz Mazatec != Majang */ {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ -/*{"mam", HB_TAG('M','A','M',' ')},*/ /* Mam */ + {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ + {"mam", HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ + {"map", HB_TAG_NONE }, /* Austronesian [family] != Mapudungun */ + {"maw", HB_TAG_NONE }, /* Mampruli != Marwari */ {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ + {"max", HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ + {"mbf", HB_TAG('C','P','P',' ')}, /* Baba Malay -> Creoles */ + {"mbn", HB_TAG_NONE }, /* Macaguán != Mbundu */ /*{"mbo", HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ + {"mch", HB_TAG_NONE }, /* Maquiritari != Manchu */ + {"mcm", HB_TAG('C','P','P',' ')}, /* Malaccan Creole Portuguese -> Creoles */ + {"mcr", HB_TAG_NONE }, /* Menya != Moose Cree */ {"mct", HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ + {"mde", HB_TAG_NONE }, /* Maba (Chad) != Mende */ {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ /*{"mdr", HB_TAG('M','D','R',' ')},*/ /* Mandar */ {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ {"meo", HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ /*{"mer", HB_TAG('M','E','R',' ')},*/ /* Meru */ -/*{"mfa", HB_TAG('M','F','A',' ')},*/ /* Pattani Malay */ + {"mfa", HB_TAG('M','F','A',' ')}, /* Pattani Malay */ + {"mfa", HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */ {"mfb", HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ -/*{"mfe", HB_TAG('M','F','E',' ')},*/ /* Morisyen */ + {"mfe", HB_TAG('M','F','E',' ')}, /* Morisyen */ + {"mfe", HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */ + {"mfp", HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */ {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ + {"mhc", HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */ {"mhr", HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ {"mhv", HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ -/*{"min", HB_TAG('M','I','N',' ')},*/ /* Minangkabau */ + {"min", HB_TAG('M','I','N',' ')}, /* Minangkabau */ + {"min", HB_TAG('M','L','Y',' ')}, /* Minangkabau -> Malay */ + {"miz", HB_TAG_NONE }, /* Coatzospan Mixtec != Mizo */ {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ + {"mkn", HB_TAG('C','P','P',' ')}, /* Kupang Malay -> Creoles */ + {"mkr", HB_TAG_NONE }, /* Malas != Makasar */ {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ /*{"mkw", HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ {"ml", HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ + {"mle", HB_TAG_NONE }, /* Manambu != Male */ + {"mln", HB_TAG_NONE }, /* Malango != Malinke */ {"mlq", HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ + {"mlr", HB_TAG_NONE }, /* Vame != Malayalam Reformed */ {"mmr", HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ + {"mnd", HB_TAG_NONE }, /* Mondé != Mandinka */ + {"mng", HB_TAG_NONE }, /* Eastern Mnong != Mongolian */ + {"mnh", HB_TAG('B','A','D','0')}, /* Mono (Democratic Republic of Congo) -> Banda */ /*{"mni", HB_TAG('M','N','I',' ')},*/ /* Manipuri */ {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ {"mnk", HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ - {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese Simplified */ + {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ + {"mnx", HB_TAG_NONE }, /* Manikion != Manx */ {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ + {"mod", HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ /*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */ + {"mok", HB_TAG_NONE }, /* Morori != Moksha */ + {"mop", HB_TAG('M','Y','N',' ')}, /* Mopán Maya -> Mayan */ + {"mor", HB_TAG_NONE }, /* Moro != Moroccan */ /*{"mos", HB_TAG('M','O','S',' ')},*/ /* Mossi */ {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ {"mqg", HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ @@ -639,9 +938,14 @@ static const LangTag ot_languages[] = { {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ {"msh", HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ {"msi", HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ + {"msi", HB_TAG('C','P','P',' ')}, /* Sabah Malay -> Creoles */ {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ + {"mth", HB_TAG_NONE }, /* Munggui != Maithili */ {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ + {"mts", HB_TAG_NONE }, /* Yora != Maltese */ + {"mud", HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ + {"mun", HB_TAG_NONE }, /* Munda [family] != Mundari */ {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ /*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ @@ -650,49 +954,101 @@ static const LangTag ot_languages[] = { {"mvf", HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ /*{"mwl", HB_TAG('M','W','L',' ')},*/ /* Mirandese */ + {"mwq", HB_TAG('Q','I','N',' ')}, /* Mün Chin -> Chin */ {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ -/*{"mww", HB_TAG('M','W','W',' ')},*/ /* Hmong Daw */ + {"mww", HB_TAG('M','W','W',' ')}, /* Hmong Daw */ + {"mww", HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */ /*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [family] */ {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ + {"mzb", HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ /*{"mzn", HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ + {"mzs", HB_TAG('C','P','P',' ')}, /* Macanese -> Creoles */ {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ -/*{"nag", HB_TAG('N','A','G',' ')},*/ /* Naga Pidgin -> Naga-Assamese */ + {"nag", HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ + {"nag", HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ /*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [family] */ - {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese Simplified */ + {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ /*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ + {"nas", HB_TAG_NONE }, /* Naasioi != Naskapi */ + {"naz", HB_TAG('N','A','H',' ')}, /* Coatepec Nahuatl -> Nahuatl */ {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */ + {"nch", HB_TAG('N','A','H',' ')}, /* Central Huasteca Nahuatl -> Nahuatl */ + {"nci", HB_TAG('N','A','H',' ')}, /* Classical Nahuatl -> Nahuatl */ + {"ncj", HB_TAG('N','A','H',' ')}, /* Northern Puebla Nahuatl -> Nahuatl */ + {"ncl", HB_TAG('N','A','H',' ')}, /* Michoacán Nahuatl -> Nahuatl */ + {"ncr", HB_TAG_NONE }, /* Ncane != N-Cree */ + {"ncx", HB_TAG('N','A','H',' ')}, /* Central Puebla Nahuatl -> Nahuatl */ {"nd", HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ + {"ndb", HB_TAG_NONE }, /* Kenswei Nsei != Ndebele */ /*{"ndc", HB_TAG('N','D','C',' ')},*/ /* Ndau */ + {"ndg", HB_TAG_NONE }, /* Ndengereko != Ndonga */ /*{"nds", HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ {"ne", HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ + {"nef", HB_TAG('C','P','P',' ')}, /* Nefamese -> Creoles */ /*{"new", HB_TAG('N','E','W',' ')},*/ /* Newari */ {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ /*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ - {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni -> Sutu */ + {"ngm", HB_TAG('C','P','P',' ')}, /* Ngatik Men's Creole -> Creoles */ + {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni (retired code) -> Sutu */ + {"ngr", HB_TAG_NONE }, /* Engdewu != Nagari */ + {"ngu", HB_TAG('N','A','H',' ')}, /* Guerrero Nahuatl -> Nahuatl */ + {"nhc", HB_TAG('N','A','H',' ')}, /* Tabasco Nahuatl -> Nahuatl */ {"nhd", HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ + {"nhe", HB_TAG('N','A','H',' ')}, /* Eastern Huasteca Nahuatl -> Nahuatl */ + {"nhg", HB_TAG('N','A','H',' ')}, /* Tetelcingo Nahuatl -> Nahuatl */ + {"nhi", HB_TAG('N','A','H',' ')}, /* Zacatlán-Ahuacatlán-Tepetzintla Nahuatl -> Nahuatl */ + {"nhk", HB_TAG('N','A','H',' ')}, /* Isthmus-Cosoleacaque Nahuatl -> Nahuatl */ + {"nhm", HB_TAG('N','A','H',' ')}, /* Morelos Nahuatl -> Nahuatl */ + {"nhn", HB_TAG('N','A','H',' ')}, /* Central Nahuatl -> Nahuatl */ + {"nhp", HB_TAG('N','A','H',' ')}, /* Isthmus-Pajapan Nahuatl -> Nahuatl */ + {"nhq", HB_TAG('N','A','H',' ')}, /* Huaxcaleca Nahuatl -> Nahuatl */ + {"nht", HB_TAG('N','A','H',' ')}, /* Ometepec Nahuatl -> Nahuatl */ + {"nhv", HB_TAG('N','A','H',' ')}, /* Temascaltepec Nahuatl -> Nahuatl */ + {"nhw", HB_TAG('N','A','H',' ')}, /* Western Huasteca Nahuatl -> Nahuatl */ + {"nhx", HB_TAG('N','A','H',' ')}, /* Isthmus-Mecayapan Nahuatl -> Nahuatl */ + {"nhy", HB_TAG('N','A','H',' ')}, /* Northern Oaxaca Nahuatl -> Nahuatl */ + {"nhz", HB_TAG('N','A','H',' ')}, /* Santa María La Alta Nahuatl -> Nahuatl */ {"niq", HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ + {"nis", HB_TAG_NONE }, /* Nimi != Nisi */ /*{"niu", HB_TAG('N','I','U',' ')},*/ /* Niuean */ {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ + {"njt", HB_TAG('C','P','P',' ')}, /* Ndyuka-Trio Pidgin -> Creoles */ {"njz", HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ + {"nko", HB_TAG_NONE }, /* Nkonya != N’Ko */ + {"nkx", HB_TAG('I','J','O',' ')}, /* Nkoroo -> Ijo */ {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ + {"nla", HB_TAG('B','M','L',' ')}, /* Ngombale -> Bamileke */ {"nle", HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ + {"nln", HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ + {"nlv", HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {"nn", HB_TAG('N','O','R',' ')}, /* Norwegian Nynorsk -> Norwegian */ + {"nnh", HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ + {"nnz", HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ /*{"noe", HB_TAG('N','O','E',' ')},*/ /* Nimadi */ /*{"nog", HB_TAG('N','O','G',' ')},*/ /* Nogai */ /*{"nov", HB_TAG('N','O','V',' ')},*/ /* Novial */ {"npi", HB_TAG('N','E','P',' ')}, /* Nepali */ + {"npl", HB_TAG('N','A','H',' ')}, /* Southeastern Puebla Nahuatl -> Nahuatl */ {"nqo", HB_TAG('N','K','O',' ')}, /* N’Ko */ {"nr", HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ -/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Pedi -> Sotho, Northern */ + {"nsm", HB_TAG_NONE }, /* Sumi Naga != Northern Sami */ +/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Northern Sotho */ + {"nsu", HB_TAG('N','A','H',' ')}, /* Sierra Negra Nahuatl -> Nahuatl */ + {"nto", HB_TAG_NONE }, /* Ntomba != Esperanto */ + {"nue", HB_TAG('B','A','D','0')}, /* Ngundu -> Banda */ + {"nuu", HB_TAG('B','A','D','0')}, /* Ngbundu -> Banda */ + {"nuz", HB_TAG('N','A','H',' ')}, /* Tlamacazapa Nahuatl -> Nahuatl */ {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ {"nv", HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ + {"nwe", HB_TAG('B','M','L',' ')}, /* Ngwe -> Bamileke */ {"ny", HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ {"nyd", HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ /*{"nym", HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ @@ -704,21 +1060,33 @@ static const LangTag ot_languages[] = { {"ojc", HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ {"ojg", HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ {"ojs", HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ + {"ojs", HB_TAG('O','J','B',' ')}, /* Severn Ojibwa -> Ojibway */ {"ojw", HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ + {"okd", HB_TAG('I','J','O',' ')}, /* Okodia -> Ijo */ {"oki", HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ {"okm", HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {"okr", HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */ {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ + {"onx", HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */ + {"oor", HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */ {"or", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ {"orc", HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ {"orn", HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ + {"oro", HB_TAG_NONE }, /* Orokolo != Oromo */ + {"orr", HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */ {"ors", HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ {"ory", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ + {"oua", HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */ + {"paa", HB_TAG_NONE }, /* Papuan [family] != Palestinian Aramaic */ /*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ + {"pal", HB_TAG_NONE }, /* Pahlavi != Pali */ /*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ {"pap", HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ + {"pap", HB_TAG('C','P','P',' ')}, /* Papiamento -> Creoles */ + {"pas", HB_TAG_NONE }, /* Papasena != Pashto */ /*{"pau", HB_TAG('P','A','U',' ')},*/ /* Palauan */ {"pbt", HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ {"pbu", HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ @@ -726,84 +1094,147 @@ static const LangTag ot_languages[] = { /*{"pcd", HB_TAG('P','C','D',' ')},*/ /* Picard */ {"pce", HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ + {"pcm", HB_TAG('C','P','P',' ')}, /* Nigerian Pidgin -> Creoles */ /*{"pdc", HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ + {"pdu", HB_TAG('K','R','N',' ')}, /* Kayan -> Karen */ + {"pea", HB_TAG('C','P','P',' ')}, /* Peranakan Indonesian -> Creoles */ {"pel", HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ + {"pey", HB_TAG('C','P','P',' ')}, /* Petjo -> Creoles */ {"pga", HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ + {"pga", HB_TAG('C','P','P',' ')}, /* Sudanese Creole Arabic -> Creoles */ /*{"phk", HB_TAG('P','H','K',' ')},*/ /* Phake */ {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ -/*{"pih", HB_TAG('P','I','H',' ')},*/ /* Pitcairn-Norfolk -> Norfolk */ + {"pih", HB_TAG('P','I','H',' ')}, /* Pitcairn-Norfolk -> Norfolk */ + {"pih", HB_TAG('C','P','P',' ')}, /* Pitcairn-Norfolk -> Creoles */ + {"pil", HB_TAG_NONE }, /* Yom != Filipino */ + {"pis", HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */ + {"pkh", HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */ {"pko", HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ + {"plg", HB_TAG_NONE }, /* Pilagá != Palaung */ + {"plk", HB_TAG_NONE }, /* Kohistani Shina != Polish */ {"pll", HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ - {"plp", HB_TAG('P','A','P',' ')}, /* Palpa */ + {"pln", HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */ + {"plp", HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ {"plt", HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ + {"pml", HB_TAG('C','P','P',' ')}, /* Lingua Franca -> Creoles */ /*{"pms", HB_TAG('P','M','S',' ')},*/ /* Piemontese */ + {"pmy", HB_TAG('C','P','P',' ')}, /* Papuan Malay -> Creoles */ /*{"pnb", HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ -/*{"poh", HB_TAG('P','O','H',' ')},*/ /* Poqomchi' -> Pocomchi */ + {"poc", HB_TAG('M','Y','N',' ')}, /* Poqomam -> Mayan */ + {"poh", HB_TAG('P','O','H',' ')}, /* Poqomchi' -> Pocomchi */ + {"poh", HB_TAG('M','Y','N',' ')}, /* Poqomchi' -> Mayan */ /*{"pon", HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ + {"pov", HB_TAG('C','P','P',' ')}, /* Upper Guinea Crioulo -> Creoles */ {"ppa", HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ + {"pre", HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */ /*{"pro", HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ {"prs", HB_TAG('D','R','I',' ')}, /* Dari */ + {"prs", HB_TAG('F','A','R',' ')}, /* Dari -> Persian */ {"ps", HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ {"pse", HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ {"pst", HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ -/*{"pwo", HB_TAG('P','W','O',' ')},*/ /* Pwo Western Karen -> Western Pwo Karen */ + {"pub", HB_TAG('Q','I','N',' ')}, /* Purum -> Chin */ + {"puz", HB_TAG('Q','I','N',' ')}, /* Purum Naga (retired code) -> Chin */ + {"pwo", HB_TAG('P','W','O',' ')}, /* Pwo Western Karen -> Western Pwo Karen */ + {"pwo", HB_TAG('K','R','N',' ')}, /* Pwo Western Karen -> Karen */ + {"pww", HB_TAG('K','R','N',' ')}, /* Pwo Northern Karen -> Karen */ {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ {"qub", HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ -/*{"quc", HB_TAG('Q','U','C',' ')},*/ /* K’iche’ */ + {"qub", HB_TAG('Q','U','Z',' ')}, /* Huallaga Huánuco Quechua -> Quechua */ + {"quc", HB_TAG('Q','U','C',' ')}, /* K’iche’ */ + {"quc", HB_TAG('M','Y','N',' ')}, /* K'iche' -> Mayan */ {"qud", HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {"qud", HB_TAG('Q','U','Z',' ')}, /* Calderón Highland Quichua -> Quechua */ {"quf", HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ {"qug", HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ -/*{"quh", HB_TAG('Q','U','H',' ')},*/ /* South Bolivian Quechua -> Quechua (Bolivia) */ + {"qug", HB_TAG('Q','U','Z',' ')}, /* Chimborazo Highland Quichua -> Quechua */ + {"quh", HB_TAG('Q','U','H',' ')}, /* South Bolivian Quechua -> Quechua (Bolivia) */ + {"quh", HB_TAG('Q','U','Z',' ')}, /* South Bolivian Quechua -> Quechua */ {"quk", HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ + {"qul", HB_TAG('Q','U','H',' ')}, /* North Bolivian Quechua -> Quechua (Bolivia) */ {"qul", HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ + {"qum", HB_TAG('M','Y','N',' ')}, /* Sipacapense -> Mayan */ {"qup", HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {"qup", HB_TAG('Q','U','Z',' ')}, /* Southern Pastaza Quechua -> Quechua */ {"qur", HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {"qur", HB_TAG('Q','U','Z',' ')}, /* Yanahuanca Pasco Quechua -> Quechua */ {"qus", HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {"qus", HB_TAG('Q','U','Z',' ')}, /* Santiago del Estero Quichua -> Quechua */ + {"quv", HB_TAG('M','Y','N',' ')}, /* Sacapulteco -> Mayan */ {"quw", HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {"quw", HB_TAG('Q','U','Z',' ')}, /* Tena Lowland Quichua -> Quechua */ {"qux", HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ + {"qux", HB_TAG('Q','U','Z',' ')}, /* Yauyos Quechua -> Quechua */ {"quy", HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ /*{"quz", HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ {"qva", HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {"qva", HB_TAG('Q','U','Z',' ')}, /* Ambo-Pasco Quechua -> Quechua */ {"qvc", HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ {"qve", HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ {"qvh", HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ -/*{"qvi", HB_TAG('Q','V','I',' ')},*/ /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {"qvh", HB_TAG('Q','U','Z',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua */ + {"qvi", HB_TAG('Q','V','I',' ')}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {"qvi", HB_TAG('Q','U','Z',' ')}, /* Imbabura Highland Quichua -> Quechua */ {"qvj", HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {"qvj", HB_TAG('Q','U','Z',' ')}, /* Loja Highland Quichua -> Quechua */ {"qvl", HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {"qvl", HB_TAG('Q','U','Z',' ')}, /* Cajatambo North Lima Quechua -> Quechua */ {"qvm", HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {"qvm", HB_TAG('Q','U','Z',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua */ {"qvn", HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ + {"qvn", HB_TAG('Q','U','Z',' ')}, /* North Junín Quechua -> Quechua */ {"qvo", HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {"qvo", HB_TAG('Q','U','Z',' ')}, /* Napo Lowland Quechua -> Quechua */ {"qvp", HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ + {"qvp", HB_TAG('Q','U','Z',' ')}, /* Pacaraos Quechua -> Quechua */ {"qvs", HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ {"qvw", HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {"qvw", HB_TAG('Q','U','Z',' ')}, /* Huaylla Wanca Quechua -> Quechua */ {"qvz", HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {"qvz", HB_TAG('Q','U','Z',' ')}, /* Northern Pastaza Quichua -> Quechua */ {"qwa", HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {"qwa", HB_TAG('Q','U','Z',' ')}, /* Corongo Ancash Quechua -> Quechua */ {"qwc", HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ -/*{"qwh", HB_TAG('Q','W','H',' ')},*/ /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {"qwh", HB_TAG('Q','W','H',' ')}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {"qwh", HB_TAG('Q','U','Z',' ')}, /* Huaylas Ancash Quechua -> Quechua */ {"qws", HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {"qws", HB_TAG('Q','U','Z',' ')}, /* Sihuas Ancash Quechua -> Quechua */ + {"qwt", HB_TAG('A','T','H',' ')}, /* Kwalhioqua-Tlatskanai -> Athapaskan */ {"qxa", HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {"qxa", HB_TAG('Q','U','Z',' ')}, /* Chiquián Ancash Quechua -> Quechua */ {"qxc", HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ + {"qxc", HB_TAG('Q','U','Z',' ')}, /* Chincha Quechua -> Quechua */ {"qxh", HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {"qxh", HB_TAG('Q','U','Z',' ')}, /* Panao Huánuco Quechua -> Quechua */ {"qxl", HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {"qxl", HB_TAG('Q','U','Z',' ')}, /* Salasaca Highland Quichua -> Quechua */ {"qxn", HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxn", HB_TAG('Q','U','Z',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua */ {"qxo", HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxo", HB_TAG('Q','U','Z',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua */ {"qxp", HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ {"qxr", HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {"qxr", HB_TAG('Q','U','Z',' ')}, /* Cañar Highland Quichua -> Quechua */ {"qxt", HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {"qxt", HB_TAG('Q','U','Z',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua */ {"qxu", HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ {"qxw", HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {"qxw", HB_TAG('Q','U','Z',' ')}, /* Jauja Wanca Quechua -> Quechua */ {"rag", HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ /*{"raj", HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ + {"ral", HB_TAG('Q','I','N',' ')}, /* Ralte -> Chin */ /*{"rar", HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ {"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ + {"rcf", HB_TAG('C','P','P',' ')}, /* Réunion Creole French -> Creoles */ /*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */ /*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ -/*{"rif", HB_TAG('R','I','F',' ')},*/ /* Tarifit */ -/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritarungo */ + {"rif", HB_TAG('R','I','F',' ')}, /* Tarifit */ + {"rif", HB_TAG('B','B','R',' ')}, /* Tarifit -> Berber */ +/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ /*{"rkw", HB_TAG('R','K','W',' ')},*/ /* Arakwal */ {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ @@ -812,13 +1243,16 @@ static const LangTag ot_languages[] = { {"rml", HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ {"rmn", HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ {"rmo", HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ + {"rms", HB_TAG_NONE }, /* Romanian Sign Language != Romansh */ {"rmw", HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ -/*{"rmy", HB_TAG('R','M','Y',' ')},*/ /* Vlax Romani */ + {"rmy", HB_TAG('R','M','Y',' ')}, /* Vlax Romani */ + {"rmy", HB_TAG('R','O','Y',' ')}, /* Vlax Romani -> Romany */ {"rmz", HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ - {"rnl", HB_TAG('H','A','L',' ')}, /* Ranglong -> Halam (Falam Chin) */ {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ + {"rop", HB_TAG('C','P','P',' ')}, /* Kriol -> Creoles */ + {"rtc", HB_TAG('Q','I','N',' ')}, /* Rungtu Chin -> Chin */ /*{"rtm", HB_TAG('R','T','M',' ')},*/ /* Rotuman */ {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ @@ -826,11 +1260,16 @@ static const LangTag ot_languages[] = { {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ + {"sad", HB_TAG_NONE }, /* Sandawe != Sadri */ {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ {"sam", HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ /*{"sas", HB_TAG('S','A','S',' ')},*/ /* Sasak */ /*{"sat", HB_TAG('S','A','T',' ')},*/ /* Santali */ + {"say", HB_TAG_NONE }, /* Saya != Sayisi */ {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ + {"scf", HB_TAG('C','P','P',' ')}, /* San Miguel Creole French -> Creoles */ + {"sch", HB_TAG('Q','I','N',' ')}, /* Sakachep -> Chin */ + {"sci", HB_TAG('C','P','P',' ')}, /* Sri Lankan Creole Malay -> Creoles */ {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ /*{"scn", HB_TAG('S','C','N',' ')},*/ /* Sicilian */ /*{"sco", HB_TAG('S','C','O',' ')},*/ /* Scots */ @@ -841,6 +1280,7 @@ static const LangTag ot_languages[] = { {"sdc", HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ {"sdh", HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ {"sdn", HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ + {"sds", HB_TAG('B','B','R',' ')}, /* Sened -> Berber */ {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ {"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ @@ -850,51 +1290,78 @@ static const LangTag ot_languages[] = { {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ /*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ {"sgc", HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ + {"sgo", HB_TAG_NONE }, /* Songa (retired code) != Sango */ /*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */ {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ - {"sgw", HB_TAG('S','G','W',' ')}, /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */ -/*{"shi", HB_TAG('S','H','I',' ')},*/ /* Tachelhit */ + {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ + {"shi", HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ + {"shl", HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ /*{"shn", HB_TAG('S','H','N',' ')},*/ /* Shan */ {"shu", HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ + {"shy", HB_TAG('B','B','R',' ')}, /* Tachawit -> Berber */ {"si", HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ + {"sib", HB_TAG_NONE }, /* Sebop != Sibe */ /*{"sid", HB_TAG('S','I','D',' ')},*/ /* Sidamo */ + {"sig", HB_TAG_NONE }, /* Paasaal != Silte Gurage */ + {"siz", HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */ {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ {"sjo", HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ + {"sjs", HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */ {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ {"skg", HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ {"skr", HB_TAG('S','R','K',' ')}, /* Saraiki */ + {"sks", HB_TAG_NONE }, /* Maia != Skolt Sami */ + {"skw", HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ + {"sky", HB_TAG_NONE }, /* Sikaiana != Slovak */ {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ + {"sla", HB_TAG_NONE }, /* Slavic [family] != Slavey */ {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ + {"sml", HB_TAG_NONE }, /* Central Sama != Somali */ {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ + {"smt", HB_TAG('Q','I','N',' ')}, /* Simte -> Chin */ {"sn", HB_TAG('S','N','A','0')}, /* Shona */ + {"snh", HB_TAG_NONE }, /* Shinabo (retired code) != Sinhala (Sinhalese) */ /*{"snk", HB_TAG('S','N','K',' ')},*/ /* Soninke */ {"so", HB_TAG('S','M','L',' ')}, /* Somali */ + {"sog", HB_TAG_NONE }, /* Sogdian != Sodo Gurage */ /*{"sop", HB_TAG('S','O','P',' ')},*/ /* Songe */ {"spv", HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ {"spy", HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ + {"srb", HB_TAG_NONE }, /* Sora != Serbian */ {"src", HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ + {"srk", HB_TAG_NONE }, /* Serudung Murut != Saraiki */ + {"srm", HB_TAG('C','P','P',' ')}, /* Saramaccan -> Creoles */ + {"srn", HB_TAG('C','P','P',' ')}, /* Sranan Tongo -> Creoles */ {"sro", HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ /*{"srr", HB_TAG('S','R','R',' ')},*/ /* Serer */ {"srs", HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ {"ssh", HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ - {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho -> Sotho, Southern */ + {"ssl", HB_TAG_NONE }, /* Western Sisaala != South Slavey */ + {"ssm", HB_TAG_NONE }, /* Semnam != Southern Sami */ + {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho */ + {"sta", HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */ /*{"stq", HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ /*{"suk", HB_TAG('S','U','K',' ')},*/ /* Sukuma */ {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ + {"sur", HB_TAG_NONE }, /* Mwaghavul != Suri */ {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ /*{"sva", HB_TAG('S','V','A',' ')},*/ /* Svan */ + {"svc", HB_TAG('C','P','P',' ')}, /* Vincentian Creole English -> Creoles */ + {"sve", HB_TAG_NONE }, /* Serili != Swedish */ {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ {"swb", HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ {"swc", HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ {"swh", HB_TAG('S','W','K',' ')}, /* Swahili */ + {"swk", HB_TAG_NONE }, /* Malawi Sena != Swahili */ + {"swn", HB_TAG('B','B','R',' ')}, /* Sawknah -> Berber */ {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ /*{"sxu", HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ @@ -904,11 +1371,16 @@ static const LangTag ot_languages[] = { {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ {"taa", HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ /*{"tab", HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ + {"taj", HB_TAG_NONE }, /* Eastern Tamang != Tajiki */ {"taq", HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ + {"taq", HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */ + {"tas", HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */ {"tau", HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ {"tcb", HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ {"tce", HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ + {"tch", HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */ {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ + {"tcs", HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */ {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ /*{"tdd", HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ @@ -917,41 +1389,70 @@ static const LangTag ot_languages[] = { {"tec", HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ {"tem", HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ /*{"tet", HB_TAG('T','E','T',' ')},*/ /* Tetum */ + {"tez", HB_TAG('B','B','R',' ')}, /* Tetserret -> Berber */ {"tfn", HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ {"tg", HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ + {"tgh", HB_TAG('C','P','P',' ')}, /* Tobagonian Creole English -> Creoles */ {"tgj", HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ + {"tgn", HB_TAG_NONE }, /* Tandaganon != Tongan */ + {"tgr", HB_TAG_NONE }, /* Tareng != Tigre */ {"tgx", HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ + {"tgy", HB_TAG_NONE }, /* Togoyo != Tigrinya */ {"th", HB_TAG('T','H','A',' ')}, /* Thai */ {"tht", HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ {"thv", HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ + {"thv", HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */ {"thz", HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ + {"thz", HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */ {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ + {"tia", HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ /*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */ + {"tjo", HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ + {"tkm", HB_TAG_NONE }, /* Takelma != Turkmen */ {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ -/*{"tmh", HB_TAG('T','M','H',' ')},*/ /* Tamashek [macrolanguage] */ + {"tmg", HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */ + {"tmh", HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */ + {"tmh", HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */ + {"tmn", HB_TAG_NONE }, /* Taman (Indonesia) != Temne */ {"tmw", HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ + {"tna", HB_TAG_NONE }, /* Tacana != Tswana */ + {"tne", HB_TAG_NONE }, /* Tinoc Kallahan (retired code) != Tundra Enets */ {"tnf", HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ + {"tnf", HB_TAG('F','A','R',' ')}, /* Tangshewi (retired code) -> Persian */ + {"tng", HB_TAG_NONE }, /* Tobanga != Tonga */ {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ {"tod", HB_TAG('T','O','D','0')}, /* Toma */ {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ + {"toj", HB_TAG('M','Y','N',' ')}, /* Tojolabal -> Mayan */ {"tol", HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ -/*{"tpi", HB_TAG('T','P','I',' ')},*/ /* Tok Pisin */ + {"tor", HB_TAG('B','A','D','0')}, /* Togbo-Vara Banda -> Banda */ + {"tpi", HB_TAG('T','P','I',' ')}, /* Tok Pisin */ + {"tpi", HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ + {"trf", HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ + {"trk", HB_TAG_NONE }, /* Turkic [family] != Turkish */ {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ + {"tsg", HB_TAG_NONE }, /* Tausug != Tsonga */ /*{"tsj", HB_TAG('T','S','J',' ')},*/ /* Tshangla */ {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ + {"ttc", HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */ {"ttm", HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ {"ttq", HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ + {"ttq", HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */ + {"tua", HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */ + {"tul", HB_TAG_NONE }, /* Tula != Tumbuka */ /*{"tum", HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ {"tuu", HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ + {"tuv", HB_TAG_NONE }, /* Turkana != Tuvin */ {"tuy", HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ /*{"tvl", HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ + {"tvy", HB_TAG('C','P','P',' ')}, /* Timor Pidgin -> Creoles */ {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ {"tw", HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ {"txc", HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ @@ -959,32 +1460,48 @@ static const LangTag ot_languages[] = { {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ /*{"tyz", HB_TAG('T','Y','Z',' ')},*/ /* Tày */ -/*{"tzm", HB_TAG('T','Z','M',' ')},*/ /* Central Atlas Tamazight -> Tamazight */ -/*{"tzo", HB_TAG('T','Z','O',' ')},*/ /* Tzotzil */ + {"tzh", HB_TAG('M','Y','N',' ')}, /* Tzeltal -> Mayan */ + {"tzj", HB_TAG('M','Y','N',' ')}, /* Tz'utujil -> Mayan */ + {"tzm", HB_TAG('T','Z','M',' ')}, /* Central Atlas Tamazight -> Tamazight */ + {"tzm", HB_TAG('B','B','R',' ')}, /* Central Atlas Tamazight -> Berber */ + {"tzo", HB_TAG('T','Z','O',' ')}, /* Tzotzil */ + {"tzo", HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */ {"ubl", HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ /*{"udm", HB_TAG('U','D','M',' ')},*/ /* Udmurt */ {"ug", HB_TAG('U','Y','G',' ')}, /* Uyghur */ {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ + {"uki", HB_TAG('K','U','I',' ')}, /* Kui (India) */ + {"uln", HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */ /*{"umb", HB_TAG('U','M','B',' ')},*/ /* Umbundu */ {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ {"urk", HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ + {"usp", HB_TAG('M','Y','N',' ')}, /* Uspanteco -> Mayan */ {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ + {"vap", HB_TAG('Q','I','N',' ')}, /* Vaiphei -> Chin */ {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ /*{"vec", HB_TAG('V','E','C',' ')},*/ /* Venetian */ {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ + {"vic", HB_TAG('C','P','P',' ')}, /* Virgin Islands Creole English -> Creoles */ + {"vit", HB_TAG_NONE }, /* Viti != Vietnamese */ {"vkk", HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ + {"vkp", HB_TAG('C','P','P',' ')}, /* Korlai Creole Portuguese -> Creoles */ {"vkt", HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ /*{"vro", HB_TAG('V','R','O',' ')},*/ /* Võro */ {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ + {"wag", HB_TAG_NONE }, /* Wa'ema != Wagdi */ /*{"war", HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ + {"wbr", HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */ + {"wea", HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */ + {"wes", HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */ + {"weu", HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */ {"wlc", HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ {"wle", HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ {"wlk", HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ @@ -993,45 +1510,58 @@ static const LangTag ot_languages[] = { {"wry", HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ {"wsg", HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ /*{"wtm", HB_TAG('W','T','M',' ')},*/ /* Mewati */ - {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese Simplified */ + {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */ {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ {"xal", HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ {"xan", HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ + {"xbd", HB_TAG_NONE }, /* Bindal != Lü */ {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ /*{"xjb", HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ /*{"xkf", HB_TAG('X','K','F',' ')},*/ /* Khengkha */ + {"xmg", HB_TAG('B','M','L',' ')}, /* Mengaka -> Bamileke */ {"xmm", HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ + {"xmm", HB_TAG('C','P','P',' ')}, /* Manado Malay -> Creoles */ {"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ {"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ - {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri */ + {"xnj", HB_TAG('S','X','T',' ')}, /* Ngoni (Tanzania) -> Sutu */ + {"xnq", HB_TAG('S','X','T',' ')}, /* Ngoni (Mozambique) -> Sutu */ + {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri (macrolanguage) */ /*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */ -/*{"xpe", HB_TAG('X','P','E',' ')},*/ /* Liberia Kpelle -> Kpelle (Liberia) */ + {"xpe", HB_TAG('X','P','E',' ')}, /* Liberia Kpelle -> Kpelle (Liberia) */ + {"xpe", HB_TAG('K','P','L',' ')}, /* Liberia Kpelle -> Kpelle */ {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ {"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ {"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ + {"xup", HB_TAG('A','T','H',' ')}, /* Upper Umpqua -> Athapaskan */ {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ + {"yaj", HB_TAG('B','A','D','0')}, /* Banda-Yangere -> Banda */ + {"yak", HB_TAG_NONE }, /* Yakama != Sakha */ /*{"yao", HB_TAG('Y','A','O',' ')},*/ /* Yao */ /*{"yap", HB_TAG('Y','A','P',' ')},*/ /* Yapese */ + {"yba", HB_TAG_NONE }, /* Yala != Yoruba */ + {"ybb", HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */ {"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ {"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ {"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ + {"yim", HB_TAG_NONE }, /* Yimchungru Naga != Yi Modern */ {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ {"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ - {"yrk", HB_TAG('T','N','E',' ')}, /* Nenets -> Tundra Nenets */ - {"yrk", HB_TAG('F','N','E',' ')}, /* Nenets -> Forest Nenets */ - {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Hong Kong SAR */ + {"yua", HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */ + {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */ {"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ {"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ {"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ /*{"zea", HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ {"zeh", HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {"zen", HB_TAG('B','B','R',' ')}, /* Zenaga -> Berber */ {"zgb", HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ -/*{"zgh", HB_TAG('Z','G','H',' ')},*/ /* Standard Moroccan Tamazight */ + {"zgh", HB_TAG('Z','G','H',' ')}, /* Standard Moroccan Tamazight */ + {"zgh", HB_TAG('B','B','R',' ')}, /* Standard Moroccan Tamazight -> Berber */ {"zgm", HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ {"zgn", HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ - {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese [macrolanguage] -> Chinese Simplified */ + {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese, Simplified [macrolanguage] */ {"zhd", HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ {"zhn", HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ {"zlj", HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ @@ -1039,6 +1569,8 @@ static const LangTag ot_languages[] = { {"zln", HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ + {"zmz", HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ + {"znd", HB_TAG_NONE }, /* Zande [family] != Zande */ {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ @@ -1049,6 +1581,7 @@ static const LangTag ot_languages[] = { {"zyg", HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ {"zyj", HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ {"zyn", HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ + {"zyp", HB_TAG('Q','I','N',' ')}, /* Zyphe Chin -> Chin */ /*{"zza", HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ {"zzj", HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ }; @@ -1087,6 +1620,13 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (subtag_matches (lang_str, limit, "-arevmda")) + { + /* Armenian; Western Armenian (retired code) */ + tags[0] = HB_TAG('H','Y','E',' '); /* Armenian */ + *count = 1; + return true; + } if (subtag_matches (lang_str, limit, "-provenc")) { /* Occitan (post 1500); Provençal */ @@ -1134,7 +1674,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'a': if (0 == strcmp (&lang_str[1], "rt-lojban")) { - /* Lojban */ + /* Lojban (retired code) */ tags[0] = HB_TAG('J','B','O',' '); /* Lojban */ *count = 1; return true; @@ -1143,169 +1683,273 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'c': if (lang_matches (&lang_str[1], "do-hant-hk")) { - /* Min Dong Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Min Dong Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "do-hant-mo")) { - /* Min Dong Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Min Dong Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "jy-hant-hk")) { - /* Jinyu Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Jinyu Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "jy-hant-mo")) { - /* Jinyu Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Jinyu Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "mn-hant-hk")) { - /* Mandarin Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Mandarin Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "mn-hant-mo")) { - /* Mandarin Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Mandarin Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (lang_matches (&lang_str[1], "np-hant-hk")) + { + /* Northern Ping Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } + if (lang_matches (&lang_str[1], "np-hant-mo")) + { + /* Northern Ping Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } if (lang_matches (&lang_str[1], "px-hant-hk")) { - /* Pu-Xian Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Pu-Xian Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "px-hant-mo")) { - /* Pu-Xian Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Pu-Xian Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (lang_matches (&lang_str[1], "sp-hant-hk")) + { + /* Southern Ping Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } + if (lang_matches (&lang_str[1], "sp-hant-mo")) + { + /* Southern Ping Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } if (lang_matches (&lang_str[1], "zh-hant-hk")) { - /* Huizhou Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Huizhou Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "zh-hant-mo")) { - /* Huizhou Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Huizhou Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "zo-hant-hk")) { - /* Min Zhong Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Min Zhong Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "zo-hant-mo")) { - /* Min Zhong Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Min Zhong Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "do-hans")) { - /* Min Dong Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Min Dong Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "do-hant")) { - /* Min Dong Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Min Dong Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "jy-hans")) { - /* Jinyu Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Jinyu Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "jy-hant")) { - /* Jinyu Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Jinyu Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "mn-hans")) { - /* Mandarin Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Mandarin Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "mn-hant")) { - /* Mandarin Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Mandarin Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hans")) + { + /* Northern Ping Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant")) + { + /* Northern Ping Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "px-hans")) { - /* Pu-Xian Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Pu-Xian Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "px-hant")) { - /* Pu-Xian Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Pu-Xian Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sp-hans")) + { + /* Southern Ping Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sp-hant")) + { + /* Southern Ping Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "zh-hans")) { - /* Huizhou Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Huizhou Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "zh-hant")) { - /* Huizhou Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Huizhou Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "zo-hans")) { - /* Min Zhong Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Min Zhong Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "zo-hant")) { - /* Min Zhong Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Min Zhong Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1313,7 +1957,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Min Dong Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1321,15 +1965,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Min Dong Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "do-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Min Dong Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1337,7 +1987,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Jinyu Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1345,15 +1995,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Jinyu Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "jy-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Jinyu Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1361,7 +2017,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Mandarin Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1369,15 +2025,51 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Mandarin Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "mn-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Mandarin Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Northern Ping Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Northern Ping Chinese; Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Northern Ping Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1385,7 +2077,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Pu-Xian Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1393,15 +2085,51 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Pu-Xian Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "px-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Pu-Xian Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sp-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Southern Ping Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sp-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Southern Ping Chinese; Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; + return true; + } + if (0 == strncmp (&lang_str[1], "sp-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Southern Ping Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1409,7 +2137,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Huizhou Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1417,15 +2145,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Huizhou Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "zh-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Huizhou Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1433,7 +2167,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Min Zhong Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1441,15 +2175,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Min Zhong Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "zo-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Min Zhong Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1457,35 +2197,41 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'g': if (lang_matches (&lang_str[1], "an-hant-hk")) { - /* Gan Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Gan Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "an-hant-mo")) { - /* Gan Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Gan Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "an-hans")) { - /* Gan Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Gan Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "an-hant")) { - /* Gan Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Gan Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "a-latg")) { - /* Irish */ + /* Irish; Latin (Gaelic variant) */ tags[0] = HB_TAG('I','R','T',' '); /* Irish Traditional */ *count = 1; return true; @@ -1494,7 +2240,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Gan Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1502,15 +2248,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Gan Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "an-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Gan Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1518,57 +2270,69 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'h': if (lang_matches (&lang_str[1], "ak-hant-hk")) { - /* Hakka Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Hakka Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "ak-hant-mo")) { - /* Hakka Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Hakka Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "sn-hant-hk")) { - /* Xiang Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Xiang Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "sn-hant-mo")) { - /* Xiang Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Xiang Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "ak-hans")) { - /* Hakka Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Hakka Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "ak-hant")) { - /* Hakka Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Hakka Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (lang_matches (&lang_str[1], "sn-hans")) { - /* Xiang Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Xiang Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "sn-hant")) { - /* Xiang Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Xiang Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1576,7 +2340,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Hakka Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1584,15 +2348,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Hakka Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "ak-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Hakka Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1600,7 +2370,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Xiang Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1608,15 +2378,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Xiang Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "sn-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Xiang Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1624,7 +2400,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'i': if (0 == strcmp (&lang_str[1], "-navajo")) { - /* Navajo */ + /* Navajo (retired code) */ unsigned int i; hb_tag_t possible_tags[] = { HB_TAG('N','A','V',' '), /* Navajo */ @@ -1637,14 +2413,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, } if (0 == strcmp (&lang_str[1], "-hak")) { - /* Hakka */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Hakka (retired code) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (0 == strcmp (&lang_str[1], "-lux")) { - /* Luxembourgish */ + /* Luxembourgish (retired code) */ tags[0] = HB_TAG('L','T','Z',' '); /* Luxembourgish */ *count = 1; return true; @@ -1653,8 +2429,8 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'l': if (lang_matches (&lang_str[1], "zh-hans")) { - /* Literary Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Literary Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } @@ -1662,29 +2438,35 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'm': if (lang_matches (&lang_str[1], "np-hant-hk")) { - /* Min Bei Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Min Bei Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "np-hant-mo")) { - /* Min Bei Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Min Bei Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "np-hans")) { - /* Min Bei Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Min Bei Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "np-hant")) { - /* Min Bei Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Min Bei Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1692,7 +2474,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Min Bei Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1700,15 +2482,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Min Bei Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "np-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Min Bei Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1716,29 +2504,35 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'n': if (lang_matches (&lang_str[1], "an-hant-hk")) { - /* Min Nan Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Min Nan Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "an-hant-mo")) { - /* Min Nan Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Min Nan Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "an-hans")) { - /* Min Nan Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Min Nan Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "an-hant")) { - /* Min Nan Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Min Nan Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1746,7 +2540,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Min Nan Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1754,30 +2548,42 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Min Nan Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "an-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Min Nan Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (0 == strcmp (&lang_str[1], "o-bok")) { - /* Norwegian Bokmal */ + /* Norwegian Bokmal (retired code) */ tags[0] = HB_TAG('N','O','R',' '); /* Norwegian */ *count = 1; return true; } if (0 == strcmp (&lang_str[1], "o-nyn")) { - /* Norwegian Nynorsk */ - tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - *count = 1; + /* Norwegian Nynorsk (retired code) */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('N','Y','N',' '), /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + HB_TAG('N','O','R',' '), /* Norwegian */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } break; @@ -1794,29 +2600,35 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'w': if (lang_matches (&lang_str[1], "uu-hant-hk")) { - /* Wu Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Wu Chinese; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "uu-hant-mo")) { - /* Wu Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Wu Chinese; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (lang_matches (&lang_str[1], "uu-hans")) { - /* Wu Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Wu Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "uu-hant")) { - /* Wu Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Wu Chinese; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1824,7 +2636,7 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-hk")) { /* Wu Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } @@ -1832,15 +2644,21 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-mo")) { /* Wu Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "uu-", 3) && subtag_matches (lang_str, limit, "-tw")) { /* Wu Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1848,8 +2666,8 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'y': if (lang_matches (&lang_str[1], "ue-hans")) { - /* Yue Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Yue Chinese; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } @@ -1857,67 +2675,79 @@ hb_ot_tags_from_complex_language (const char *lang_str, case 'z': if (lang_matches (&lang_str[1], "h-hant-hk")) { - /* Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Chinese [macrolanguage]; Han (Traditional variant); Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (lang_matches (&lang_str[1], "h-hant-mo")) { - /* Chinese */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Chinese [macrolanguage]; Han (Traditional variant); Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strcmp (&lang_str[1], "h-min-nan")) { - /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Minnan, Hokkien, Amoy, Taiwanese, Southern Min, Southern Fujian, Hoklo, Southern Fukien, Ho-lo (retired code) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "h-hans")) { - /* Chinese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Chinese [macrolanguage]; Han (Simplified variant) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (lang_matches (&lang_str[1], "h-hant")) { - /* Chinese */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Chinese [macrolanguage]; Han (Traditional variant) */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } if (0 == strcmp (&lang_str[1], "h-min")) { - /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese */ - tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + /* Min, Fuzhou, Hokkien, Amoy, or Taiwanese (retired code) */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese, Simplified */ *count = 1; return true; } if (0 == strncmp (&lang_str[1], "h-", 2) && subtag_matches (lang_str, limit, "-hk")) { - /* Chinese; Hong Kong */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + /* Chinese [macrolanguage]; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Traditional, Hong Kong SAR */ *count = 1; return true; } if (0 == strncmp (&lang_str[1], "h-", 2) && subtag_matches (lang_str, limit, "-mo")) { - /* Chinese; Macao */ - tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ - *count = 1; + /* Chinese [macrolanguage]; Macao */ + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('Z','H','T','M'), /* Chinese, Traditional, Macao SAR */ + HB_TAG('Z','H','H',' '), /* Chinese, Traditional, Hong Kong SAR */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } if (0 == strncmp (&lang_str[1], "h-", 2) && subtag_matches (lang_str, limit, "-tw")) { - /* Chinese; Taiwan, Province of China */ - tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + /* Chinese [macrolanguage]; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese, Traditional */ *count = 1; return true; } @@ -1948,97 +2778,131 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */ case HB_TAG('A','R','A',' '): /* Arabic */ - return hb_language_from_string ("ar", -1); /* Arabic */ + return hb_language_from_string ("ar", -1); /* Arabic [macrolanguage] */ case HB_TAG('A','R','K',' '): /* Rakhine */ return hb_language_from_string ("rki", -1); /* Rakhine */ case HB_TAG('A','T','H',' '): /* Athapaskan */ - return hb_language_from_string ("ath", -1); /* Athapascan */ + return hb_language_from_string ("ath", -1); /* Athapascan [family] */ + case HB_TAG('B','B','R',' '): /* Berber */ + return hb_language_from_string ("ber", -1); /* Berber [family] */ case HB_TAG('B','I','K',' '): /* Bikol */ - return hb_language_from_string ("bik", -1); /* Bikol */ + return hb_language_from_string ("bik", -1); /* Bikol [macrolanguage] */ + case HB_TAG('B','T','K',' '): /* Batak */ + return hb_language_from_string ("btk", -1); /* Batak [family] */ case HB_TAG('C','P','P',' '): /* Creoles */ - return hb_language_from_string ("crp", -1); /* Creoles and pidgins */ + return hb_language_from_string ("crp", -1); /* Creoles and pidgins [family] */ case HB_TAG('C','R','R',' '): /* Carrier */ return hb_language_from_string ("crx", -1); /* Carrier */ + case HB_TAG('D','G','R',' '): /* Dogri (macrolanguage) */ + return hb_language_from_string ("doi", -1); /* Dogri [macrolanguage] */ case HB_TAG('D','N','K',' '): /* Dinka */ - return hb_language_from_string ("din", -1); /* Dinka */ + return hb_language_from_string ("din", -1); /* Dinka [macrolanguage] */ case HB_TAG('D','R','I',' '): /* Dari */ return hb_language_from_string ("prs", -1); /* Dari */ case HB_TAG('D','Z','N',' '): /* Dzongkha */ return hb_language_from_string ("dz", -1); /* Dzongkha */ case HB_TAG('E','T','I',' '): /* Estonian */ - return hb_language_from_string ("et", -1); /* Estonian */ + return hb_language_from_string ("et", -1); /* Estonian [macrolanguage] */ + case HB_TAG('F','A','R',' '): /* Persian */ + return hb_language_from_string ("fa", -1); /* Persian [macrolanguage] */ case HB_TAG('G','O','N',' '): /* Gondi */ - return hb_language_from_string ("gon", -1); /* Gondi */ + return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */ case HB_TAG('H','M','N',' '): /* Hmong */ - return hb_language_from_string ("hmn", -1); /* Hmong */ + return hb_language_from_string ("hmn", -1); /* Hmong [macrolanguage] */ case HB_TAG('H','N','D',' '): /* Hindko */ return hb_language_from_string ("hnd", -1); /* Southern Hindko */ + case HB_TAG('H','Y','E',' '): /* Armenian */ + return hb_language_from_string ("hyw", -1); /* Western Armenian */ + case HB_TAG('I','B','A',' '): /* Iban */ + return hb_language_from_string ("iba", -1); /* Iban */ case HB_TAG('I','J','O',' '): /* Ijo */ - return hb_language_from_string ("ijo", -1); /* Ijo */ + return hb_language_from_string ("ijo", -1); /* Ijo [family] */ case HB_TAG('I','N','U',' '): /* Inuktitut */ - return hb_language_from_string ("iu", -1); /* Inuktitut */ + return hb_language_from_string ("iu", -1); /* Inuktitut [macrolanguage] */ case HB_TAG('I','P','K',' '): /* Inupiat */ - return hb_language_from_string ("ik", -1); /* Inupiaq */ + return hb_language_from_string ("ik", -1); /* Inupiaq [macrolanguage] */ case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */ return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */ case HB_TAG('I','R','T',' '): /* Irish Traditional */ return hb_language_from_string ("ga-Latg", -1); /* Irish; Latin (Gaelic variant) */ case HB_TAG('J','I','I',' '): /* Yiddish */ - return hb_language_from_string ("yi", -1); /* Yiddish */ + return hb_language_from_string ("yi", -1); /* Yiddish [macrolanguage] */ case HB_TAG('K','A','L',' '): /* Kalenjin */ - return hb_language_from_string ("kln", -1); /* Kalenjin */ + return hb_language_from_string ("kln", -1); /* Kalenjin [macrolanguage] */ case HB_TAG('K','G','E',' '): /* Khutsuri Georgian */ return hb_language_from_string ("und-Geok", -1); /* Undetermined; Khutsuri (Asomtavruli and Nuskhuri) */ case HB_TAG('K','N','R',' '): /* Kanuri */ - return hb_language_from_string ("kr", -1); /* Kanuri */ + return hb_language_from_string ("kr", -1); /* Kanuri [macrolanguage] */ + case HB_TAG('K','O','H',' '): /* Korean Old Hangul */ + return hb_language_from_string ("okm", -1); /* Middle Korean (10th-16th cent.) */ case HB_TAG('K','O','K',' '): /* Konkani */ - return hb_language_from_string ("kok", -1); /* Konkani */ + return hb_language_from_string ("kok", -1); /* Konkani [macrolanguage] */ + case HB_TAG('K','O','M',' '): /* Komi */ + return hb_language_from_string ("kv", -1); /* Komi [macrolanguage] */ + case HB_TAG('K','P','L',' '): /* Kpelle */ + return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */ + case HB_TAG('K','R','N',' '): /* Karen */ + return hb_language_from_string ("kar", -1); /* Karen [family] */ + case HB_TAG('K','U','I',' '): /* Kui */ + return hb_language_from_string ("uki", -1); /* Kui (India) */ case HB_TAG('K','U','R',' '): /* Kurdish */ - return hb_language_from_string ("ku", -1); /* Kurdish */ + return hb_language_from_string ("ku", -1); /* Kurdish [macrolanguage] */ case HB_TAG('L','U','H',' '): /* Luyia */ - return hb_language_from_string ("luy", -1); /* Luyia */ + return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */ case HB_TAG('L','V','I',' '): /* Latvian */ - return hb_language_from_string ("lv", -1); /* Latvian */ + return hb_language_from_string ("lv", -1); /* Latvian [macrolanguage] */ case HB_TAG('M','A','W',' '): /* Marwari */ - return hb_language_from_string ("mwr", -1); /* Marwari */ + return hb_language_from_string ("mwr", -1); /* Marwari [macrolanguage] */ case HB_TAG('M','L','G',' '): /* Malagasy */ - return hb_language_from_string ("mg", -1); /* Malagasy */ + return hb_language_from_string ("mg", -1); /* Malagasy [macrolanguage] */ case HB_TAG('M','L','Y',' '): /* Malay */ - return hb_language_from_string ("ms", -1); /* Malay */ + return hb_language_from_string ("ms", -1); /* Malay [macrolanguage] */ case HB_TAG('M','N','G',' '): /* Mongolian */ - return hb_language_from_string ("mn", -1); /* Mongolian */ + return hb_language_from_string ("mn", -1); /* Mongolian [macrolanguage] */ + case HB_TAG('M','N','K',' '): /* Maninka */ + return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */ case HB_TAG('M','O','L',' '): /* Moldavian */ return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */ + case HB_TAG('M','Y','N',' '): /* Mayan */ + return hb_language_from_string ("myn", -1); /* Mayan [family] */ + case HB_TAG('N','A','H',' '): /* Nahuatl */ + return hb_language_from_string ("nah", -1); /* Nahuatl [family] */ case HB_TAG('N','E','P',' '): /* Nepali */ - return hb_language_from_string ("ne", -1); /* Nepali */ + return hb_language_from_string ("ne", -1); /* Nepali [macrolanguage] */ case HB_TAG('N','I','S',' '): /* Nisi */ return hb_language_from_string ("njz", -1); /* Nyishi */ case HB_TAG('N','O','R',' '): /* Norwegian */ - return hb_language_from_string ("no", -1); /* Norwegian */ + return hb_language_from_string ("no", -1); /* Norwegian [macrolanguage] */ case HB_TAG('O','J','B',' '): /* Ojibway */ - return hb_language_from_string ("oj", -1); /* Ojibwa */ + return hb_language_from_string ("oj", -1); /* Ojibwa [macrolanguage] */ case HB_TAG('O','R','O',' '): /* Oromo */ - return hb_language_from_string ("om", -1); /* Oromo */ + return hb_language_from_string ("om", -1); /* Oromo [macrolanguage] */ case HB_TAG('P','A','S',' '): /* Pashto */ - return hb_language_from_string ("ps", -1); /* Pashto */ + return hb_language_from_string ("ps", -1); /* Pashto [macrolanguage] */ case HB_TAG('P','G','R',' '): /* Polytonic Greek */ return hb_language_from_string ("el-polyton", -1); /* Modern Greek (1453-); Polytonic Greek */ case HB_TAG('P','R','O',' '): /* Provençal / Old Provençal */ return hb_language_from_string ("pro", -1); /* Old Provençal (to 1500) */ case HB_TAG('Q','U','H',' '): /* Quechua (Bolivia) */ return hb_language_from_string ("quh", -1); /* South Bolivian Quechua */ + case HB_TAG('Q','U','Z',' '): /* Quechua */ + return hb_language_from_string ("qu", -1); /* Quechua [macrolanguage] */ case HB_TAG('Q','V','I',' '): /* Quechua (Ecuador) */ return hb_language_from_string ("qvi", -1); /* Imbabura Highland Quichua */ case HB_TAG('Q','W','H',' '): /* Quechua (Peru) */ return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */ case HB_TAG('R','A','J',' '): /* Rajasthani */ - return hb_language_from_string ("raj", -1); /* Rajasthani */ + return hb_language_from_string ("raj", -1); /* Rajasthani [macrolanguage] */ case HB_TAG('R','O','Y',' '): /* Romany */ - return hb_language_from_string ("rom", -1); /* Romany */ + return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */ case HB_TAG('S','Q','I',' '): /* Albanian */ - return hb_language_from_string ("sq", -1); /* Albanian */ + return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */ + case HB_TAG('S','R','B',' '): /* Serbian */ + return hb_language_from_string ("sr", -1); /* Serbian */ + case HB_TAG('S','X','T',' '): /* Sutu */ + return hb_language_from_string ("xnj", -1); /* Ngoni (Tanzania) */ case HB_TAG('S','Y','R',' '): /* Syriac */ - return hb_language_from_string ("syr", -1); /* Syriac */ + return hb_language_from_string ("syr", -1); /* Syriac [macrolanguage] */ case HB_TAG('S','Y','R','E'): /* Syriac, Estrangela script-variant (equivalent to ISO 15924 'Syre') */ return hb_language_from_string ("und-Syre", -1); /* Undetermined; Syriac (Estrangelo variant) */ case HB_TAG('S','Y','R','J'): /* Syriac, Western script-variant (equivalent to ISO 15924 'Syrj') */ @@ -2046,15 +2910,19 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('S','Y','R','N'): /* Syriac, Eastern script-variant (equivalent to ISO 15924 'Syrn') */ return hb_language_from_string ("und-Syrn", -1); /* Undetermined; Syriac (Eastern variant) */ case HB_TAG('T','M','H',' '): /* Tamashek */ - return hb_language_from_string ("tmh", -1); /* Tamashek */ - case HB_TAG('T','N','E',' '): /* Tundra Nenets */ - return hb_language_from_string ("yrk", -1); /* Nenets */ - case HB_TAG('Z','H','H',' '): /* Chinese, Hong Kong SAR */ - return hb_language_from_string ("zh-HK", -1); /* Chinese; Hong Kong */ - case HB_TAG('Z','H','S',' '): /* Chinese Simplified */ - return hb_language_from_string ("zh-Hans", -1); /* Chinese; Han (Simplified variant) */ - case HB_TAG('Z','H','T',' '): /* Chinese Traditional */ - return hb_language_from_string ("zh-Hant", -1); /* Chinese; Han (Traditional variant) */ + return hb_language_from_string ("tmh", -1); /* Tamashek [macrolanguage] */ + case HB_TAG('T','O','D',' '): /* Todo */ + return hb_language_from_string ("xwo", -1); /* Written Oirat */ + case HB_TAG('Z','H','H',' '): /* Chinese, Traditional, Hong Kong SAR */ + return hb_language_from_string ("zh-HK", -1); /* Chinese [macrolanguage]; Hong Kong */ + case HB_TAG('Z','H','S',' '): /* Chinese, Simplified */ + return hb_language_from_string ("zh-Hans", -1); /* Chinese [macrolanguage]; Han (Simplified variant) */ + case HB_TAG('Z','H','T',' '): /* Chinese, Traditional */ + return hb_language_from_string ("zh-Hant", -1); /* Chinese [macrolanguage]; Han (Traditional variant) */ + case HB_TAG('Z','H','T','M'): /* Chinese, Traditional, Macao SAR */ + return hb_language_from_string ("zh-MO", -1); /* Chinese [macrolanguage]; Macao */ + case HB_TAG('Z','Z','A',' '): /* Zazaki */ + return hb_language_from_string ("zza", -1); /* Zazaki [macrolanguage] */ default: return HB_LANGUAGE_INVALID; } diff --git a/src/hb-ot-tag.cc b/src/hb-ot-tag.cc index 8ad917ae7fd27fb9aa3f77ae2d88cbe4da2b456a..fc145a41f7969759abda20cb03cbbea36277c5d6 100644 --- a/src/hb-ot-tag.cc +++ b/src/hb-ot-tag.cc @@ -164,6 +164,15 @@ hb_ot_all_tags_from_script (hb_script_t script, *count = i; } +/** + * hb_ot_tag_to_script: + * @tag: a script tag + * + * Converts a script tag to an #hb_script_t. + * + * Return value: The #hb_script_t corresponding to @tag. + * + **/ hb_script_t hb_ot_tag_to_script (hb_tag_t tag) { @@ -280,6 +289,7 @@ hb_ot_tags_from_language (const char *lang_str, for (i = 0; i < *count && tag_idx + i < ARRAY_LENGTH (ot_languages) && + ot_languages[tag_idx + i].tag != HB_TAG_NONE && 0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language); i++) tags[i] = ot_languages[tag_idx + i].tag; @@ -319,12 +329,26 @@ parse_private_use_subtag (const char *private_use_subtag, char tag[4]; int i; s += strlen (prefix); - for (i = 0; i < 4 && ISALNUM (s[i]); i++) - tag[i] = normalize (s[i]); - if (!i) return false; - - for (; i < 4; i++) - tag[i] = ' '; + if (s[0] == '-') { + s += 1; + char c; + for (i = 0; i < 8 && ISHEX (s[i]); i++) + { + c = FROMHEX (s[i]); + if (i % 2 == 0) + tag[i / 2] = c << 4; + else + tag[i / 2] += c; + } + if (i != 8) return false; + } else { + for (i = 0; i < 4 && ISALNUM (s[i]); i++) + tag[i] = normalize (s[i]); + if (!i) return false; + + for (; i < 4; i++) + tag[i] = ' '; + } tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]); if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT) tags[0] ^= ~0xDFDFDFDF; @@ -336,13 +360,13 @@ parse_private_use_subtag (const char *private_use_subtag, * hb_ot_tags_from_script_and_language: * @script: an #hb_script_t to convert. * @language: an #hb_language_t to convert. - * @script_count: (allow-none): maximum number of script tags to retrieve (IN) + * @script_count: (inout) (optional): maximum number of script tags to retrieve (IN) * and actual number of script tags retrieved (OUT) - * @script_tags: (out) (allow-none): array of size at least @script_count to store the + * @script_tags: (out) (optional): array of size at least @script_count to store the * script tag results - * @language_count: (allow-none): maximum number of language tags to retrieve + * @language_count: (inout) (optional): maximum number of language tags to retrieve * (IN) and actual number of language tags retrieved (OUT) - * @language_tags: (out) (allow-none): array of size at least @language_count to store + * @language_tags: (out) (optional): array of size at least @language_count to store * the language tag results * * Converts an #hb_script_t and an #hb_language_t to script and language tags. @@ -409,10 +433,12 @@ hb_ot_tags_from_script_and_language (hb_script_t script, /** * hb_ot_tag_to_language: + * @tag: an language tag * + * Converts a language tag to an #hb_language_t. * - * - * Return value: (transfer none): + * Return value: (transfer none) (nullable): + * The #hb_language_t corresponding to @tag. * * Since: 0.9.2 **/ @@ -434,30 +460,28 @@ hb_ot_tag_to_language (hb_tag_t tag) if (ot_languages[i].tag == tag) return hb_language_from_string (ot_languages[i].language, -1); - /* If it's three letters long, assume it's ISO 639-3 and lower-case and use it - * (if it's not a registered tag, calling hb_ot_tag_from_language on the - * result might not return the same tag as the original tag). - * Else return a custom language in the form of "x-hbotABCD". */ + /* Return a custom language in the form of "x-hbot-AABBCCDD". + * If it's three letters long, also guess it's ISO 639-3 and lower-case and + * prepend it (if it's not a registered tag, the private use subtags will + * ensure that calling hb_ot_tag_from_language on the result will still return + * the same tag as the original tag). + */ { - char buf[11] = "x-hbot"; + char buf[20]; char *str = buf; - buf[6] = tag >> 24; - buf[7] = (tag >> 16) & 0xFF; - buf[8] = (tag >> 8) & 0xFF; - buf[9] = tag & 0xFF; - if (buf[9] == 0x20) + if (ISALPHA (tag >> 24) + && ISALPHA ((tag >> 16) & 0xFF) + && ISALPHA ((tag >> 8) & 0xFF) + && (tag & 0xFF) == ' ') { - buf[9] = '\0'; - if (ISALPHA (buf[6]) && ISALPHA (buf[7]) && ISALPHA (buf[8])) - { - buf[6] = TOLOWER (buf[6]); - buf[7] = TOLOWER (buf[7]); - buf[8] = TOLOWER (buf[8]); - str += 6; - } + buf[0] = TOLOWER (tag >> 24); + buf[1] = TOLOWER ((tag >> 16) & 0xFF); + buf[2] = TOLOWER ((tag >> 8) & 0xFF); + buf[3] = '-'; + str += 4; } - buf[10] = '\0'; - return hb_language_from_string (str, -1); + snprintf (str, 16, "x-hbot-%08x", tag); + return hb_language_from_string (&*buf, -1); } } @@ -465,9 +489,9 @@ hb_ot_tag_to_language (hb_tag_t tag) * hb_ot_tags_to_script_and_language: * @script_tag: a script tag * @language_tag: a language tag - * @script: (allow-none): the #hb_script_t corresponding to @script_tag (OUT). - * @language: (allow-none): the #hb_language_t corresponding to @script_tag and - * @language_tag (OUT). + * @script: (out) (optional): the #hb_script_t corresponding to @script_tag. + * @language: (out) (optional): the #hb_language_t corresponding to @script_tag and + * @language_tag. * * Converts a script tag and a language tag to an #hb_script_t and an * #hb_language_t. @@ -498,13 +522,14 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, unsigned char *buf; const char *lang_str = hb_language_to_string (*language); size_t len = strlen (lang_str); - buf = (unsigned char *) malloc (len + 11); + buf = (unsigned char *) malloc (len + 16); if (unlikely (!buf)) { *language = nullptr; } else { + int shift; memcpy (buf, lang_str, len); if (lang_str[0] != 'x' || lang_str[1] != '-') { buf[len++] = '-'; @@ -515,10 +540,9 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, buf[len++] = 'b'; buf[len++] = 's'; buf[len++] = 'c'; - buf[len++] = script_tag >> 24; - buf[len++] = (script_tag >> 16) & 0xFF; - buf[len++] = (script_tag >> 8) & 0xFF; - buf[len++] = script_tag & 0xFF; + buf[len++] = '-'; + for (shift = 28; shift >= 0; shift -= 4) + buf[len++] = TOHEX (script_tag >> shift); *language = hb_language_from_string ((char *) buf, len); free (buf); } diff --git a/src/hb-ot-var-avar-table.hh b/src/hb-ot-var-avar-table.hh index 45f702dbd9e829f0c522dd3a7864d3468cf98ae0..65f26c1d22dd76d54575b65e241f29f551f45d79 100644 --- a/src/hb-ot-var-avar-table.hh +++ b/src/hb-ot-var-avar-table.hh @@ -51,14 +51,14 @@ struct AxisValueMap public: F2DOT14 coords[2]; // F2DOT14 fromCoord; /* A normalized coordinate value obtained using -// * default normalization. */ +// * default normalization. */ // F2DOT14 toCoord; /* The modified, normalized coordinate value. */ public: DEFINE_SIZE_STATIC (4); }; -struct SegmentMaps : ArrayOf +struct SegmentMaps : Array16Of { int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const { @@ -79,7 +79,7 @@ struct SegmentMaps : ArrayOf return value - arrayZ[0].fromCoord + arrayZ[0].toCoord; unsigned int i; - unsigned int count = len; + unsigned int count = len - 1; for (i = 1; i < count && value > arrayZ[i].fromCoord; i++) ; @@ -90,9 +90,8 @@ struct SegmentMaps : ArrayOf return arrayZ[i-1].toCoord; int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord; - return arrayZ[i-1].toCoord + - ((arrayZ[i].toCoord - arrayZ[i-1].toCoord) * - (value - arrayZ[i-1].fromCoord) + denom/2) / denom; + return roundf (arrayZ[i-1].toCoord + ((float) (arrayZ[i].toCoord - arrayZ[i-1].toCoord) * + (value - arrayZ[i-1].fromCoord)) / denom); #undef toCoord #undef fromCoord } @@ -120,7 +119,7 @@ struct avar for (unsigned int i = 0; i < count; i++) { if (unlikely (!map->sanitize (c))) - return_trace (false); + return_trace (false); map = &StructAfter (*map); } diff --git a/src/hb-ot-var-fvar-table.hh b/src/hb-ot-var-fvar-table.hh index f1d024560e54634cb9e5855fd3a3d5ffedbc7b51..ceacb4f256e3c5b599d77c6c78990cfc36fbc9fa 100644 --- a/src/hb-ot-var-fvar-table.hh +++ b/src/hb-ot-var-fvar-table.hh @@ -44,7 +44,7 @@ struct InstanceRecord { friend struct fvar; - hb_array_t get_coordinates (unsigned int axis_count) const + hb_array_t get_coordinates (unsigned int axis_count) const { return coordinatesZ.as_array (axis_count); } bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const @@ -58,7 +58,7 @@ struct InstanceRecord NameID subfamilyNameID;/* The name ID for entries in the 'name' table * that provide subfamily names for this instance. */ HBUINT16 flags; /* Reserved for future use — set to 0. */ - UnsizedArrayOf + UnsizedArrayOf coordinatesZ; /* The coordinates array for this instance. */ //NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name' // * table that provide PostScript names for this @@ -70,22 +70,83 @@ struct InstanceRecord struct AxisRecord { + int cmp (hb_tag_t key) const { return axisTag.cmp (key); } + enum { AXIS_FLAG_HIDDEN = 0x0001, }; +#ifndef HB_DISABLE_DEPRECATED + void get_axis_deprecated (hb_ot_var_axis_t *info) const + { + info->tag = axisTag; + info->name_id = axisNameID; + get_coordinates (info->min_value, info->default_value, info->max_value); + } +#endif + + void get_axis_info (unsigned axis_index, hb_ot_var_axis_info_t *info) const + { + info->axis_index = axis_index; + info->tag = axisTag; + info->name_id = axisNameID; + info->flags = (hb_ot_var_axis_flags_t) (unsigned int) flags; + get_coordinates (info->min_value, info->default_value, info->max_value); + info->reserved = 0; + } + + int normalize_axis_value (float v) const + { + float min_value, default_value, max_value; + get_coordinates (min_value, default_value, max_value); + + v = hb_clamp (v, min_value, max_value); + + if (v == default_value) + return 0; + else if (v < default_value) + v = (v - default_value) / (default_value - min_value); + else + v = (v - default_value) / (max_value - default_value); + return roundf (v * 16384.f); + } + + float unnormalize_axis_value (int v) const + { + float min_value, default_value, max_value; + get_coordinates (min_value, default_value, max_value); + + if (v == 0) + return default_value; + else if (v < 0) + return v * (default_value - min_value) / 16384.f + default_value; + else + return v * (max_value - default_value) / 16384.f + default_value; + } + + hb_ot_name_id_t get_name_id () const { return axisNameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - public: + protected: + void get_coordinates (float &min, float &default_, float &max) const + { + default_ = defaultValue / 65536.f; + /* Ensure order, to simplify client math. */ + min = hb_min (default_, minValue / 65536.f); + max = hb_max (default_, maxValue / 65536.f); + } + + protected: Tag axisTag; /* Tag identifying the design variation for the axis. */ - Fixed minValue; /* The minimum coordinate value for the axis. */ - Fixed defaultValue; /* The default coordinate value for the axis. */ - Fixed maxValue; /* The maximum coordinate value for the axis. */ + HBFixed minValue; /* The minimum coordinate value for the axis. */ + HBFixed defaultValue; /* The default coordinate value for the axis. */ + HBFixed maxValue; /* The maximum coordinate value for the axis. */ HBUINT16 flags; /* Axis flags. */ NameID axisNameID; /* The name ID for entries in the 'name' table that * provide a display name for this axis. */ @@ -114,35 +175,6 @@ struct fvar unsigned int get_axis_count () const { return axisCount; } -#ifndef HB_DISABLE_DEPRECATED - void get_axis_deprecated (unsigned int axis_index, - hb_ot_var_axis_t *info) const - { - const AxisRecord &axis = get_axes ()[axis_index]; - info->tag = axis.axisTag; - info->name_id = axis.axisNameID; - info->default_value = axis.defaultValue / 65536.f; - /* Ensure order, to simplify client math. */ - info->min_value = hb_min (info->default_value, axis.minValue / 65536.f); - info->max_value = hb_max (info->default_value, axis.maxValue / 65536.f); - } -#endif - - void get_axis_info (unsigned int axis_index, - hb_ot_var_axis_info_t *info) const - { - const AxisRecord &axis = get_axes ()[axis_index]; - info->axis_index = axis_index; - info->tag = axis.axisTag; - info->name_id = axis.axisNameID; - info->flags = (hb_ot_var_axis_flags_t) (unsigned int) axis.flags; - info->default_value = axis.defaultValue / 65536.f; - /* Ensure order, to simplify client math. */ - info->min_value = hb_min (info->default_value, axis.minValue / 65536.f); - info->max_value = hb_max (info->default_value, axis.maxValue / 65536.f); - info->reserved = 0; - } - #ifndef HB_DISABLE_DEPRECATED unsigned int get_axes_deprecated (unsigned int start_offset, unsigned int *axes_count /* IN/OUT */, @@ -150,18 +182,9 @@ struct fvar { if (axes_count) { - /* TODO Rewrite as hb_array_t<>::sub-array() */ - unsigned int count = axisCount; - start_offset = hb_min (start_offset, count); - - count -= start_offset; - axes_array += start_offset; - - count = hb_min (count, *axes_count); - *axes_count = count; - - for (unsigned int i = 0; i < count; i++) - get_axis_deprecated (start_offset + i, axes_array + i); + hb_array_t arr = get_axes ().sub_array (start_offset, axes_count); + for (unsigned i = 0; i < arr.length; ++i) + arr[i].get_axis_deprecated (&axes_array[i]); } return axisCount; } @@ -173,86 +196,38 @@ struct fvar { if (axes_count) { - /* TODO Rewrite as hb_array_t<>::sub-array() */ - unsigned int count = axisCount; - start_offset = hb_min (start_offset, count); - - count -= start_offset; - axes_array += start_offset; - - count = hb_min (count, *axes_count); - *axes_count = count; - - for (unsigned int i = 0; i < count; i++) - get_axis_info (start_offset + i, axes_array + i); + hb_array_t arr = get_axes ().sub_array (start_offset, axes_count); + for (unsigned i = 0; i < arr.length; ++i) + arr[i].get_axis_info (start_offset + i, &axes_array[i]); } return axisCount; } #ifndef HB_DISABLE_DEPRECATED - bool find_axis_deprecated (hb_tag_t tag, - unsigned int *axis_index, - hb_ot_var_axis_t *info) const + bool + find_axis_deprecated (hb_tag_t tag, unsigned *axis_index, hb_ot_var_axis_t *info) const { - const AxisRecord *axes = get_axes (); - unsigned int count = get_axis_count (); - for (unsigned int i = 0; i < count; i++) - if (axes[i].axisTag == tag) - { - if (axis_index) - *axis_index = i; - get_axis_deprecated (i, info); - return true; - } - if (axis_index) - *axis_index = HB_OT_VAR_NO_AXIS_INDEX; - return false; + unsigned i; + if (!axis_index) axis_index = &i; + *axis_index = HB_OT_VAR_NO_AXIS_INDEX; + auto axes = get_axes (); + return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true); } #endif - bool find_axis_info (hb_tag_t tag, - hb_ot_var_axis_info_t *info) const + bool + find_axis_info (hb_tag_t tag, hb_ot_var_axis_info_t *info) const { - const AxisRecord *axes = get_axes (); - unsigned int count = get_axis_count (); - for (unsigned int i = 0; i < count; i++) - if (axes[i].axisTag == tag) - { - get_axis_info (i, info); - return true; - } - return false; + unsigned i; + auto axes = get_axes (); + return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true); } int normalize_axis_value (unsigned int axis_index, float v) const - { - hb_ot_var_axis_info_t axis; - get_axis_info (axis_index, &axis); - - v = hb_max (hb_min (v, axis.max_value), axis.min_value); /* Clamp. */ - - if (v == axis.default_value) - return 0; - else if (v < axis.default_value) - v = (v - axis.default_value) / (axis.default_value - axis.min_value); - else - v = (v - axis.default_value) / (axis.max_value - axis.default_value); - return roundf (v * 16384.f); - } - - float unnormalize_axis_value (unsigned int axis_index, float v) const - { - hb_ot_var_axis_info_t axis; - get_axis_info (axis_index, &axis); + { return get_axes ()[axis_index].normalize_axis_value (v); } - if (v == 0) - return axis.default_value; - else if (v < 0) - v = v * (axis.default_value - axis.min_value) / 16384.f + axis.default_value; - else - v = v * (axis.max_value - axis.default_value) / 16384.f + axis.default_value; - return v; - } + float unnormalize_axis_value (unsigned int axis_index, int v) const + { return get_axes ()[axis_index].unnormalize_axis_value (v); } unsigned int get_instance_count () const { return instanceCount; } @@ -280,16 +255,16 @@ struct fvar if (unlikely (!instance)) { if (coords_length) - *coords_length = 0; + *coords_length = 0; return 0; } if (coords_length && *coords_length) { - hb_array_t instanceCoords = instance->get_coordinates (axisCount) + hb_array_t instanceCoords = instance->get_coordinates (axisCount) .sub_array (0, *coords_length); for (unsigned int i = 0; i < instanceCoords.length; i++) - coords[i] = instanceCoords.arrayZ[i].to_float (); + coords[i] = instanceCoords.arrayZ[i].to_float (); } return axisCount; } @@ -299,7 +274,7 @@ struct fvar if (!has_data ()) return; + get_axes () - | hb_map (&AxisRecord::axisNameID) + | hb_map (&AxisRecord::get_name_id) | hb_sink (nameids) ; @@ -314,7 +289,6 @@ struct fvar ; } - protected: hb_array_t get_axes () const { return hb_array (&(this+firstAxis), axisCount); } @@ -329,7 +303,7 @@ struct fvar protected: FixedVersion<>version; /* Version of the fvar table * initially set to 0x00010000u */ - OffsetTo + Offset16To firstAxis; /* Offset in bytes from the beginning of the table * to the start of the AxisRecord array. */ HBUINT16 reserved; /* This field is permanently reserved. Set to 2. */ @@ -340,8 +314,8 @@ struct fvar HBUINT16 instanceCount; /* The number of named instances defined in the font * (the number of records in the instances array). */ HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set - * to either axisCount * sizeof(Fixed) + 4, or to - * axisCount * sizeof(Fixed) + 6. */ + * to either axisCount * sizeof(HBFixed) + 4, or to + * axisCount * sizeof(HBFixed) + 6. */ public: DEFINE_SIZE_STATIC (16); diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh new file mode 100644 index 0000000000000000000000000000000000000000..157dfd7a5da9b37163e5858701ddffefa1fb4e2a --- /dev/null +++ b/src/hb-ot-var-gvar-table.hh @@ -0,0 +1,701 @@ +/* + * Copyright © 2019 Adobe Inc. + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_VAR_GVAR_TABLE_HH +#define HB_OT_VAR_GVAR_TABLE_HH + +#include "hb-open-type.hh" + +/* + * gvar -- Glyph Variation Table + * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar + */ +#define HB_OT_TAG_gvar HB_TAG('g','v','a','r') + +namespace OT { + +struct contour_point_t +{ + void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false) + { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } + + void translate (const contour_point_t &p) { x += p.x; y += p.y; } + + uint8_t flag; + float x, y; + bool is_end_point; +}; + +struct contour_point_vector_t : hb_vector_t +{ + void extend (const hb_array_t &a) + { + unsigned int old_len = length; + resize (old_len + a.length); + for (unsigned int i = 0; i < a.length; i++) + (*this)[old_len + i] = a[i]; + } + + void transform (const float (&matrix)[4]) + { + for (unsigned int i = 0; i < length; i++) + { + contour_point_t &p = (*this)[i]; + float x_ = p.x * matrix[0] + p.y * matrix[2]; + p.y = p.x * matrix[1] + p.y * matrix[3]; + p.x = x_; + } + } + + void translate (const contour_point_t& delta) + { + for (unsigned int i = 0; i < length; i++) + (*this)[i].translate (delta); + } +}; + +/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */ +struct TupleVariationHeader +{ + unsigned get_size (unsigned axis_count) const + { return min_size + get_all_tuples (axis_count).get_size (); } + + unsigned get_data_size () const { return varDataSize; } + + const TupleVariationHeader &get_next (unsigned axis_count) const + { return StructAtOffset (this, get_size (axis_count)); } + + float calculate_scalar (const int *coords, unsigned int coord_count, + const hb_array_t shared_tuples) const + { + hb_array_t peak_tuple; + + if (has_peak ()) + peak_tuple = get_peak_tuple (coord_count); + else + { + unsigned int index = get_index (); + if (unlikely (index * coord_count >= shared_tuples.length)) + return 0.f; + peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count); + } + + hb_array_t start_tuple; + hb_array_t end_tuple; + if (has_intermediate ()) + { + start_tuple = get_start_tuple (coord_count); + end_tuple = get_end_tuple (coord_count); + } + + float scalar = 1.f; + for (unsigned int i = 0; i < coord_count; i++) + { + int v = coords[i]; + int peak = peak_tuple[i]; + if (!peak || v == peak) continue; + + if (has_intermediate ()) + { + int start = start_tuple[i]; + int end = end_tuple[i]; + if (unlikely (start > peak || peak > end || + (start < 0 && end > 0 && peak))) continue; + if (v < start || v > end) return 0.f; + if (v < peak) + { if (peak != start) scalar *= (float) (v - start) / (peak - start); } + else + { if (peak != end) scalar *= (float) (end - v) / (end - peak); } + } + else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f; + else + scalar *= (float) v / peak; + } + return scalar; + } + + bool has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; } + bool has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; } + bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; } + unsigned get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; } + + protected: + struct TuppleIndex : HBUINT16 + { + enum Flags { + EmbeddedPeakTuple = 0x8000u, + IntermediateRegion = 0x4000u, + PrivatePointNumbers = 0x2000u, + TupleIndexMask = 0x0FFFu + }; + + DEFINE_SIZE_STATIC (2); + }; + + hb_array_t get_all_tuples (unsigned axis_count) const + { return StructAfter> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); } + hb_array_t get_peak_tuple (unsigned axis_count) const + { return get_all_tuples (axis_count).sub_array (0, axis_count); } + hb_array_t get_start_tuple (unsigned axis_count) const + { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); } + hb_array_t get_end_tuple (unsigned axis_count) const + { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); } + + HBUINT16 varDataSize; /* The size in bytes of the serialized + * data for this tuple variation table. */ + TuppleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below). + The low 12 bits are an index into a shared tuple + records array. */ + /* UnsizedArrayOf peakTuple - optional */ + /* Peak tuple record for this tuple variation table — optional, + * determined by flags in the tupleIndex value. + * + * Note that this must always be included in the 'cvar' table. */ + /* UnsizedArrayOf intermediateStartTuple - optional */ + /* Intermediate start tuple record for this tuple variation table — optional, + determined by flags in the tupleIndex value. */ + /* UnsizedArrayOf intermediateEndTuple - optional */ + /* Intermediate end tuple record for this tuple variation table — optional, + * determined by flags in the tupleIndex value. */ + public: + DEFINE_SIZE_MIN (4); +}; + +struct GlyphVariationData +{ + const TupleVariationHeader &get_tuple_var_header (void) const + { return StructAfter (data); } + + struct tuple_iterator_t + { + void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_) + { + var_data_bytes = var_data_bytes_; + var_data = var_data_bytes_.as (); + index = 0; + axis_count = axis_count_; + current_tuple = &var_data->get_tuple_var_header (); + data_offset = 0; + } + + bool get_shared_indices (hb_vector_t &shared_indices /* OUT */) + { + if (var_data->has_shared_point_numbers ()) + { + const HBUINT8 *base = &(var_data+var_data->data); + const HBUINT8 *p = base; + if (!unpack_points (p, shared_indices, var_data_bytes)) return false; + data_offset = p - base; + } + return true; + } + + bool is_valid () const + { + return (index < var_data->tupleVarCount.get_count ()) && + var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) && + var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) && + current_tuple->get_size (axis_count); + } + + bool move_to_next () + { + data_offset += current_tuple->get_data_size (); + current_tuple = ¤t_tuple->get_next (axis_count); + index++; + return is_valid (); + } + + const HBUINT8 *get_serialized_data () const + { return &(var_data+var_data->data) + data_offset; } + + private: + const GlyphVariationData *var_data; + unsigned int index; + unsigned int axis_count; + unsigned int data_offset; + + public: + hb_bytes_t var_data_bytes; + const TupleVariationHeader *current_tuple; + }; + + static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count, + hb_vector_t &shared_indices /* OUT */, + tuple_iterator_t *iterator /* OUT */) + { + iterator->init (var_data_bytes, axis_count); + if (!iterator->get_shared_indices (shared_indices)) + return false; + return iterator->is_valid (); + } + + bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); } + + static bool unpack_points (const HBUINT8 *&p /* IN/OUT */, + hb_vector_t &points /* OUT */, + const hb_bytes_t &bytes) + { + enum packed_point_flag_t + { + POINTS_ARE_WORDS = 0x80, + POINT_RUN_COUNT_MASK = 0x7F + }; + + if (unlikely (!bytes.check_range (p))) return false; + + uint16_t count = *p++; + if (count & POINTS_ARE_WORDS) + { + if (unlikely (!bytes.check_range (p))) return false; + count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++; + } + points.resize (count); + + unsigned int n = 0; + uint16_t i = 0; + while (i < count) + { + if (unlikely (!bytes.check_range (p))) return false; + uint16_t j; + uint8_t control = *p++; + uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1; + if (control & POINTS_ARE_WORDS) + { + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) + return false; + n += *(const HBUINT16 *)p; + points[i] = n; + p += HBUINT16::static_size; + } + } + else + { + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range (p))) return false; + n += *p++; + points[i] = n; + } + } + if (j < run_count) return false; + } + return true; + } + + static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */, + hb_vector_t &deltas /* IN/OUT */, + const hb_bytes_t &bytes) + { + enum packed_delta_flag_t + { + DELTAS_ARE_ZERO = 0x80, + DELTAS_ARE_WORDS = 0x40, + DELTA_RUN_COUNT_MASK = 0x3F + }; + + unsigned int i = 0; + unsigned int count = deltas.length; + while (i < count) + { + if (unlikely (!bytes.check_range (p))) return false; + uint8_t control = *p++; + unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1; + unsigned int j; + if (control & DELTAS_ARE_ZERO) + for (j = 0; j < run_count && i < count; j++, i++) + deltas[i] = 0; + else if (control & DELTAS_ARE_WORDS) + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) + return false; + deltas[i] = *(const HBINT16 *) p; + p += HBUINT16::static_size; + } + else + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range (p))) + return false; + deltas[i] = *(const HBINT8 *) p++; + } + if (j < run_count) + return false; + } + return true; + } + + bool has_data () const { return tupleVarCount; } + + protected: + struct TupleVarCount : HBUINT16 + { + bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); } + unsigned int get_count () const { return (*this) & CountMask; } + + protected: + enum Flags + { + SharedPointNumbers= 0x8000u, + CountMask = 0x0FFFu + }; + public: + DEFINE_SIZE_STATIC (2); + }; + + TupleVarCount tupleVarCount; /* A packed field. The high 4 bits are flags, and the + * low 12 bits are the number of tuple variation tables + * for this glyph. The number of tuple variation tables + * can be any number between 1 and 4095. */ + Offset16To + data; /* Offset from the start of the GlyphVariationData table + * to the serialized data. */ + /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */ + public: + DEFINE_SIZE_MIN (4); +}; + +struct gvar +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar; + + bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && (version.major == 1) && + (glyphCount == c->get_num_glyphs ()) && + sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) && + (is_long_offset () ? + c->check_array (get_long_offset_array (), glyphCount+1) : + c->check_array (get_short_offset_array (), glyphCount+1)) && + c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0), + get_offset (glyphCount) - get_offset (0))); + } + + /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */ + bool sanitize (hb_sanitize_context_t *c) const + { return sanitize_shallow (c); } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + gvar *out = c->serializer->allocate_min (); + if (unlikely (!out)) return_trace (false); + + out->version.major = 1; + out->version.minor = 0; + out->axisCount = axisCount; + out->sharedTupleCount = sharedTupleCount; + + unsigned int num_glyphs = c->plan->num_output_glyphs (); + out->glyphCount = num_glyphs; + + unsigned int subset_data_size = 0; + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue; + subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length; + } + + bool long_offset = subset_data_size & ~0xFFFFu; + out->flags = long_offset ? 1 : 0; + + HBUINT8 *subset_offsets = c->serializer->allocate_size ((long_offset ? 4 : 2) * (num_glyphs + 1)); + if (!subset_offsets) return_trace (false); + + /* shared tuples */ + if (!sharedTupleCount || !sharedTuples) + out->sharedTuples = 0; + else + { + unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount; + F2DOT14 *tuples = c->serializer->allocate_size (shared_tuple_size); + if (!tuples) return_trace (false); + out->sharedTuples = (char *) tuples - (char *) out; + memcpy (tuples, this+sharedTuples, shared_tuple_size); + } + + char *subset_data = c->serializer->allocate_size (subset_data_size); + if (!subset_data) return_trace (false); + out->dataZ = subset_data - (char *) out; + + unsigned int glyph_offset = 0; + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t old_gid; + hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid) + ? get_glyph_var_data_bytes (c->source_blob, old_gid) + : hb_bytes_t (); + + if (long_offset) + ((HBUINT32 *) subset_offsets)[gid] = glyph_offset; + else + ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2; + + if (var_data_bytes.length > 0) + memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length); + subset_data += var_data_bytes.length; + glyph_offset += var_data_bytes.length; + } + if (long_offset) + ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset; + else + ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2; + + return_trace (true); + } + + protected: + const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const + { + unsigned start_offset = get_offset (glyph); + unsigned length = get_offset (glyph+1) - start_offset; + hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length); + return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); + } + + bool is_long_offset () const { return flags & 1; } + + unsigned get_offset (unsigned i) const + { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; } + + const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; } + const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; } + + public: + struct accelerator_t + { + void init (hb_face_t *face) + { table = hb_sanitize_context_t ().reference_table (face); } + void fini () { table.destroy (); } + + private: + struct x_getter { static float get (const contour_point_t &p) { return p.x; } }; + struct y_getter { static float get (const contour_point_t &p) { return p.y; } }; + + template + static float infer_delta (const hb_array_t points, + const hb_array_t deltas, + unsigned int target, unsigned int prev, unsigned int next) + { + float target_val = T::get (points[target]); + float prev_val = T::get (points[prev]); + float next_val = T::get (points[next]); + float prev_delta = T::get (deltas[prev]); + float next_delta = T::get (deltas[next]); + + if (prev_val == next_val) + return (prev_delta == next_delta) ? prev_delta : 0.f; + else if (target_val <= hb_min (prev_val, next_val)) + return (prev_val < next_val) ? prev_delta : next_delta; + else if (target_val >= hb_max (prev_val, next_val)) + return (prev_val > next_val) ? prev_delta : next_delta; + + /* linear interpolation */ + float r = (target_val - prev_val) / (next_val - prev_val); + return (1.f - r) * prev_delta + r * next_delta; + } + + static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end) + { return (i >= end) ? start : (i + 1); } + + public: + bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font, + const hb_array_t points) const + { + /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */ + if (!font->num_coords || font->num_coords != table->axisCount) return true; + + if (unlikely (glyph >= table->glyphCount)) return true; + + hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph); + if (!var_data_bytes.as ()->has_data ()) return true; + hb_vector_t shared_indices; + GlyphVariationData::tuple_iterator_t iterator; + if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount, + shared_indices, &iterator)) + return true; /* so isn't applied at all */ + + /* Save original points for inferred delta calculation */ + contour_point_vector_t orig_points; + orig_points.resize (points.length); + for (unsigned int i = 0; i < orig_points.length; i++) + orig_points[i] = points[i]; + + contour_point_vector_t deltas; /* flag is used to indicate referenced point */ + deltas.resize (points.length); + + hb_vector_t end_points; + for (unsigned i = 0; i < points.length; ++i) + if (points[i].is_end_point) + end_points.push (i); + + int *coords = font->coords; + unsigned num_coords = font->num_coords; + hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); + do + { + float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples); + if (scalar == 0.f) continue; + const HBUINT8 *p = iterator.get_serialized_data (); + unsigned int length = iterator.current_tuple->get_data_size (); + if (unlikely (!iterator.var_data_bytes.check_range (p, length))) + return false; + + hb_bytes_t bytes ((const char *) p, length); + hb_vector_t private_indices; + if (iterator.current_tuple->has_private_points () && + !GlyphVariationData::unpack_points (p, private_indices, bytes)) + return false; + const hb_array_t &indices = private_indices.length ? private_indices : shared_indices; + + bool apply_to_all = (indices.length == 0); + unsigned int num_deltas = apply_to_all ? points.length : indices.length; + hb_vector_t x_deltas; + x_deltas.resize (num_deltas); + if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes)) + return false; + hb_vector_t y_deltas; + y_deltas.resize (num_deltas); + if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes)) + return false; + + for (unsigned int i = 0; i < deltas.length; i++) + deltas[i].init (); + for (unsigned int i = 0; i < num_deltas; i++) + { + unsigned int pt_index = apply_to_all ? i : indices[i]; + deltas[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */ + deltas[pt_index].x += x_deltas[i] * scalar; + deltas[pt_index].y += y_deltas[i] * scalar; + } + + /* infer deltas for unreferenced points */ + unsigned start_point = 0; + for (unsigned c = 0; c < end_points.length; c++) + { + unsigned end_point = end_points[c]; + + /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */ + unsigned unref_count = 0; + for (unsigned i = start_point; i <= end_point; i++) + if (!deltas[i].flag) unref_count++; + + unsigned j = start_point; + if (unref_count == 0 || unref_count > end_point - start_point) + goto no_more_gaps; + + for (;;) + { + /* Locate the next gap of unreferenced points between two referenced points prev and next. + * Note that a gap may wrap around at left (start_point) and/or at right (end_point). + */ + unsigned int prev, next, i; + for (;;) + { + i = j; + j = next_index (i, start_point, end_point); + if (deltas[i].flag && !deltas[j].flag) break; + } + prev = j = i; + for (;;) + { + i = j; + j = next_index (i, start_point, end_point); + if (!deltas[i].flag && deltas[j].flag) break; + } + next = j; + /* Infer deltas for all unref points in the gap between prev and next */ + i = prev; + for (;;) + { + i = next_index (i, start_point, end_point); + if (i == next) break; + deltas[i].x = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next); + deltas[i].y = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next); + if (--unref_count == 0) goto no_more_gaps; + } + } +no_more_gaps: + start_point = end_point + 1; + } + + /* apply specified / inferred deltas to points */ + for (unsigned int i = 0; i < points.length; i++) + { + points[i].x += deltas[i].x; + points[i].y += deltas[i].y; + } + } while (iterator.move_to_next ()); + + return true; + } + + unsigned int get_axis_count () const { return table->axisCount; } + + private: + hb_blob_ptr_t table; + }; + + protected: + FixedVersion<>version; /* Version number of the glyph variations table + * Set to 0x00010000u. */ + HBUINT16 axisCount; /* The number of variation axes for this font. This must be + * the same number as axisCount in the 'fvar' table. */ + HBUINT16 sharedTupleCount; + /* The number of shared tuple records. Shared tuple records + * can be referenced within glyph variation data tables for + * multiple glyphs, as opposed to other tuple records stored + * directly within a glyph variation data table. */ + NNOffset32To> + sharedTuples; /* Offset from the start of this table to the shared tuple records. + * Array of tuple records shared across all glyph variation data tables. */ + HBUINT16 glyphCount; /* The number of glyphs in this font. This must match the number of + * glyphs stored elsewhere in the font. */ + HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows. + * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the + * offsets are uint32. */ + Offset32To + dataZ; /* Offset from the start of this table to the array of + * GlyphVariationData tables. */ + UnsizedArrayOf + offsetZ; /* Offsets from the start of the GlyphVariationData array + * to each GlyphVariationData table. */ + public: + DEFINE_SIZE_MIN (20); +}; + +struct gvar_accelerator_t : gvar::accelerator_t {}; + +} /* namespace OT */ + +#endif /* HB_OT_VAR_GVAR_TABLE_HH */ diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index a8d9fe3c8754d8c3df8339ff9a31d2556cccff3f..62bd1aa6868a05c277a6cc005e0f8822c2c708e1 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -44,7 +44,39 @@ struct DeltaSetIndexMap get_width ())); } - unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ + template + bool serialize (hb_serialize_context_t *c, const T &plan) + { + unsigned int width = plan.get_width (); + unsigned int inner_bit_count = plan.get_inner_bit_count (); + const hb_array_t output_map = plan.get_output_map (); + + TRACE_SERIALIZE (this); + if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0)))) + return_trace (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + + format = ((width-1)<<4)|(inner_bit_count-1); + mapCount = output_map.length; + HBUINT8 *p = c->allocate_size (width * output_map.length); + if (unlikely (!p)) return_trace (false); + for (unsigned int i = 0; i < output_map.length; i++) + { + unsigned int v = output_map[i]; + unsigned int outer = v >> 16; + unsigned int inner = v & 0xFFFF; + unsigned int u = (outer << inner_bit_count) | inner; + for (unsigned int w = width; w > 0;) + { + p[--w] = u; + u >>= 8; + } + p += width; + } + return_trace (true); + } + + uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */ { /* If count is zero, pass value unchanged. This takes * care of direct mapping for advance map. */ @@ -63,7 +95,7 @@ struct DeltaSetIndexMap } { /* Repack it. */ - unsigned int n = get_inner_bitcount (); + unsigned int n = get_inner_bit_count (); unsigned int outer = u >> n; unsigned int inner = u & ((1 << n) - 1); u = (outer<<16) | inner; @@ -72,22 +104,230 @@ struct DeltaSetIndexMap return u; } - protected: - unsigned int get_width () const { return ((format >> 4) & 3) + 1; } - - unsigned int get_inner_bitcount () const { return (format & 0xF) + 1; } + unsigned int get_map_count () const { return mapCount; } + unsigned int get_width () const { return ((format >> 4) & 3) + 1; } + unsigned int get_inner_bit_count () const { return (format & 0xF) + 1; } protected: HBUINT16 format; /* A packed field that describes the compressed * representation of delta-set indices. */ HBUINT16 mapCount; /* The number of mapping entries. */ UnsizedArrayOf - mapDataZ; /* The delta-set index mapping data. */ + mapDataZ; /* The delta-set index mapping data. */ public: DEFINE_SIZE_ARRAY (4, mapDataZ); }; +struct index_map_subset_plan_t +{ + enum index_map_index_t { + ADV_INDEX, + LSB_INDEX, /* dual as TSB */ + RSB_INDEX, /* dual as BSB */ + VORG_INDEX + }; + + void init (const DeltaSetIndexMap &index_map, + hb_inc_bimap_t &outer_map, + hb_vector_t &inner_sets, + const hb_subset_plan_t *plan) + { + map_count = 0; + outer_bit_count = 0; + inner_bit_count = 1; + max_inners.init (); + output_map.init (); + + if (&index_map == &Null (DeltaSetIndexMap)) return; + + unsigned int last_val = (unsigned int)-1; + hb_codepoint_t last_gid = (hb_codepoint_t)-1; + hb_codepoint_t gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ()); + + outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count (); + max_inners.resize (inner_sets.length); + for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0; + + /* Search backwards for a map value different from the last map value */ + for (; gid > 0; gid--) + { + hb_codepoint_t old_gid; + if (!plan->old_gid_for_new_gid (gid - 1, &old_gid)) + { + if (last_gid == (hb_codepoint_t) -1) + continue; + else + break; + } + + unsigned int v = index_map.map (old_gid); + if (last_gid == (hb_codepoint_t) -1) + { + last_val = v; + last_gid = gid; + continue; + } + if (v != last_val) break; + + last_gid = gid; + } + + if (unlikely (last_gid == (hb_codepoint_t)-1)) return; + map_count = last_gid; + for (gid = 0; gid < map_count; gid++) + { + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (gid, &old_gid)) + { + unsigned int v = index_map.map (old_gid); + unsigned int outer = v >> 16; + unsigned int inner = v & 0xFFFF; + outer_map.add (outer); + if (inner > max_inners[outer]) max_inners[outer] = inner; + if (outer >= inner_sets.length) return; + inner_sets[outer]->add (inner); + } + } + } + + void fini () + { + max_inners.fini (); + output_map.fini (); + } + + void remap (const DeltaSetIndexMap *input_map, + const hb_inc_bimap_t &outer_map, + const hb_vector_t &inner_maps, + const hb_subset_plan_t *plan) + { + if (input_map == &Null (DeltaSetIndexMap)) return; + + for (unsigned int i = 0; i < max_inners.length; i++) + { + if (inner_maps[i].get_population () == 0) continue; + unsigned int bit_count = (max_inners[i]==0)? 1: hb_bit_storage (inner_maps[i][max_inners[i]]); + if (bit_count > inner_bit_count) inner_bit_count = bit_count; + } + + output_map.resize (map_count); + for (hb_codepoint_t gid = 0; gid < output_map.length; gid++) + { + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (gid, &old_gid)) + { + uint32_t v = input_map->map (old_gid); + unsigned int outer = v >> 16; + output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]); + } + else + output_map[gid] = 0; /* Map unused glyph to outer/inner=0/0 */ + } + } + + unsigned int get_inner_bit_count () const { return inner_bit_count; } + unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); } + unsigned int get_map_count () const { return map_count; } + + unsigned int get_size () const + { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } + + bool is_identity () const { return get_output_map ().length == 0; } + hb_array_t get_output_map () const { return output_map.as_array (); } + + protected: + unsigned int map_count; + hb_vector_t max_inners; + unsigned int outer_bit_count; + unsigned int inner_bit_count; + hb_vector_t output_map; +}; + +struct hvarvvar_subset_plan_t +{ + hvarvvar_subset_plan_t() : inner_maps (), index_map_plans () {} + ~hvarvvar_subset_plan_t() { fini (); } + + void init (const hb_array_t &index_maps, + const VariationStore &_var_store, + const hb_subset_plan_t *plan) + { + index_map_plans.resize (index_maps.length); + + var_store = &_var_store; + inner_sets.resize (var_store->get_sub_table_count ()); + for (unsigned int i = 0; i < inner_sets.length; i++) + inner_sets[i] = hb_set_create (); + adv_set = hb_set_create (); + + inner_maps.resize (var_store->get_sub_table_count ()); + + for (unsigned int i = 0; i < inner_maps.length; i++) + inner_maps[i].init (); + + if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; + + bool retain_adv_map = false; + index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan); + if (index_maps[0] == &Null (DeltaSetIndexMap)) + { + retain_adv_map = plan->retain_gids; + outer_map.add (0); + for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + { + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (gid, &old_gid)) + inner_sets[0]->add (old_gid); + } + hb_set_union (adv_set, inner_sets[0]); + } + + for (unsigned int i = 1; i < index_maps.length; i++) + index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan); + + outer_map.sort (); + + if (retain_adv_map) + { + for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + if (inner_sets[0]->has (gid)) + inner_maps[0].add (gid); + else + inner_maps[0].skip (); + } + else + { + inner_maps[0].add_set (adv_set); + hb_set_subtract (inner_sets[0], adv_set); + inner_maps[0].add_set (inner_sets[0]); + } + + for (unsigned int i = 1; i < inner_maps.length; i++) + inner_maps[i].add_set (inner_sets[i]); + + for (unsigned int i = 0; i < index_maps.length; i++) + index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan); + } + + void fini () + { + for (unsigned int i = 0; i < inner_sets.length; i++) + hb_set_destroy (inner_sets[i]); + hb_set_destroy (adv_set); + inner_maps.fini_deep (); + index_map_plans.fini_deep (); + } + + hb_inc_bimap_t outer_map; + hb_vector_t inner_maps; + hb_vector_t index_map_plans; + const VariationStore *var_store; + + protected: + hb_vector_t inner_sets; + hb_set_t *adv_set; +}; /* * HVAR -- Horizontal Metrics Variations @@ -114,25 +354,84 @@ struct HVARVVAR rsbMap.sanitize (c, this)); } - float get_advance_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count) const + void listup_index_maps (hb_vector_t &index_maps) const + { + index_maps.push (&(this+advMap)); + index_maps.push (&(this+lsbMap)); + index_maps.push (&(this+rsbMap)); + } + + bool serialize_index_maps (hb_serialize_context_t *c, + const hb_array_t &im_plans) + { + TRACE_SERIALIZE (this); + if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ()) + advMap = 0; + else if (unlikely (!advMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX]))) + return_trace (false); + if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ()) + lsbMap = 0; + else if (unlikely (!lsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX]))) + return_trace (false); + if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ()) + rsbMap = 0; + else if (unlikely (!rsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX]))) + return_trace (false); + + return_trace (true); + } + + template + bool _subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + hvarvvar_subset_plan_t hvar_plan; + hb_vector_t + index_maps; + + ((T*)this)->listup_index_maps (index_maps); + hvar_plan.init (index_maps.as_array (), this+varStore, c->plan); + + T *out = c->serializer->allocate_min (); + if (unlikely (!out)) return_trace (false); + + out->version.major = 1; + out->version.minor = 0; + + if (unlikely (!out->varStore.serialize (c->serializer, out) + .serialize (c->serializer, hvar_plan.var_store, hvar_plan.inner_maps.as_array ()))) + return_trace (false); + + return_trace (out->T::serialize_index_maps (c->serializer, + hvar_plan.index_map_plans.as_array ())); + } + + float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const { - unsigned int varidx = (this+advMap).map (glyph); + uint32_t varidx = (this+advMap).map (glyph); + return (this+varStore).get_delta (varidx, font->coords, font->num_coords); + } + + float get_side_bearing_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count) const + { + if (!has_side_bearing_deltas ()) return 0.f; + uint32_t varidx = (this+lsbMap).map (glyph); return (this+varStore).get_delta (varidx, coords, coord_count); } - bool has_sidebearing_deltas () const { return lsbMap && rsbMap; } + bool has_side_bearing_deltas () const { return lsbMap && rsbMap; } protected: FixedVersion<>version; /* Version of the metrics variation table * initially set to 0x00010000u */ - LOffsetTo + Offset32To varStore; /* Offset to item variation store table. */ - LOffsetTo + Offset32To advMap; /* Offset to advance var-idx mapping. */ - LOffsetTo + Offset32To lsbMap; /* Offset to lsb/tsb var-idx mapping. */ - LOffsetTo + Offset32To rsbMap; /* Offset to rsb/bsb var-idx mapping. */ public: @@ -141,6 +440,7 @@ struct HVARVVAR struct HVAR : HVARVVAR { static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR; + bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset (c); } }; struct VVAR : HVARVVAR { static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR; @@ -152,8 +452,30 @@ struct VVAR : HVARVVAR { vorgMap.sanitize (c, this)); } + void listup_index_maps (hb_vector_t &index_maps) const + { + HVARVVAR::listup_index_maps (index_maps); + index_maps.push (&(this+vorgMap)); + } + + bool serialize_index_maps (hb_serialize_context_t *c, + const hb_array_t &im_plans) + { + TRACE_SERIALIZE (this); + if (unlikely (!HVARVVAR::serialize_index_maps (c, im_plans))) + return_trace (false); + if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ()) + vorgMap = 0; + else if (unlikely (!vorgMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX]))) + return_trace (false); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset (c); } + protected: - LOffsetTo + Offset32To vorgMap; /* Offset to vertical-origin var-idx mapping. */ public: diff --git a/src/hb-ot-var-mvar-table.hh b/src/hb-ot-var-mvar-table.hh index 5a9d2afb7c6920e53bad82cafa17253c92e3814d..208db4674107049de50b4cf9f56bdd969021e709 100644 --- a/src/hb-ot-var-mvar-table.hh +++ b/src/hb-ot-var-mvar-table.hh @@ -77,7 +77,9 @@ struct MVAR const int *coords, unsigned int coord_count) const { const VariationValueRecord *record; - record = (VariationValueRecord *) hb_bsearch (&tag, valuesZ.arrayZ, + record = (VariationValueRecord *) hb_bsearch (tag, + (const VariationValueRecord *) + (const HBUINT8 *) valuesZ, valueRecordCount, valueRecordSize, tag_compare); if (!record) @@ -101,7 +103,7 @@ protected: HBUINT16 valueRecordSize;/* The size in bytes of each value record — * must be greater than zero. */ HBUINT16 valueRecordCount;/* The number of value records — may be zero. */ - OffsetTo + Offset16To varStore; /* Offset to item variation store table. */ UnsizedArrayOf valuesZ; /* Array of value records. The records must be diff --git a/src/hb-ot-var.cc b/src/hb-ot-var.cc index 6b8b09b6ba85a74b6a4ffaba4367a9d8782f0d02..6b42b45cd964fe42ac5bd9797dace2fd3bda55fe 100644 --- a/src/hb-ot-var.cc +++ b/src/hb-ot-var.cc @@ -52,11 +52,11 @@ /** * hb_ot_var_has_data: - * @face: #hb_face_t to test + * @face: The #hb_face_t to work on * - * This function allows to verify the presence of OpenType variation data on the face. + * Tests whether a face includes any OpenType variation data in the `fvar` table. * - * Return value: true if face has a `fvar' table and false otherwise + * Return value: %true if data found, %false otherwise * * Since: 1.4.2 **/ @@ -68,6 +68,11 @@ hb_ot_var_has_data (hb_face_t *face) /** * hb_ot_var_get_axis_count: + * @face: The #hb_face_t to work on + * + * Fetches the number of OpenType variation axes included in the face. + * + * Return value: the number of variation axes defined * * Since: 1.4.2 **/ @@ -80,9 +85,17 @@ hb_ot_var_get_axis_count (hb_face_t *face) #ifndef HB_DISABLE_DEPRECATED /** * hb_ot_var_get_axes: + * @face: #hb_face_t to work upon + * @start_offset: offset of the first lookup to retrieve + * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return; + * Output = the actual number of variation axes returned (may be zero) + * @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found + * + * Fetches a list of all variation axes in the specified face. The list returned will begin + * at the offset provided. * * Since: 1.4.2 - * Deprecated: 2.2.0 + * Deprecated: 2.2.0: use hb_ot_var_get_axis_infos() instead **/ unsigned int hb_ot_var_get_axes (hb_face_t *face, @@ -95,9 +108,16 @@ hb_ot_var_get_axes (hb_face_t *face, /** * hb_ot_var_find_axis: + * @face: #hb_face_t to work upon + * @axis_tag: The #hb_tag_t of the variation axis to query + * @axis_index: The index of the variation axis + * @axis_info: (out): The #hb_ot_var_axis_info_t of the axis tag queried + * + * Fetches the variation-axis information corresponding to the specified axis tag + * in the specified face. * * Since: 1.4.2 - * Deprecated: 2.2.0 + * Deprecated: 2.2.0 - use hb_ot_var_find_axis_info() instead **/ hb_bool_t hb_ot_var_find_axis (hb_face_t *face, @@ -111,6 +131,16 @@ hb_ot_var_find_axis (hb_face_t *face, /** * hb_ot_var_get_axis_infos: + * @face: #hb_face_t to work upon + * @start_offset: offset of the first lookup to retrieve + * @axes_count: (inout) (optional): Input = the maximum number of variation axes to return; + * Output = the actual number of variation axes returned (may be zero) + * @axes_array: (out caller-allocates) (array length=axes_count): The array of variation axes found + * + * Fetches a list of all variation axes in the specified face. The list returned will begin + * at the offset provided. + * + * Return value: the number of variation axes in the face * * Since: 2.2.0 **/ @@ -125,6 +155,14 @@ hb_ot_var_get_axis_infos (hb_face_t *face, /** * hb_ot_var_find_axis_info: + * @face: #hb_face_t to work upon + * @axis_tag: The #hb_tag_t of the variation axis to query + * @axis_info: (out): The #hb_ot_var_axis_info_t of the axis tag queried + * + * Fetches the variation-axis information corresponding to the specified axis tag + * in the specified face. + * + * Return value: %true if data found, %false otherwise * * Since: 2.2.0 **/ @@ -141,12 +179,34 @@ hb_ot_var_find_axis_info (hb_face_t *face, * Named instances. */ +/** + * hb_ot_var_get_named_instance_count: + * @face: The #hb_face_t to work on + * + * Fetches the number of named instances included in the face. + * + * Return value: the number of named instances defined + * + * Since: 2.2.0 + **/ unsigned int hb_ot_var_get_named_instance_count (hb_face_t *face) { return face->table.fvar->get_instance_count (); } +/** + * hb_ot_var_named_instance_get_subfamily_name_id: + * @face: The #hb_face_t to work on + * @instance_index: The index of the named instance to query + * + * Fetches the `name` table Name ID that provides display names for + * the "Subfamily name" defined for the given named instance in the face. + * + * Return value: the Name ID found for the Subfamily name + * + * Since: 2.2.0 + **/ hb_ot_name_id_t hb_ot_var_named_instance_get_subfamily_name_id (hb_face_t *face, unsigned int instance_index) @@ -154,6 +214,18 @@ hb_ot_var_named_instance_get_subfamily_name_id (hb_face_t *face, return face->table.fvar->get_instance_subfamily_name_id (instance_index); } +/** + * hb_ot_var_named_instance_get_postscript_name_id: + * @face: The #hb_face_t to work on + * @instance_index: The index of the named instance to query + * + * Fetches the `name` table Name ID that provides display names for + * the "PostScript name" defined for the given named instance in the face. + * + * Return value: the Name ID found for the PostScript name + * + * Since: 2.2.0 + **/ hb_ot_name_id_t hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face, unsigned int instance_index) @@ -161,6 +233,21 @@ hb_ot_var_named_instance_get_postscript_name_id (hb_face_t *face, return face->table.fvar->get_instance_postscript_name_id (instance_index); } +/** + * hb_ot_var_named_instance_get_design_coords: + * @face: The #hb_face_t to work on + * @instance_index: The index of the named instance to query + * @coords_length: (inout) (optional): Input = the maximum number of coordinates to return; + * Output = the actual number of coordinates returned (may be zero) + * @coords: (out) (array length=coords_length): The array of coordinates found for the query + * + * Fetches the design-space coordinates corresponding to the given + * named instance in the face. + * + * Return value: the number of variation axes in the face + * + * Since: 2.2.0 + **/ unsigned int hb_ot_var_named_instance_get_design_coords (hb_face_t *face, unsigned int instance_index, @@ -173,6 +260,13 @@ hb_ot_var_named_instance_get_design_coords (hb_face_t *face, /** * hb_ot_var_normalize_variations: + * @face: The #hb_face_t to work on + * @variations: The array of variations to normalize + * @variations_length: The number of variations to normalize + * @coords: (out) (array length=coords_length): The array of normalized coordinates + * @coords_length: The length of the coordinate array + * + * Normalizes all of the coordinates in the given list of variation axes. * * Since: 1.4.2 **/ @@ -200,6 +294,17 @@ hb_ot_var_normalize_variations (hb_face_t *face, /** * hb_ot_var_normalize_coords: + * @face: The #hb_face_t to work on + * @coords_length: The length of the coordinate array + * @design_coords: The design-space coordinates to normalize + * @normalized_coords: (out): The normalized coordinates + * + * Normalizes the given design-space coordinates. The minimum and maximum + * values for the axis are mapped to the interval [-1,1], with the default + * axis value mapped to 0. + * + * Any additional scaling defined in the face's `avar` table is also + * applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar * * Since: 1.4.2 **/ diff --git a/src/hb-ot-var.h b/src/hb-ot-var.h index df89bc5a231e41348e6ea09aa10454c0ca6288d0..ce201d3b4f5acd70ba639f249ccb02cabeb4f973 100644 --- a/src/hb-ot-var.h +++ b/src/hb-ot-var.h @@ -24,7 +24,7 @@ * Red Hat Author(s): Behdad Esfahbod */ -#ifndef HB_OT_H_IN +#if !defined(HB_OT_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -35,11 +35,40 @@ HB_BEGIN_DECLS - +/** + * HB_OT_TAG_VAR_AXIS_ITALIC: + * + * Registered tag for the roman/italic axis. + */ #define HB_OT_TAG_VAR_AXIS_ITALIC HB_TAG('i','t','a','l') + +/** + * HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE: + * + * Registered tag for the optical-size axis. + * Note: The optical-size axis supersedes the OpenType `size` feature. + */ #define HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE HB_TAG('o','p','s','z') + +/** + * HB_OT_TAG_VAR_AXIS_SLANT: + * + * Registered tag for the slant axis + */ #define HB_OT_TAG_VAR_AXIS_SLANT HB_TAG('s','l','n','t') + +/** + * HB_OT_TAG_VAR_AXIS_WIDTH: + * + * Registered tag for the width axis. + */ #define HB_OT_TAG_VAR_AXIS_WIDTH HB_TAG('w','d','t','h') + +/** + * HB_OT_TAG_VAR_AXIS_WEIGHT: + * + * Registered tag for the weight axis. + */ #define HB_OT_TAG_VAR_AXIS_WEIGHT HB_TAG('w','g','h','t') @@ -63,21 +92,37 @@ hb_ot_var_get_axis_count (hb_face_t *face); * hb_ot_var_axis_flags_t: * @HB_OT_VAR_AXIS_FLAG_HIDDEN: The axis should not be exposed directly in user interfaces. * + * Flags for #hb_ot_var_axis_info_t. + * * Since: 2.2.0 */ typedef enum { /*< flags >*/ HB_OT_VAR_AXIS_FLAG_HIDDEN = 0x00000001u, + /*< private >*/ _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_var_axis_flags_t; /** * hb_ot_var_axis_info_t: + * @axis_index: Index of the axis in the variation-axis array + * @tag: The #hb_tag_t tag identifying the design variation of the axis + * @name_id: The `name` table Name ID that provides display names for the axis + * @flags: The #hb_ot_var_axis_flags_t flags for the axis + * @min_value: The mininum value on the variation axis that the font covers + * @default_value: The position on the variation axis corresponding to the font's defaults + * @max_value: The maximum value on the variation axis that the font covers + * + * Data type for holding variation-axis values. + * + * The minimum, default, and maximum values are in un-normalized, user scales. + * + * Note: at present, the only flag defined for @flags is + * #HB_OT_VAR_AXIS_FLAG_HIDDEN. * * Since: 2.2.0 */ -typedef struct hb_ot_var_axis_info_t -{ +typedef struct hb_ot_var_axis_info_t { unsigned int axis_index; hb_tag_t tag; hb_ot_name_id_t name_id; diff --git a/src/hb-ot-vorg-table.hh b/src/hb-ot-vorg-table.hh index d9002f3d69044203342a27c910eac4cd88f472c3..efa7737d6f7637bfb19e26e8cc1455c28f83070e 100644 --- a/src/hb-ot-vorg-table.hh +++ b/src/hb-ot-vorg-table.hh @@ -48,7 +48,7 @@ struct VertOriginMetric } public: - GlyphID glyph; + HBGlyphID glyph; FWORD vertOriginY; public: @@ -70,10 +70,10 @@ struct VORG } template + hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, - Iterator it, - FWORD defaultVertOriginY) + Iterator it, + FWORD defaultVertOriginY) { if (unlikely (!c->extend_min ((*this)))) return; @@ -84,9 +84,7 @@ struct VORG this->defaultVertOriginY = defaultVertOriginY; this->vertYOrigins.len = it.len (); - + it - | hb_apply ([c] (const VertOriginMetric& _) { c->copy (_); }) - ; + c->copy_all (it); } bool subset (hb_subset_context_t *c) const @@ -99,15 +97,15 @@ struct VORG + vertYOrigins.as_array () | hb_filter (c->plan->glyphset (), &VertOriginMetric::glyph) | hb_map ([&] (const VertOriginMetric& _) - { - hb_codepoint_t new_glyph = HB_SET_VALUE_INVALID; - c->plan->new_gid_for_old_gid (_.glyph, &new_glyph); - - VertOriginMetric metric; - metric.glyph = new_glyph; - metric.vertOriginY = _.vertOriginY; - return metric; - }) + { + hb_codepoint_t new_glyph = HB_SET_VALUE_INVALID; + c->plan->new_gid_for_old_gid (_.glyph, &new_glyph); + + VertOriginMetric metric; + metric.glyph = new_glyph; + metric.vertOriginY = _.vertOriginY; + return metric; + }) ; /* serialize the new table */ @@ -119,15 +117,16 @@ struct VORG { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - version.major == 1 && - vertYOrigins.sanitize (c)); + version.major == 1 && + vertYOrigins.sanitize (c)); } protected: - FixedVersion<> version; /* Version of VORG table. Set to 0x00010000u. */ - FWORD defaultVertOriginY; /* The default vertical origin. */ - SortedArrayOf - vertYOrigins; /* The array of vertical origins. */ + FixedVersion<>version; /* Version of VORG table. Set to 0x00010000u. */ + FWORD defaultVertOriginY; + /* The default vertical origin. */ + SortedArray16Of + vertYOrigins; /* The array of vertical origins. */ public: DEFINE_SIZE_ARRAY(8, vertYOrigins); diff --git a/src/hb-pool.hh b/src/hb-pool.hh index 2dd84968e01e9c782197a69c5bd12934fc6684c8..dcf0faf2a9363e4bea7e796935653bf6b6b33d80 100644 --- a/src/hb-pool.hh +++ b/src/hb-pool.hh @@ -41,9 +41,7 @@ struct hb_pool_t { next = nullptr; - + hb_iter (chunks) - | hb_apply ([] (chunk_t *_) { ::free (_); }) - ; + for (chunk_t *_ : chunks) ::free (_); chunks.fini (); } @@ -84,7 +82,7 @@ struct hb_pool_t T* thread () { for (unsigned i = 0; i < ARRAY_LENGTH (arrayZ) - 1; i++) - * (T**) &arrayZ[i] = &arrayZ[i + 1]; + * (T**) &arrayZ[i] = &arrayZ[i + 1]; * (T**) &arrayZ[ARRAY_LENGTH (arrayZ) - 1] = nullptr; diff --git a/src/hb-priority-queue.hh b/src/hb-priority-queue.hh new file mode 100644 index 0000000000000000000000000000000000000000..7d799ae9062b746a62194a0c6efa57283d571fc5 --- /dev/null +++ b/src/hb-priority-queue.hh @@ -0,0 +1,151 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef HB_PRIORITY_QUEUE_HH +#define HB_PRIORITY_QUEUE_HH + +#include "hb.hh" +#include "hb-vector.hh" + +/* + * hb_priority_queue_t + * + * Priority queue implemented as a binary heap. Supports extract minimum + * and insert operations. + */ +struct hb_priority_queue_t +{ + HB_DELETE_COPY_ASSIGN (hb_priority_queue_t); + hb_priority_queue_t () { init (); } + ~hb_priority_queue_t () { fini (); } + + private: + typedef hb_pair_t item_t; + hb_vector_t heap; + + public: + void init () { heap.init (); } + + void fini () { heap.fini (); } + + void reset () { heap.resize (0); } + + bool in_error () const { return heap.in_error (); } + + void insert (int64_t priority, unsigned value) + { + heap.push (item_t (priority, value)); + bubble_up (heap.length - 1); + } + + item_t pop_minimum () + { + item_t result = heap[0]; + + heap[0] = heap[heap.length - 1]; + heap.shrink (heap.length - 1); + bubble_down (0); + + return result; + } + + const item_t& minimum () + { + return heap[0]; + } + + bool is_empty () const { return heap.length == 0; } + explicit operator bool () const { return !is_empty (); } + unsigned int get_population () const { return heap.length; } + + /* Sink interface. */ + hb_priority_queue_t& operator << (item_t item) + { insert (item.first, item.second); return *this; } + + private: + + static constexpr unsigned parent (unsigned index) + { + return (index - 1) / 2; + } + + static constexpr unsigned left_child (unsigned index) + { + return 2 * index + 1; + } + + static constexpr unsigned right_child (unsigned index) + { + return 2 * index + 2; + } + + void bubble_down (unsigned index) + { + unsigned left = left_child (index); + unsigned right = right_child (index); + + bool has_left = left < heap.length; + if (!has_left) + // If there's no left, then there's also no right. + return; + + bool has_right = right < heap.length; + if (heap[index].first <= heap[left].first + && (!has_right || heap[index].first <= heap[right].first)) + return; + + if (!has_right || heap[left].first < heap[right].first) + { + swap (index, left); + bubble_down (left); + return; + } + + swap (index, right); + bubble_down (right); + } + + void bubble_up (unsigned index) + { + if (index == 0) return; + + unsigned parent_index = parent (index); + if (heap[parent_index].first <= heap[index].first) + return; + + swap (index, parent_index); + bubble_up (parent_index); + } + + void swap (unsigned a, unsigned b) + { + item_t temp = heap[a]; + heap[a] = heap[b]; + heap[b] = temp; + } +}; + +#endif /* HB_PRIORITY_QUEUE_HH */ diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh new file mode 100644 index 0000000000000000000000000000000000000000..6211dedb9ccf475c0f3d397ab17736f8f15d0055 --- /dev/null +++ b/src/hb-repacker.hh @@ -0,0 +1,758 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef HB_REPACKER_HH +#define HB_REPACKER_HH + +#include "hb-open-type.hh" +#include "hb-map.hh" +#include "hb-priority-queue.hh" +#include "hb-serialize.hh" +#include "hb-vector.hh" + + +struct graph_t +{ + struct vertex_t + { + vertex_t () : + distance (0), + incoming_edges (0), + start (0), + end (0), + priority(0) {} + + void fini () { obj.fini (); } + + hb_serialize_context_t::object_t obj; + int64_t distance; + unsigned incoming_edges; + unsigned start; + unsigned end; + unsigned priority; + + bool is_shared () const + { + return incoming_edges > 1; + } + + bool is_leaf () const + { + return !obj.links.length; + } + + void raise_priority () + { + priority++; + } + + int64_t modified_distance (unsigned order) const + { + // TODO(garretrieger): once priority is high enough, should try + // setting distance = 0 which will force to sort immediately after + // it's parent where possible. + + int64_t modified_distance = + hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFF); + return (modified_distance << 24) | (0x00FFFFFF & order); + } + + int64_t distance_modifier () const + { + if (!priority) return 0; + int64_t table_size = obj.tail - obj.head; + return -(table_size - table_size / (1 << hb_min(priority, 16u))); + } + }; + + struct overflow_record_t + { + unsigned parent; + const hb_serialize_context_t::object_t::link_t* link; + }; + + struct clone_buffer_t + { + clone_buffer_t () : head (nullptr), tail (nullptr) {} + + bool copy (const hb_serialize_context_t::object_t& object) + { + fini (); + unsigned size = object.tail - object.head; + head = (char*) malloc (size); + if (!head) return false; + + memcpy (head, object.head, size); + tail = head + size; + return true; + } + + char* head; + char* tail; + + void fini () + { + if (!head) return; + free (head); + head = nullptr; + } + }; + + /* + * A topological sorting of an object graph. Ordered + * in reverse serialization order (first object in the + * serialization is at the end of the list). This matches + * the 'packed' object stack used internally in the + * serializer + */ + graph_t (const hb_vector_t& objects) + : edge_count_invalid (true), + distance_invalid (true), + positions_invalid (true), + successful (true) + { + bool removed_nil = false; + for (unsigned i = 0; i < objects.length; i++) + { + // TODO(grieger): check all links point to valid objects. + + // If this graph came from a serialization buffer object 0 is the + // nil object. We don't need it for our purposes here so drop it. + if (i == 0 && !objects[i]) + { + removed_nil = true; + continue; + } + + vertex_t* v = vertices_.push (); + if (check_success (!vertices_.in_error ())) + v->obj = *objects[i]; + if (!removed_nil) continue; + for (unsigned i = 0; i < v->obj.links.length; i++) + // Fix indices to account for removed nil object. + v->obj.links[i].objidx--; + } + } + + ~graph_t () + { + vertices_.fini_deep (); + clone_buffers_.fini_deep (); + } + + bool in_error () const + { + return !successful || vertices_.in_error () || clone_buffers_.in_error (); + } + + const vertex_t& root () const + { + return vertices_[root_idx ()]; + } + + unsigned root_idx () const + { + // Object graphs are in reverse order, the first object is at the end + // of the vector. Since the graph is topologically sorted it's safe to + // assume the first object has no incoming edges. + return vertices_.length - 1; + } + + const hb_serialize_context_t::object_t& object(unsigned i) const + { + return vertices_[i].obj; + } + + /* + * serialize graph into the provided serialization buffer. + */ + void serialize (hb_serialize_context_t* c) const + { + c->start_serialize (); + for (unsigned i = 0; i < vertices_.length; i++) { + c->push (); + + size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; + char* start = c->allocate_size (size); + if (!start) return; + + memcpy (start, vertices_[i].obj.head, size); + + for (const auto& link : vertices_[i].obj.links) + serialize_link (link, start, c); + + // All duplications are already encoded in the graph, so don't + // enable sharing during packing. + c->pop_pack (false); + } + c->end_serialize (); + } + + /* + * Generates a new topological sorting of graph using Kahn's + * algorithm: https://en.wikipedia.org/wiki/Topological_sorting#Algorithms + */ + void sort_kahn () + { + positions_invalid = true; + + if (vertices_.length <= 1) { + // Graph of 1 or less doesn't need sorting. + return; + } + + hb_vector_t queue; + hb_vector_t sorted_graph; + hb_vector_t id_map; + if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; + + hb_vector_t removed_edges; + if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; + update_incoming_edge_count (); + + queue.push (root_idx ()); + int new_id = vertices_.length - 1; + + while (!queue.in_error () && queue.length) + { + unsigned next_id = queue[0]; + queue.remove (0); + + vertex_t& next = vertices_[next_id]; + sorted_graph.push (next); + id_map[next_id] = new_id--; + + for (const auto& link : next.obj.links) { + removed_edges[link.objidx]++; + if (!(vertices_[link.objidx].incoming_edges - removed_edges[link.objidx])) + queue.push (link.objidx); + } + } + + check_success (!queue.in_error ()); + check_success (!sorted_graph.in_error ()); + if (!check_success (new_id == -1)) + DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); + + remap_obj_indices (id_map, &sorted_graph); + + sorted_graph.as_array ().reverse (); + + vertices_.fini_deep (); + vertices_ = sorted_graph; + sorted_graph.fini_deep (); + } + + /* + * Generates a new topological sorting of graph ordered by the shortest + * distance to each node. + */ + void sort_shortest_distance () + { + positions_invalid = true; + + if (vertices_.length <= 1) { + // Graph of 1 or less doesn't need sorting. + return; + } + + update_distances (); + + hb_priority_queue_t queue; + hb_vector_t sorted_graph; + hb_vector_t id_map; + if (unlikely (!check_success (id_map.resize (vertices_.length)))) return; + + hb_vector_t removed_edges; + if (unlikely (!check_success (removed_edges.resize (vertices_.length)))) return; + update_incoming_edge_count (); + + queue.insert (root ().modified_distance (0), root_idx ()); + int new_id = root_idx (); + unsigned order = 1; + while (!queue.in_error () && !queue.is_empty ()) + { + unsigned next_id = queue.pop_minimum().second; + + vertex_t& next = vertices_[next_id]; + sorted_graph.push (next); + id_map[next_id] = new_id--; + + for (const auto& link : next.obj.links) { + removed_edges[link.objidx]++; + if (!(vertices_[link.objidx].incoming_edges - removed_edges[link.objidx])) + // Add the order that the links were encountered to the priority. + // This ensures that ties between priorities objects are broken in a consistent + // way. More specifically this is set up so that if a set of objects have the same + // distance they'll be added to the topological order in the order that they are + // referenced from the parent object. + queue.insert (vertices_[link.objidx].modified_distance (order++), + link.objidx); + } + } + + check_success (!queue.in_error ()); + check_success (!sorted_graph.in_error ()); + if (!check_success (new_id == -1)) + DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); + + remap_obj_indices (id_map, &sorted_graph); + + sorted_graph.as_array ().reverse (); + + vertices_.fini_deep (); + vertices_ = sorted_graph; + sorted_graph.fini_deep (); + } + + /* + * Creates a copy of child and re-assigns the link from + * parent to the clone. The copy is a shallow copy, objects + * linked from child are not duplicated. + */ + void duplicate (unsigned parent_idx, unsigned child_idx) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", + parent_idx, child_idx); + + positions_invalid = true; + + auto* clone = vertices_.push (); + auto& child = vertices_[child_idx]; + clone_buffer_t* buffer = clone_buffers_.push (); + if (vertices_.in_error () + || clone_buffers_.in_error () + || !check_success (buffer->copy (child.obj))) { + return; + } + + clone->obj.head = buffer->head; + clone->obj.tail = buffer->tail; + clone->distance = child.distance; + + for (const auto& l : child.obj.links) + clone->obj.links.push (l); + + check_success (!clone->obj.links.in_error ()); + + auto& parent = vertices_[parent_idx]; + unsigned clone_idx = vertices_.length - 2; + for (unsigned i = 0; i < parent.obj.links.length; i++) + { + auto& l = parent.obj.links[i]; + if (l.objidx == child_idx) + { + l.objidx = clone_idx; + clone->incoming_edges++; + child.incoming_edges--; + } + } + + // The last object is the root of the graph, so swap back the root to the end. + // The root's obj idx does change, however since it's root nothing else refers to it. + // all other obj idx's will be unaffected. + vertex_t root = vertices_[vertices_.length - 2]; + vertices_[vertices_.length - 2] = *clone; + vertices_[vertices_.length - 1] = root; + } + + /* + * Raises the sorting priority of all children. + */ + void raise_childrens_priority (unsigned parent_idx) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", + parent_idx); + // This operation doesn't change ordering until a sort is run, so no need + // to invalidate positions. It does not change graph structure so no need + // to update distances or edge counts. + auto& parent = vertices_[parent_idx].obj; + for (unsigned i = 0; i < parent.links.length; i++) + vertices_[parent.links[i].objidx].raise_priority (); + } + + /* + * Will any offsets overflow on graph when it's serialized? + */ + bool will_overflow (hb_vector_t* overflows = nullptr) + { + if (overflows) overflows->resize (0); + update_positions (); + + for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--) + { + for (const auto& link : vertices_[parent_idx].obj.links) + { + int64_t offset = compute_offset (parent_idx, link); + if (is_valid_offset (offset, link)) + continue; + + if (!overflows) return true; + + overflow_record_t r; + r.parent = parent_idx; + r.link = &link; + overflows->push (r); + } + } + + if (!overflows) return false; + return overflows->length; + } + + void print_overflows (const hb_vector_t& overflows) + { + if (!DEBUG_ENABLED(SUBSET_REPACK)) return; + + update_incoming_edge_count (); + for (const auto& o : overflows) + { + const auto& child = vertices_[o.link->objidx]; + DEBUG_MSG (SUBSET_REPACK, nullptr, " overflow from %d => %d (%d incoming , %d outgoing)", + o.parent, + o.link->objidx, + child.incoming_edges, + child.obj.links.length); + } + } + + void err_other_error () { this->successful = false; } + + private: + + bool check_success (bool success) + { return this->successful && (success || (err_other_error (), false)); } + + /* + * Creates a map from objid to # of incoming edges. + */ + void update_incoming_edge_count () + { + if (!edge_count_invalid) return; + + for (unsigned i = 0; i < vertices_.length; i++) + vertices_[i].incoming_edges = 0; + + for (const vertex_t& v : vertices_) + { + for (auto& l : v.obj.links) + { + vertices_[l.objidx].incoming_edges++; + } + } + + edge_count_invalid = false; + } + + /* + * compute the serialized start and end positions for each vertex. + */ + void update_positions () + { + if (!positions_invalid) return; + + unsigned current_pos = 0; + for (int i = root_idx (); i >= 0; i--) + { + auto& v = vertices_[i]; + v.start = current_pos; + current_pos += v.obj.tail - v.obj.head; + v.end = current_pos; + } + + positions_invalid = false; + } + + /* + * Finds the distance to each object in the graph + * from the initial node. + */ + void update_distances () + { + if (!distance_invalid) return; + + // Uses Dijkstra's algorithm to find all of the shortest distances. + // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm + // + // Implementation Note: + // Since our priority queue doesn't support fast priority decreases + // we instead just add new entries into the queue when a priority changes. + // Redundant ones are filtered out later on by the visited set. + // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf + // for practical performance this is faster then using a more advanced queue + // (such as a fibonaacci queue) with a fast decrease priority. + for (unsigned i = 0; i < vertices_.length; i++) + { + if (i == vertices_.length - 1) + vertices_[i].distance = 0; + else + vertices_[i].distance = hb_int_max (int64_t); + } + + hb_priority_queue_t queue; + queue.insert (0, vertices_.length - 1); + + hb_set_t visited; + + while (!queue.in_error () && !queue.is_empty ()) + { + unsigned next_idx = queue.pop_minimum ().second; + if (visited.has (next_idx)) continue; + const auto& next = vertices_[next_idx]; + int64_t next_distance = vertices_[next_idx].distance; + visited.add (next_idx); + + for (const auto& link : next.obj.links) + { + if (visited.has (link.objidx)) continue; + + const auto& child = vertices_[link.objidx].obj; + int64_t child_weight = child.tail - child.head + + (!link.is_wide ? (1 << 16) : ((int64_t) 1 << 32)); + int64_t child_distance = next_distance + child_weight; + + if (child_distance < vertices_[link.objidx].distance) + { + vertices_[link.objidx].distance = child_distance; + queue.insert (child_distance, link.objidx); + } + } + } + + check_success (!queue.in_error ()); + if (!check_success (queue.is_empty ())) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Graph is not fully connected."); + return; + } + + distance_invalid = false; + } + + int64_t compute_offset ( + unsigned parent_idx, + const hb_serialize_context_t::object_t::link_t& link) const + { + const auto& parent = vertices_[parent_idx]; + const auto& child = vertices_[link.objidx]; + int64_t offset = 0; + switch ((hb_serialize_context_t::whence_t) link.whence) { + case hb_serialize_context_t::whence_t::Head: + offset = child.start - parent.start; break; + case hb_serialize_context_t::whence_t::Tail: + offset = child.start - parent.end; break; + case hb_serialize_context_t::whence_t::Absolute: + offset = child.start; break; + } + + assert (offset >= link.bias); + offset -= link.bias; + return offset; + } + + bool is_valid_offset (int64_t offset, + const hb_serialize_context_t::object_t::link_t& link) const + { + if (link.is_signed) + { + if (link.is_wide) + return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); + else + return offset >= -(1 << 15) && offset < (1 << 15); + } + else + { + if (link.is_wide) + return offset >= 0 && offset < ((int64_t) 1 << 32); + else + return offset >= 0 && offset < (1 << 16); + } + } + + /* + * Updates all objidx's in all links using the provided mapping. + */ + void remap_obj_indices (const hb_vector_t& id_map, + hb_vector_t* sorted_graph) const + { + for (unsigned i = 0; i < sorted_graph->length; i++) + { + for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++) + { + auto& link = (*sorted_graph)[i].obj.links[j]; + link.objidx = id_map[link.objidx]; + } + } + } + + template void + serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, + char* head, + hb_serialize_context_t* c) const + { + OT::Offset* offset = reinterpret_cast*> (head + link.position); + *offset = 0; + c->add_link (*offset, + // serializer has an extra nil object at the start of the + // object array. So all id's are +1 of what our id's are. + link.objidx + 1, + (hb_serialize_context_t::whence_t) link.whence, + link.bias); + } + + void serialize_link (const hb_serialize_context_t::object_t::link_t& link, + char* head, + hb_serialize_context_t* c) const + { + if (link.is_wide) + { + if (link.is_signed) + { + serialize_link_of_type (link, head, c); + } else { + serialize_link_of_type (link, head, c); + } + } else { + if (link.is_signed) + { + serialize_link_of_type (link, head, c); + } else { + serialize_link_of_type (link, head, c); + } + } + } + + public: + // TODO(garretrieger): make private, will need to move most of offset overflow code into graph. + hb_vector_t vertices_; + private: + hb_vector_t clone_buffers_; + bool edge_count_invalid; + bool distance_invalid; + bool positions_invalid; + bool successful; +}; + + +/* + * Attempts to modify the topological sorting of the provided object graph to + * eliminate offset overflows in the links between objects of the graph. If a + * non-overflowing ordering is found the updated graph is serialized it into the + * provided serialization context. + * + * If necessary the structure of the graph may be modified in ways that do not + * affect the functionality of the graph. For example shared objects may be + * duplicated. + */ +inline void +hb_resolve_overflows (const hb_vector_t& packed, + hb_serialize_context_t* c) { + // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts + // so try it first to save time. + graph_t sorted_graph (packed); + sorted_graph.sort_kahn (); + if (!sorted_graph.will_overflow ()) + { + sorted_graph.serialize (c); + return; + } + + sorted_graph.sort_shortest_distance (); + + unsigned round = 0; + hb_vector_t overflows; + // TODO(garretrieger): select a good limit for max rounds. + while (!sorted_graph.in_error () + && sorted_graph.will_overflow (&overflows) + && round++ < 10) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Over flow resolution round %d ===", round); + sorted_graph.print_overflows (overflows); + + bool resolution_attempted = false; + hb_set_t priority_bumped_parents; + // Try resolving the furthest overflows first. + for (int i = overflows.length - 1; i >= 0; i--) + { + const graph_t::overflow_record_t& r = overflows[i]; + const auto& child = sorted_graph.vertices_[r.link->objidx]; + if (child.is_shared ()) + { + // The child object is shared, we may be able to eliminate the overflow + // by duplicating it. + sorted_graph.duplicate (r.parent, r.link->objidx); + resolution_attempted = true; + + // Stop processing overflows for this round so that object order can be + // updated to account for the newly added object. + break; + } + + if (child.is_leaf () && !priority_bumped_parents.has (r.parent)) + { + // This object is too far from it's parent, attempt to move it closer. + // + // TODO(garretrieger): initially limiting this to leaf's since they can be + // moved closer with fewer consequences. However, this can + // likely can be used for non-leafs as well. + // TODO(garretrieger): add a maximum priority, don't try to raise past this. + // TODO(garretrieger): also try lowering priority of the parent. Make it + // get placed further up in the ordering, closer to it's children. + // this is probably preferable if the total size of the parent object + // is < then the total size of the children (and the parent can be moved). + // Since in that case moving the parent will cause a smaller increase in + // the length of other offsets. + sorted_graph.raise_childrens_priority (r.parent); + priority_bumped_parents.add (r.parent); + resolution_attempted = true; + continue; + } + + // TODO(garretrieger): add additional offset resolution strategies + // - Promotion to extension lookups. + // - Table splitting. + } + + if (resolution_attempted) + { + sorted_graph.sort_shortest_distance (); + continue; + } + + DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :("); + c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); + return; + } + + if (sorted_graph.in_error ()) + { + c->err (HB_SERIALIZE_ERROR_OTHER); + return; + } + sorted_graph.serialize (c); +} + + +#endif /* HB_REPACKER_HH */ diff --git a/src/hb-sanitize.hh b/src/hb-sanitize.hh index 5f5b4bdc9884561171b725dbca9be06d99e21351..56c46015a6765f7799c3c662aac6e4a611f6ecb4 100644 --- a/src/hb-sanitize.hh +++ b/src/hb-sanitize.hh @@ -73,7 +73,7 @@ * === The sanitize() contract === * * The sanitize() method of each object type shall return true if it's safe to - * call other methods of the object, and false otherwise. + * call other methods of the object, and %false otherwise. * * Note that what sanitize() checks for might align with what the specification * describes as valid table data, but does not have to be. In particular, we @@ -105,7 +105,7 @@ #define HB_SANITIZE_MAX_EDITS 32 #endif #ifndef HB_SANITIZE_MAX_OPS_FACTOR -#define HB_SANITIZE_MAX_OPS_FACTOR 8 +#define HB_SANITIZE_MAX_OPS_FACTOR 64 #endif #ifndef HB_SANITIZE_MAX_OPS_MIN #define HB_SANITIZE_MAX_OPS_MIN 16384 @@ -113,14 +113,16 @@ #ifndef HB_SANITIZE_MAX_OPS_MAX #define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF #endif +#ifndef HB_SANITIZE_MAX_SUBTABLES +#define HB_SANITIZE_MAX_SUBTABLES 0x4000 +#endif struct hb_sanitize_context_t : hb_dispatch_context_t { hb_sanitize_context_t () : - debug_depth (0), start (nullptr), end (nullptr), - max_ops (0), + max_ops (0), max_subtables (0), writable (false), edit_count (0), blob (nullptr), num_glyphs (65536), @@ -134,6 +136,12 @@ struct hb_sanitize_context_t : static return_t no_dispatch_return_value () { return false; } bool stop_sublookup_iteration (const return_t r) const { return !r; } + bool visit_subtables (unsigned count) + { + max_subtables += count; + return max_subtables < HB_SANITIZE_MAX_SUBTABLES; + } + private: template auto _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN @@ -189,8 +197,12 @@ struct hb_sanitize_context_t : void start_processing () { reset_object (); - this->max_ops = hb_max ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR, - (unsigned) HB_SANITIZE_MAX_OPS_MIN); + if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR))) + this->max_ops = HB_SANITIZE_MAX_OPS_MAX; + else + this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR, + (unsigned) HB_SANITIZE_MAX_OPS_MIN, + (unsigned) HB_SANITIZE_MAX_OPS_MAX); this->edit_count = 0; this->debug_depth = 0; @@ -221,7 +233,7 @@ struct hb_sanitize_context_t : (this->start <= p && p <= this->end && (unsigned int) (this->end - p) >= len && - this->max_ops-- > 0); + (this->max_ops -= len) > 0); DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, "check_range [%p..%p]" @@ -326,8 +338,8 @@ struct hb_sanitize_context_t : { DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count); - /* sanitize again to ensure no toe-stepping */ - edit_count = 0; + /* sanitize again to ensure no toe-stepping */ + edit_count = 0; sane = t->sanitize (this); if (edit_count) { DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count); @@ -338,7 +350,7 @@ struct hb_sanitize_context_t : else { if (edit_count && !writable) { - start = hb_blob_get_data_writable (blob, nullptr); + start = hb_blob_get_data_writable (blob, nullptr); end = start + blob->length; if (start) @@ -374,9 +386,8 @@ struct hb_sanitize_context_t : return sanitize_blob (hb_face_reference_table (face, tableTag)); } - mutable unsigned int debug_depth; const char *start, *end; - mutable int max_ops; + mutable int max_ops, max_subtables; private: bool writable; unsigned int edit_count; diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh index 5764a90f6ebf07c93a23e3abb423bb816efb00f8..3ec055b7b0b282a3cb91d7d3ace93ff42945fd72 100644 --- a/src/hb-serialize.hh +++ b/src/hb-serialize.hh @@ -41,16 +41,29 @@ * Serialize */ +enum hb_serialize_error_t { + HB_SERIALIZE_ERROR_NONE = 0x00000000u, + HB_SERIALIZE_ERROR_OTHER = 0x00000001u, + HB_SERIALIZE_ERROR_OFFSET_OVERFLOW = 0x00000002u, + HB_SERIALIZE_ERROR_OUT_OF_ROOM = 0x00000004u, + HB_SERIALIZE_ERROR_INT_OVERFLOW = 0x00000008u, + HB_SERIALIZE_ERROR_ARRAY_OVERFLOW = 0x00000010u +}; +HB_MARK_AS_FLAG_T (hb_serialize_error_t); + struct hb_serialize_context_t { typedef unsigned objidx_t; - struct range_t - { - char *head, *tail; - }; + enum whence_t { + Head, /* Relative to the current object head (default). */ + Tail, /* Relative to the current object tail after packed. */ + Absolute /* Absolute: from the start of the serialize buffer. */ + }; + - struct object_t : range_t + + struct object_t { void fini () { links.fini (); } @@ -70,17 +83,29 @@ struct hb_serialize_context_t struct link_t { bool is_wide: 1; - unsigned position : 31; + bool is_signed: 1; + unsigned whence: 2; + unsigned position: 28; unsigned bias; objidx_t objidx; }; + char *head; + char *tail; hb_vector_t links; object_t *next; }; - range_t snapshot () { range_t s = {head, tail} ; return s; } + struct snapshot_t + { + char *head; + char *tail; + object_t *current; // Just for sanity check + unsigned num_links; + }; + snapshot_t snapshot () + { return snapshot_t { head, tail, current, current->links.length }; } hb_serialize_context_t (void *start_, unsigned int size) : start ((char *) start_), @@ -91,9 +116,7 @@ struct hb_serialize_context_t void fini () { - ++ hb_iter (packed) - | hb_apply ([] (object_t *_) { _->fini (); }) - ; + for (object_t *_ : ++hb_iter (packed)) _->fini (); packed.fini (); this->packed_map.fini (); @@ -106,30 +129,54 @@ struct hb_serialize_context_t object_pool.fini (); } - bool in_error () const { return !this->successful; } + bool in_error () const { return bool (errors); } + + bool successful () const { return !bool (errors); } + + HB_NODISCARD bool ran_out_of_room () const { return errors & HB_SERIALIZE_ERROR_OUT_OF_ROOM; } + HB_NODISCARD bool offset_overflow () const { return errors & HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; } + HB_NODISCARD bool only_offset_overflow () const { return errors == HB_SERIALIZE_ERROR_OFFSET_OVERFLOW; } + + void reset (void *start_, unsigned int size) + { + start = (char*) start_; + end = start + size; + reset (); + current = nullptr; + } void reset () { - this->successful = true; - this->ran_out_of_room = false; + this->errors = HB_SERIALIZE_ERROR_NONE; this->head = this->start; this->tail = this->end; this->debug_depth = 0; fini (); this->packed.push (nullptr); + this->packed_map.init (); } - bool check_success (bool success) - { return this->successful && (success || (err_other_error (), false)); } + bool check_success (bool success, + hb_serialize_error_t err_type = HB_SERIALIZE_ERROR_OTHER) + { + return successful () + && (success || err (err_type)); + } template - bool check_equal (T1 &&v1, T2 &&v2) - { return check_success (v1 == v2); } + bool check_equal (T1 &&v1, T2 &&v2, hb_serialize_error_t err_type) + { + if ((long long) v1 != (long long) v2) + { + return err (err_type); + } + return true; + } template - bool check_assign (T1 &v1, T2 &&v2) - { return check_equal (v1 = v2, v2); } + bool check_assign (T1 &v1, T2 &&v2, hb_serialize_error_t err_type) + { return check_equal (v1 = v2, v2, err_type); } template bool propagate_error (T &&obj) { return check_success (!hb_deref (obj).in_error ()); } @@ -156,11 +203,19 @@ struct hb_serialize_context_t "end [%p..%p] serialized %u bytes; %s", this->start, this->end, (unsigned) (this->head - this->start), - this->successful ? "successful" : "UNSUCCESSFUL"); + successful () ? "successful" : "UNSUCCESSFUL"); propagate_error (packed, packed_map); if (unlikely (!current)) return; + if (unlikely (in_error())) + { + // Offset overflows that occur before link resolution cannot be handled + // by repacking, so set a more general error. + if (offset_overflow ()) err (HB_SERIALIZE_ERROR_OTHER); + return; + } + assert (!current->next); /* Only "pack" if there exist other objects... Otherwise, don't bother. @@ -168,7 +223,7 @@ struct hb_serialize_context_t if (packed.length <= 1) return; - pop_pack (); + pop_pack (false); resolve_links (); } @@ -176,6 +231,8 @@ struct hb_serialize_context_t template Type *push () { + if (unlikely (in_error ())) return start_embed (); + object_t *obj = object_pool.alloc (); if (unlikely (!obj)) check_success (false); @@ -192,14 +249,24 @@ struct hb_serialize_context_t { object_t *obj = current; if (unlikely (!obj)) return; + if (unlikely (in_error())) return; + current = current->next; - revert (*obj); + revert (obj->head, obj->tail); + obj->fini (); object_pool.free (obj); } - objidx_t pop_pack () + + /* Set share to false when an object is unlikely sharable with others + * so not worth an attempt, or a contiguous table is serialized as + * multiple consecutive objects in the reverse order so can't be shared. + */ + objidx_t pop_pack (bool share=true) { object_t *obj = current; if (unlikely (!obj)) return 0; + if (unlikely (in_error())) return 0; + current = current->next; obj->tail = head; obj->next = nullptr; @@ -212,11 +279,15 @@ struct hb_serialize_context_t return 0; } - objidx_t objidx = packed_map.get (obj); - if (objidx) + objidx_t objidx; + if (share) { - obj->fini (); - return objidx; + objidx = packed_map.get (obj); + if (objidx) + { + obj->fini (); + return objidx; + } } tail -= len; @@ -227,27 +298,45 @@ struct hb_serialize_context_t packed.push (obj); - if (unlikely (packed.in_error ())) + if (unlikely (!propagate_error (packed))) + { + /* Obj wasn't successfully added to packed, so clean it up otherwise its + * links will be leaked. When we use constructor/destructors properly, we + * can remove these. */ + obj->fini (); return 0; + } objidx = packed.length - 1; - packed_map.set (obj, objidx); + if (share) packed_map.set (obj, objidx); + propagate_error (packed_map); return objidx; } - void revert (range_t snap) + void revert (snapshot_t snap) + { + if (unlikely (in_error ())) return; + assert (snap.current == current); + current->links.shrink (snap.num_links); + revert (snap.head, snap.tail); + } + + void revert (char *snap_head, + char *snap_tail) { - assert (snap.head <= head); - assert (tail <= snap.tail); - head = snap.head; - tail = snap.tail; + if (unlikely (in_error ())) return; + assert (snap_head <= head); + assert (tail <= snap_tail); + head = snap_head; + tail = snap_tail; discard_stale_objects (); } void discard_stale_objects () { + if (unlikely (in_error ())) return; while (packed.length > 1 && packed.tail ()->head < tail) { @@ -261,9 +350,12 @@ struct hb_serialize_context_t } template - void add_link (T &ofs, objidx_t objidx, const void *base = nullptr) + void add_link (T &ofs, objidx_t objidx, + whence_t whence = Head, + unsigned bias = 0) { static_assert (sizeof (T) == 2 || sizeof (T) == 4, ""); + if (unlikely (in_error ())) return; if (!objidx) return; @@ -271,18 +363,25 @@ struct hb_serialize_context_t assert (current); assert (current->head <= (const char *) &ofs); - if (!base) - base = current->head; - else - assert (current->head <= (const char *) base); - auto& link = *current->links.push (); + link.is_wide = sizeof (T) == 4; + link.is_signed = hb_is_signed (hb_unwrap_type (T)); + link.whence = (unsigned) whence; link.position = (const char *) &ofs - current->head; - link.bias = (const char *) base - current->head; + link.bias = bias; link.objidx = objidx; } + unsigned to_bias (const void *base) const + { + if (unlikely (in_error ())) return 0; + if (!base) return 0; + assert (current); + assert (current->head <= (const char *) base); + return (const char *) base - current->head; + } + void resolve_links () { if (unlikely (in_error ())) return; @@ -291,30 +390,41 @@ struct hb_serialize_context_t assert (packed.length > 1); for (const object_t* parent : ++hb_iter (packed)) - { for (const object_t::link_t &link : parent->links) { const object_t* child = packed[link.objidx]; - assert (link.bias <= (size_t) (parent->tail - parent->head)); - unsigned offset = (child->head - parent->head) - link.bias; + if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; } + unsigned offset = 0; + switch ((whence_t) link.whence) { + case Head: offset = child->head - parent->head; break; + case Tail: offset = child->head - parent->tail; break; + case Absolute: offset = (head - start) + (child->head - tail); break; + } - if (link.is_wide) + assert (offset >= link.bias); + offset -= link.bias; + if (link.is_signed) { - auto &off = * ((BEInt *) (parent->head + link.position)); - assert (0 == off); - check_assign (off, offset); + if (link.is_wide) + assign_offset (parent, link, offset); + else + assign_offset (parent, link, offset); } else { - auto &off = * ((BEInt *) (parent->head + link.position)); - assert (0 == off); - check_assign (off, offset); + if (link.is_wide) + assign_offset (parent, link, offset); + else + assign_offset (parent, link, offset); } } - } } - unsigned int length () const { return this->head - current->head; } + unsigned int length () const + { + if (unlikely (!current)) return 0; + return this->head - current->head; + } void align (unsigned int alignment) { @@ -330,19 +440,19 @@ struct hb_serialize_context_t Type *start_embed (const Type &obj) const { return start_embed (hb_addressof (obj)); } - /* Following two functions exist to allow setting breakpoint on. */ - void err_ran_out_of_room () { this->ran_out_of_room = true; } - void err_other_error () { this->successful = false; } + bool err (hb_serialize_error_t err_type) + { + return !bool ((errors = (errors | err_type))); + } template Type *allocate_size (unsigned int size) { - if (unlikely (!this->successful)) return nullptr; + if (unlikely (in_error ())) return nullptr; if (this->tail - this->head < ptrdiff_t (size)) { - err_ran_out_of_room (); - this->successful = false; + err (HB_SERIALIZE_ERROR_OUT_OF_ROOM); return nullptr; } memset (this->head, 0, size); @@ -353,9 +463,7 @@ struct hb_serialize_context_t template Type *allocate_min () - { - return this->allocate_size (Type::min_size); - } + { return this->allocate_size (Type::min_size); } template Type *embed (const Type *obj) @@ -392,12 +500,20 @@ struct hb_serialize_context_t Type *copy (const Type *src, Ts&&... ds) { return copy (*src, hb_forward (ds)...); } + template + void copy_all (Iterator it, Ts&&... ds) + { for (decltype (*it) _ : it) copy (_, hb_forward (ds)...); } + template hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; } template Type *extend_size (Type *obj, unsigned int size) { + if (unlikely (in_error ())) return nullptr; + assert (this->start <= (char *) obj); assert ((char *) obj <= this->head); assert ((char *) obj + size >= this->head); @@ -423,18 +539,16 @@ struct hb_serialize_context_t /* Output routines. */ hb_bytes_t copy_bytes () const { - assert (this->successful); + assert (successful ()); /* Copy both items from head side and tail side... */ unsigned int len = (this->head - this->start) + (this->end - this->tail); + char *p = (char *) malloc (len); - if (p) - { - memcpy (p, this->start, this->head - this->start); - memcpy (p + (this->head - this->start), this->tail, this->end - this->tail); - } - else - return hb_bytes_t (); + if (unlikely (!p)) return hb_bytes_t (); + + memcpy (p, this->start, this->head - this->start); + memcpy (p + (this->head - this->start), this->tail, this->end - this->tail); return hb_bytes_t (p, len); } template @@ -448,11 +562,22 @@ struct hb_serialize_context_t (char *) b.arrayZ, free); } + const hb_vector_t& object_graph() const + { return packed; } + + private: + template + void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) + { + auto &off = * ((BEInt *) (parent->head + link.position)); + assert (0 == off); + check_assign (off, offset, HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); + } + public: /* TODO Make private. */ char *start, *head, *tail, *end; unsigned int debug_depth; - bool successful; - bool ran_out_of_room; + hb_serialize_error_t errors; private: @@ -469,5 +594,4 @@ struct hb_serialize_context_t hb_hashmap_t packed_map; }; - #endif /* HB_SERIALIZE_HH */ diff --git a/src/hb-set-digest.hh b/src/hb-set-digest.hh index b97526f775070e8c0d0bc7af6d6133eab660af85..1ef1ba5fb28be42374785bbd2615d0b0c5ffaa26 100644 --- a/src/hb-set-digest.hh +++ b/src/hb-set-digest.hh @@ -87,6 +87,8 @@ struct hb_set_digest_lowest_bits_t } } template + void add_array (const hb_array_t& arr) { add_array (&arr, arr.len ()); } + template bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { for (unsigned int i = 0; i < count; i++) @@ -96,6 +98,8 @@ struct hb_set_digest_lowest_bits_t } return true; } + template + bool add_sorted_array (const hb_sorted_array_t& arr) { return add_sorted_array (&arr, arr.len ()); } bool may_have (hb_codepoint_t g) const { return !!(mask & mask_for (g)); } @@ -135,12 +139,16 @@ struct hb_set_digest_combiner_t tail.add_array (array, count, stride); } template + void add_array (const hb_array_t& arr) { add_array (&arr, arr.len ()); } + template bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T)) { head.add_sorted_array (array, count, stride); tail.add_sorted_array (array, count, stride); return true; } + template + bool add_sorted_array (const hb_sorted_array_t& arr) { return add_sorted_array (&arr, arr.len ()); } bool may_have (hb_codepoint_t g) const { diff --git a/src/hb-set.cc b/src/hb-set.cc index 10638a7e6d5441054bebf2d171c5c544b03a5a9c..86bf70034c92f058aaac5b2508edc03279731397 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -30,11 +30,11 @@ /** * SECTION:hb-set * @title: hb-set - * @short_description: Object representing a set of integers + * @short_description: Objects representing a set of integers * @include: hb.h * * Set objects represent a mathematical set of integer values. They are - * used in non-shaping API to query certain set of characters or glyphs, + * used in non-shaping APIs to query certain sets of characters or glyphs, * or other integer values. **/ @@ -42,7 +42,9 @@ /** * hb_set_create: (Xconstructor) * - * Return value: (transfer full): + * Creates a new, initially empty set. + * + * Return value: (transfer full): The new #hb_set_t * * Since: 0.9.2 **/ @@ -62,21 +64,25 @@ hb_set_create () /** * hb_set_get_empty: * - * Return value: (transfer full): + * Fetches the singleton empty #hb_set_t. + * + * Return value: (transfer full): The empty #hb_set_t * * Since: 0.9.2 **/ hb_set_t * hb_set_get_empty () { - return const_cast (&Null(hb_set_t)); + return const_cast (&Null (hb_set_t)); } /** * hb_set_reference: (skip) - * @set: a set. + * @set: A set * - * Return value: (transfer full): + * Increases the reference count on a set. + * + * Return value: (transfer full): The set * * Since: 0.9.2 **/ @@ -88,7 +94,11 @@ hb_set_reference (hb_set_t *set) /** * hb_set_destroy: (skip) - * @set: a set. + * @set: A set + * + * Decreases the reference count on a set. When + * the reference count reaches zero, the set is + * destroyed, freeing all memory. * * Since: 0.9.2 **/ @@ -104,13 +114,15 @@ hb_set_destroy (hb_set_t *set) /** * hb_set_set_user_data: (skip) - * @set: a set. - * @key: - * @data: - * @destroy: - * @replace: + * @set: A set + * @key: The user-data key to set + * @data: A pointer to the user data to set + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * - * Return value: + * Attaches a user-data key/data pair to the specified set. + * + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ @@ -126,10 +138,13 @@ hb_set_set_user_data (hb_set_t *set, /** * hb_set_get_user_data: (skip) - * @set: a set. - * @key: + * @set: A set + * @key: The user-data key to query * - * Return value: (transfer none): + * Fetches the user data associated with the specified key, + * attached to the specified set. + * + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.2 **/ @@ -143,11 +158,11 @@ hb_set_get_user_data (hb_set_t *set, /** * hb_set_allocation_successful: - * @set: a set. + * @set: A set * - * + * Tests whether memory allocation for a set was successful. * - * Return value: + * Return value: %true if allocation succeeded, %false otherwise * * Since: 0.9.2 **/ @@ -159,15 +174,18 @@ hb_set_allocation_successful (const hb_set_t *set) /** * hb_set_clear: - * @set: a set. + * @set: A set * - * + * Clears out the contents of a set. * * Since: 0.9.2 **/ void hb_set_clear (hb_set_t *set) { + if (unlikely (hb_object_is_immutable (set))) + return; + set->clear (); } @@ -175,9 +193,9 @@ hb_set_clear (hb_set_t *set) * hb_set_is_empty: * @set: a set. * - * + * Tests whether a set is empty (contains no elements). * - * Return value: + * Return value: %true if @set is empty * * Since: 0.9.7 **/ @@ -189,12 +207,12 @@ hb_set_is_empty (const hb_set_t *set) /** * hb_set_has: - * @set: a set. - * @codepoint: + * @set: A set + * @codepoint: The element to query * - * + * Tests whether @codepoint belongs to @set. * - * Return value: + * Return value: %true if @codepoint is in @set, %false otherwise * * Since: 0.9.2 **/ @@ -207,10 +225,10 @@ hb_set_has (const hb_set_t *set, /** * hb_set_add: - * @set: a set. - * @codepoint: + * @set: A set + * @codepoint: The element to add to @set * - * + * Adds @codepoint to @set. * * Since: 0.9.2 **/ @@ -223,11 +241,12 @@ hb_set_add (hb_set_t *set, /** * hb_set_add_range: - * @set: a set. - * @first: - * @last: + * @set: A set + * @first: The first element to add to @set + * @last: The final element to add to @set * - * + * Adds all of the elements from @first to @last + * (inclusive) to @set. * * Since: 0.9.7 **/ @@ -241,10 +260,10 @@ hb_set_add_range (hb_set_t *set, /** * hb_set_del: - * @set: a set. - * @codepoint: + * @set: A set + * @codepoint: Removes @codepoint from @set * - * + * Removes @codepoint from @set. * * Since: 0.9.2 **/ @@ -257,11 +276,12 @@ hb_set_del (hb_set_t *set, /** * hb_set_del_range: - * @set: a set. - * @first: - * @last: + * @set: A set + * @first: The first element to remove from @set + * @last: The final element to remove from @set * - * + * Removes all of the elements from @first to @last + * (inclusive) from @set. * * Since: 0.9.7 **/ @@ -275,12 +295,13 @@ hb_set_del_range (hb_set_t *set, /** * hb_set_is_equal: - * @set: a set. - * @other: other set. + * @set: A set + * @other: Another set * - * + * Tests whether @set and @other are equal (contain the same + * elements). * - * Return value: %TRUE if the two sets are equal, %FALSE otherwise. + * Return value: %true if the two sets are equal, %false otherwise. * * Since: 0.9.7 **/ @@ -293,12 +314,12 @@ hb_set_is_equal (const hb_set_t *set, /** * hb_set_is_subset: - * @set: a set. - * @larger_set: other set. - * + * @set: A set + * @larger_set: Another set * + * Tests whether @set is a subset of @larger_set. * - * Return value: %TRUE if the @set is a subset of (or equal to) @larger_set, %FALSE otherwise. + * Return value: %true if the @set is a subset of (or equal to) @larger_set, %false otherwise. * * Since: 1.8.1 **/ @@ -311,10 +332,10 @@ hb_set_is_subset (const hb_set_t *set, /** * hb_set_set: - * @set: a set. - * @other: + * @set: A set + * @other: Another set * - * + * Makes the contents of @set equal to the contents of @other. * * Since: 0.9.2 **/ @@ -327,10 +348,10 @@ hb_set_set (hb_set_t *set, /** * hb_set_union: - * @set: a set. - * @other: + * @set: A set + * @other: Another set * - * + * Makes @set the union of @set and @other. * * Since: 0.9.2 **/ @@ -343,10 +364,10 @@ hb_set_union (hb_set_t *set, /** * hb_set_intersect: - * @set: a set. - * @other: + * @set: A set + * @other: Another set * - * + * Makes @set the intersection of @set and @other. * * Since: 0.9.2 **/ @@ -359,10 +380,10 @@ hb_set_intersect (hb_set_t *set, /** * hb_set_subtract: - * @set: a set. - * @other: + * @set: A set + * @other: Another set * - * + * Subtracts the contents of @other from @set. * * Since: 0.9.2 **/ @@ -375,10 +396,11 @@ hb_set_subtract (hb_set_t *set, /** * hb_set_symmetric_difference: - * @set: a set. - * @other: + * @set: A set + * @other: Another set * - * + * Makes @set the symmetric difference of @set + * and @other. * * Since: 0.9.2 **/ @@ -392,9 +414,9 @@ hb_set_symmetric_difference (hb_set_t *set, #ifndef HB_DISABLE_DEPRECATED /** * hb_set_invert: - * @set: a set. + * @set: A set * - * + * Inverts the contents of @set. * * Since: 0.9.10 * @@ -408,11 +430,11 @@ hb_set_invert (hb_set_t *set HB_UNUSED) /** * hb_set_get_population: - * @set: a set. + * @set: A set * - * Returns the number of numbers in the set. + * Returns the number of elements in the set. * - * Return value: set population. + * Return value: The population of @set * * Since: 0.9.7 **/ @@ -424,11 +446,11 @@ hb_set_get_population (const hb_set_t *set) /** * hb_set_get_min: - * @set: a set. + * @set: A set * - * Finds the minimum number in the set. + * Finds the smallest element in the set. * - * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty. + * Return value: minimum of @set, or #HB_SET_VALUE_INVALID if @set is empty. * * Since: 0.9.7 **/ @@ -440,11 +462,11 @@ hb_set_get_min (const hb_set_t *set) /** * hb_set_get_max: - * @set: a set. + * @set: A set * - * Finds the maximum number in the set. + * Finds the largest element in the set. * - * Return value: minimum of the set, or %HB_SET_VALUE_INVALID if set is empty. + * Return value: maximum of @set, or #HB_SET_VALUE_INVALID if @set is empty. * * Since: 0.9.7 **/ @@ -456,14 +478,15 @@ hb_set_get_max (const hb_set_t *set) /** * hb_set_next: - * @set: a set. - * @codepoint: (inout): + * @set: A set + * @codepoint: (inout): Input = Code point to query + * Output = Code point retrieved * - * Gets the next number in @set that is greater than current value of @codepoint. + * Fetches the next element in @set that is greater than current value of @codepoint. * - * Set @codepoint to %HB_SET_VALUE_INVALID to get started. + * Set @codepoint to #HB_SET_VALUE_INVALID to get started. * - * Return value: whether there was a next value. + * Return value: %true if there was a next value, %false otherwise * * Since: 0.9.2 **/ @@ -476,14 +499,15 @@ hb_set_next (const hb_set_t *set, /** * hb_set_previous: - * @set: a set. - * @codepoint: (inout): + * @set: A set + * @codepoint: (inout): Input = Code point to query + * Output = Code point retrieved * - * Gets the previous number in @set that is lower than current value of @codepoint. + * Fetches the previous element in @set that is lower than current value of @codepoint. * - * Set @codepoint to %HB_SET_VALUE_INVALID to get started. + * Set @codepoint to #HB_SET_VALUE_INVALID to get started. * - * Return value: whether there was a previous value. + * Return value: %true if there was a previous value, %false otherwise * * Since: 1.8.0 **/ @@ -496,16 +520,17 @@ hb_set_previous (const hb_set_t *set, /** * hb_set_next_range: - * @set: a set. - * @first: (out): output first codepoint in the range. - * @last: (inout): input current last and output last codepoint in the range. + * @set: A set + * @first: (out): The first code point in the range + * @last: (inout): Input = The current last code point in the range + * Output = The last code point in the range * - * Gets the next consecutive range of numbers in @set that + * Fetches the next consecutive range of elements in @set that * are greater than current value of @last. * - * Set @last to %HB_SET_VALUE_INVALID to get started. + * Set @last to #HB_SET_VALUE_INVALID to get started. * - * Return value: whether there was a next range. + * Return value: %true if there was a next range, %false otherwise * * Since: 0.9.7 **/ @@ -519,16 +544,17 @@ hb_set_next_range (const hb_set_t *set, /** * hb_set_previous_range: - * @set: a set. - * @first: (inout): input current first and output first codepoint in the range. - * @last: (out): output last codepoint in the range. + * @set: A set + * @first: (inout): Input = The current first code point in the range + * Output = The first code point in the range + * @last: (out): The last code point in the range * - * Gets the previous consecutive range of numbers in @set that - * are less than current value of @first. + * Fetches the previous consecutive range of elements in @set that + * are greater than current value of @last. * - * Set @first to %HB_SET_VALUE_INVALID to get started. + * Set @first to #HB_SET_VALUE_INVALID to get started. * - * Return value: whether there was a previous range. + * Return value: %true if there was a previous range, %false otherwise * * Since: 1.8.0 **/ diff --git a/src/hb-set.h b/src/hb-set.h index ed0e05db2e4e94784c940a2db69b2d5dba63f023..0ad27f4bbdab20851b0e72f568f41eb930c47676 100644 --- a/src/hb-set.h +++ b/src/hb-set.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -36,11 +36,24 @@ HB_BEGIN_DECLS -/* +/** + * HB_SET_VALUE_INVALID: + * + * Unset #hb_set_t value. + * * Since: 0.9.21 */ #define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1) +/** + * hb_set_t: + * + * Data type for holding a set of integers. #hb_set_t's are + * used to gather and contain glyph IDs, Unicode code + * points, and various other collections of discrete + * values. + * + **/ typedef struct hb_set_t hb_set_t; diff --git a/src/hb-set.hh b/src/hb-set.hh index ad449d0ce7a225e23b535f95cd4a83ed6110fd67..9404ba2615b8169b1f6bffcd89eda73b8fc9fee2 100644 --- a/src/hb-set.hh +++ b/src/hb-set.hh @@ -63,7 +63,7 @@ struct hb_set_t bool is_empty () const { for (unsigned int i = 0; i < len (); i++) - if (v[i]) + if (v[i]) return false; return true; } @@ -77,7 +77,7 @@ struct hb_set_t elt_t *la = &elt (a); elt_t *lb = &elt (b); if (la == lb) - *la |= (mask (b) << 1) - mask(a); + *la |= (mask (b) << 1) - mask(a); else { *la |= ~(mask (a) - 1); @@ -89,6 +89,23 @@ struct hb_set_t } } + void del_range (hb_codepoint_t a, hb_codepoint_t b) + { + elt_t *la = &elt (a); + elt_t *lb = &elt (b); + if (la == lb) + *la &= ~((mask (b) << 1) - mask(a)); + else + { + *la &= mask (a) - 1; + la++; + + memset (la, 0, (char *) lb - (char *) la); + + *lb &= ~((mask (b) << 1) - 1); + } + } + bool is_equal (const page_t *other) const { return 0 == hb_memcmp (&v, &other->v, sizeof (v)); @@ -98,7 +115,7 @@ struct hb_set_t { unsigned int pop = 0; for (unsigned int i = 0; i < len (); i++) - pop += hb_popcount (v[i]); + pop += hb_popcount (v[i]); return pop; } @@ -135,13 +152,22 @@ struct hb_set_t unsigned int i = m / ELT_BITS; unsigned int j = m & ELT_MASK; - const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1); - for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i]) + /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */ + const elt_t mask = j < 8 * sizeof (elt_t) - 1 ? + ((elt_t (1) << (j + 1)) - 1) : + (elt_t) -1; + const elt_t vv = v[i] & mask; + const elt_t *p = &vv; + while (true) + { if (*p) { *codepoint = i * ELT_BITS + elt_get_max (*p); return true; } + if ((int) i <= 0) break; + p = &v[--i]; + } *codepoint = INVALID; return false; @@ -149,14 +175,14 @@ struct hb_set_t hb_codepoint_t get_min () const { for (unsigned int i = 0; i < len (); i++) - if (v[i]) + if (v[i]) return i * ELT_BITS + elt_get_min (v[i]); return INVALID; } hb_codepoint_t get_max () const { for (int i = len () - 1; i >= 0; i--) - if (v[i]) + if (v[i]) return i * ELT_BITS + elt_get_max (v[i]); return 0; } @@ -218,7 +244,7 @@ struct hb_set_t bool resize (unsigned int count) { - if (unlikely (!successful)) return false; + if (unlikely (count > pages.length && !successful)) return false; if (!pages.resize (count) || !page_map.resize (count)) { pages.resize (page_map.length); @@ -230,30 +256,26 @@ struct hb_set_t void reset () { - if (unlikely (hb_object_is_immutable (this))) - return; - clear (); successful = true; + clear (); } void clear () { - if (unlikely (hb_object_is_immutable (this))) - return; - population = 0; - page_map.resize (0); - pages.resize (0); + if (resize (0)) + population = 0; } bool is_empty () const { unsigned int count = pages.length; for (unsigned int i = 0; i < count; i++) if (!pages[i].is_empty ()) - return false; + return false; return true; } + explicit operator bool () const { return !is_empty (); } - void dirty () { population = (unsigned int) -1; } + void dirty () { population = UINT_MAX; } void add (hb_codepoint_t g) { @@ -315,6 +337,8 @@ struct hb_set_t while (count && (g = *array, start <= g && g < end)); } } + template + void add_array (const hb_array_t& arr) { add_array (&arr, arr.len ()); } /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ @@ -333,9 +357,9 @@ struct hb_set_t unsigned int end = major_start (m + 1); do { - /* If we try harder we can change the following comparison to <=; + /* If we try harder we can change the following comparison to <=; * Not sure if it's worth it. */ - if (g < last_g) return false; + if (g < last_g) return false; last_g = g; page->add (g); @@ -346,6 +370,8 @@ struct hb_set_t } return true; } + template + bool add_sorted_array (const hb_sorted_array_t& arr) { return add_sorted_array (&arr, arr.len ()); } void del (hb_codepoint_t g) { @@ -357,14 +383,62 @@ struct hb_set_t dirty (); page->del (g); } + + private: + void del_pages (int ds, int de) + { + if (ds <= de) + { + // Pre-allocate the workspace that compact() will need so we can bail on allocation failure + // before attempting to rewrite the page map. + hb_vector_t compact_workspace; + if (unlikely (!allocate_compact_workspace (compact_workspace))) return; + + unsigned int write_index = 0; + for (unsigned int i = 0; i < page_map.length; i++) + { + int m = (int) page_map[i].major; + if (m < ds || de < m) + page_map[write_index++] = page_map[i]; + } + compact (compact_workspace, write_index); + resize (write_index); + } + } + + + public: void del_range (hb_codepoint_t a, hb_codepoint_t b) { /* TODO perform op even if !successful. */ - /* TODO Optimize, like add_range(). */ if (unlikely (!successful)) return; - for (unsigned int i = a; i < b + 1; i++) - del (i); + if (unlikely (a > b || a == INVALID || b == INVALID)) return; + dirty (); + unsigned int ma = get_major (a); + unsigned int mb = get_major (b); + /* Delete pages from ds through de if ds <= de. */ + int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1); + int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1); + if (ds > de || (int) ma < ds) + { + page_t *page = page_for (a); + if (page) + { + if (ma == mb) + page->del_range (a, b); + else + page->del_range (a, major_start (ma + 1) - 1); + } + } + if (de < (int) mb && ma != mb) + { + page_t *page = page_for (b); + if (page) + page->del_range (major_start (mb), b); + } + del_pages (ds, de); } + bool get (hb_codepoint_t g) const { const page_t *page = page_for (g); @@ -382,7 +456,10 @@ struct hb_set_t bool operator () (hb_codepoint_t k) const { return has (k); } /* Sink interface. */ - hb_set_t& operator << (hb_codepoint_t v) { add (v); return *this; } + hb_set_t& operator << (hb_codepoint_t v) + { add (v); return *this; } + hb_set_t& operator << (const hb_pair_t& range) + { add_range (range.first, range.second); return *this; } bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { @@ -415,7 +492,7 @@ struct hb_set_t if (other->page_at (b).is_empty ()) { b++; continue; } if (page_map[a].major != other->page_map[b].major || !page_at (a).is_equal (&other->page_at (b))) - return false; + return false; a++; b++; } @@ -436,14 +513,62 @@ struct hb_set_t hb_codepoint_t c = INVALID; while (next (&c)) if (!larger_set->has (c)) - return false; + return false; return true; } + bool allocate_compact_workspace(hb_vector_t& workspace) + { + if (unlikely(!workspace.resize (pages.length))) + { + successful = false; + return false; + } + + return true; + } + + + /* + * workspace should be a pre-sized vector allocated to hold at exactly pages.length + * elements. + */ + void compact (hb_vector_t& workspace, + unsigned int length) + { + assert(workspace.length == pages.length); + hb_vector_t& old_index_to_page_map_index = workspace; + + hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF); + /* TODO(iter) Rewrite as dagger? */ + for (unsigned i = 0; i < length; i++) + old_index_to_page_map_index[page_map[i].index] = i; + + compact_pages (old_index_to_page_map_index); + } + + void compact_pages (const hb_vector_t& old_index_to_page_map_index) + { + unsigned int write_index = 0; + for (unsigned int i = 0; i < pages.length; i++) + { + if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue; + + if (write_index < i) + pages[write_index] = pages[i]; + + page_map[old_index_to_page_map_index[i]].index = write_index; + write_index++; + } + } + template void process (const Op& op, const hb_set_t *other) { + const bool passthru_left = op (1, 0); + const bool passthru_right = op (0, 1); + if (unlikely (!successful)) return; dirty (); @@ -454,35 +579,60 @@ struct hb_set_t unsigned int count = 0, newCount = 0; unsigned int a = 0, b = 0; + unsigned int write_index = 0; + + // Pre-allocate the workspace that compact() will need so we can bail on allocation failure + // before attempting to rewrite the page map. + hb_vector_t compact_workspace; + if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return; + for (; a < na && b < nb; ) { if (page_map[a].major == other->page_map[b].major) { - count++; + if (!passthru_left) + { + // Move page_map entries that we're keeping from the left side set + // to the front of the page_map vector. This isn't necessary if + // passthru_left is set since no left side pages will be removed + // in that case. + if (write_index < a) + page_map[write_index] = page_map[a]; + write_index++; + } + + count++; a++; b++; } else if (page_map[a].major < other->page_map[b].major) { - if (Op::passthru_left) + if (passthru_left) count++; - a++; + a++; } else { - if (Op::passthru_right) + if (passthru_right) count++; - b++; + b++; } } - if (Op::passthru_left) + if (passthru_left) count += na - a; - if (Op::passthru_right) + if (passthru_right) count += nb - b; - if (count > pages.length) - if (!resize (count)) - return; + if (!passthru_left) + { + na = write_index; + next_page = write_index; + compact (compact_workspace, write_index); + } + + if (!resize (count)) + return; + newCount = count; /* Process in-place backward. */ @@ -501,7 +651,7 @@ struct hb_set_t else if (page_map[a - 1].major > other->page_map[b - 1].major) { a--; - if (Op::passthru_left) + if (passthru_left) { count--; page_map[count] = page_map[a]; @@ -510,7 +660,7 @@ struct hb_set_t else { b--; - if (Op::passthru_right) + if (passthru_right) { count--; page_map[count].major = other->page_map[b].major; @@ -519,14 +669,14 @@ struct hb_set_t } } } - if (Op::passthru_left) + if (passthru_left) while (a) { a--; count--; page_map[count] = page_map [a]; } - if (Op::passthru_right) + if (passthru_right) while (b) { b--; @@ -537,6 +687,9 @@ struct hb_set_t } assert (!count); if (pages.length > newCount) + // This resize() doesn't need to be checked because we can't get here + // if the set is currently in_error() and this only resizes downwards + // which will always succeed if the set is not in_error(). resize (newCount); } @@ -657,7 +810,7 @@ struct hb_set_t unsigned int get_population () const { - if (population != (unsigned int) -1) + if (population != UINT_MAX) return population; unsigned int pop = 0; @@ -673,15 +826,15 @@ struct hb_set_t unsigned int count = pages.length; for (unsigned int i = 0; i < count; i++) if (!page_at (i).is_empty ()) - return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min (); + return page_map[i].major * page_t::PAGE_BITS + page_at (i).get_min (); return INVALID; } hb_codepoint_t get_max () const { unsigned int count = pages.length; - for (int i = count - 1; i >= 0; i++) + for (int i = count - 1; i >= 0; i--) if (!page_at (i).is_empty ()) - return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max (); + return page_map[(unsigned) i].major * page_t::PAGE_BITS + page_at (i).get_max (); return INVALID; } @@ -693,8 +846,15 @@ struct hb_set_t struct iter_t : hb_iter_with_fallback_t { static constexpr bool is_sorted_iterator = true; - iter_t (const hb_set_t &s_ = Null(hb_set_t)) : - s (&s_), v (INVALID), l (s->get_population () + 1) { __next__ (); } + iter_t (const hb_set_t &s_ = Null (hb_set_t), + bool init = true) : s (&s_), v (INVALID), l(0) + { + if (init) + { + l = s->get_population () + 1; + __next__ (); + } + } typedef hb_codepoint_t __item_t__; hb_codepoint_t __item__ () const { return v; } @@ -702,7 +862,7 @@ struct hb_set_t void __next__ () { s->next (&v); if (l) l--; } void __prev__ () { s->previous (&v); } unsigned __len__ () const { return l; } - iter_t end () const { return iter_t (*s); } + iter_t end () const { return iter_t (*s, false); } bool operator != (const iter_t& o) const { return s != o.s || v != o.v; } diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index 2b23dee62ca93b4f509b45e75c9357900391a5f5..0d9eaddaa6930ad934bf133911bea78fb07caee4 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -37,10 +37,17 @@ * @short_description: Object representing a shaping plan * @include: hb.h * - * Shape plans are not used for shaping directly, but can be access to query - * certain information about how shaping will perform given a set of input - * parameters (script, language, direction, features, etc.) - * Most client would not need to deal with shape plans directly. + * Shape plans are an internal mechanism. Each plan contains state + * describing how HarfBuzz will shape a particular text segment, based on + * the combination of segment properties and the capabilities in the + * font face in use. + * + * Shape plans are not used for shaping directly, but can be queried to + * access certain information about how shaping will perform, given a set + * of specific input parameters (script, language, direction, features, + * etc.). + * + * Most client programs will not need to deal with shape plans directly. **/ @@ -164,15 +171,16 @@ hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other) /** * hb_shape_plan_create: (Xconstructor) - * @face: - * @props: - * @user_features: (array length=num_user_features): - * @num_user_features: - * @shaper_list: (array zero-terminated=1): + * @face: #hb_face_t to use + * @props: The #hb_segment_properties_t of the segment + * @user_features: (array length=num_user_features): The list of user-selected features + * @num_user_features: The number of user-selected features + * @shaper_list: (array zero-terminated=1): List of shapers to try * - * + * Constructs a shaping plan for a combination of @face, @user_features, @props, + * and @shaper_list. * - * Return value: (transfer full): + * Return value: (transfer full): The shaping plan * * Since: 0.9.7 **/ @@ -189,6 +197,24 @@ hb_shape_plan_create (hb_face_t *face, shaper_list); } +/** + * hb_shape_plan_create2: (Xconstructor) + * @face: #hb_face_t to use + * @props: The #hb_segment_properties_t of the segment + * @user_features: (array length=num_user_features): The list of user-selected features + * @num_user_features: The number of user-selected features + * @coords: (array length=num_coords): The list of variation-space coordinates + * @num_coords: The number of variation-space coordinates + * @shaper_list: (array zero-terminated=1): List of shapers to try + * + * The variable-font version of #hb_shape_plan_create. + * Constructs a shaping plan for a combination of @face, @user_features, @props, + * and @shaper_list, plus the variation-space coordinates @coords. + * + * Return value: (transfer full): The shaping plan + * + * Since: 1.4.0 + **/ hb_shape_plan_t * hb_shape_plan_create2 (hb_face_t *face, const hb_segment_properties_t *props, @@ -248,25 +274,25 @@ bail: /** * hb_shape_plan_get_empty: * - * + * Fetches the singleton empty shaping plan. * - * Return value: (transfer full): + * Return value: (transfer full): The empty shaping plan * * Since: 0.9.7 **/ hb_shape_plan_t * hb_shape_plan_get_empty () { - return const_cast (&Null(hb_shape_plan_t)); + return const_cast (&Null (hb_shape_plan_t)); } /** * hb_shape_plan_reference: (skip) - * @shape_plan: a shape plan. + * @shape_plan: A shaping plan * - * + * Increases the reference count on the given shaping plan. * - * Return value: (transfer full): + * Return value: (transfer full): @shape_plan * * Since: 0.9.7 **/ @@ -278,9 +304,11 @@ hb_shape_plan_reference (hb_shape_plan_t *shape_plan) /** * hb_shape_plan_destroy: (skip) - * @shape_plan: a shape plan. + * @shape_plan: A shaping plan * - * + * Decreases the reference count on the given shaping plan. When the + * reference count reaches zero, the shaping plan is destroyed, + * freeing all memory. * * Since: 0.9.7 **/ @@ -298,15 +326,15 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) /** * hb_shape_plan_set_user_data: (skip) - * @shape_plan: a shape plan. - * @key: - * @data: - * @destroy: - * @replace: + * @shape_plan: A shaping plan + * @key: The user-data key to set + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * - * + * Attaches a user-data key/data pair to the given shaping plan. * - * Return value: + * Return value: %true if success, %false otherwise. * * Since: 0.9.7 **/ @@ -322,12 +350,13 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan, /** * hb_shape_plan_get_user_data: (skip) - * @shape_plan: a shape plan. - * @key: + * @shape_plan: A shaping plan + * @key: The user-data key to query * - * + * Fetches the user data associated with the specified key, + * attached to the specified shaping plan. * - * Return value: (transfer none): + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.7 **/ @@ -340,11 +369,11 @@ hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan, /** * hb_shape_plan_get_shaper: - * @shape_plan: a shape plan. + * @shape_plan: A shaping plan * - * + * Fetches the shaper from a given shaping plan. * - * Return value: (transfer none): + * Return value: (transfer none): The shaper * * Since: 0.9.7 **/ @@ -355,26 +384,12 @@ hb_shape_plan_get_shaper (hb_shape_plan_t *shape_plan) } -/** - * hb_shape_plan_execute: - * @shape_plan: a shape plan. - * @font: a font. - * @buffer: a buffer. - * @features: (array length=num_features): - * @num_features: - * - * - * - * Return value: - * - * Since: 0.9.7 - **/ -hb_bool_t -hb_shape_plan_execute (hb_shape_plan_t *shape_plan, - hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features) +static bool +_hb_shape_plan_execute_internal (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) { DEBUG_MSG_FUNC (SHAPE_PLAN, shape_plan, "num_features=%d shaper_func=%p, shaper_name=%s", @@ -386,7 +401,8 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, return true; assert (!hb_object_is_immutable (buffer)); - assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE); + + buffer->assert_unicode (); if (unlikely (hb_object_is_inert (shape_plan))) return false; @@ -412,6 +428,36 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, return false; } +/** + * hb_shape_plan_execute: + * @shape_plan: A shaping plan + * @font: The #hb_font_t to use + * @buffer: The #hb_buffer_t to work upon + * @features: (array length=num_features): Features to enable + * @num_features: The number of features to enable + * + * Executes the given shaping plan on the specified buffer, using + * the given @font and @features. + * + * Return value: %true if success, %false otherwise. + * + * Since: 0.9.7 + **/ +hb_bool_t +hb_shape_plan_execute (hb_shape_plan_t *shape_plan, + hb_font_t *font, + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned int num_features) +{ + bool ret = _hb_shape_plan_execute_internal (shape_plan, font, buffer, + features, num_features); + + if (ret && buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) + buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; + + return ret; +} /* @@ -420,15 +466,16 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, /** * hb_shape_plan_create_cached: - * @face: - * @props: - * @user_features: (array length=num_user_features): - * @num_user_features: - * @shaper_list: (array zero-terminated=1): + * @face: #hb_face_t to use + * @props: The #hb_segment_properties_t of the segment + * @user_features: (array length=num_user_features): The list of user-selected features + * @num_user_features: The number of user-selected features + * @shaper_list: (array zero-terminated=1): List of shapers to try * - * + * Creates a cached shaping plan suitable for reuse, for a combination + * of @face, @user_features, @props, and @shaper_list. * - * Return value: (transfer full): + * Return value: (transfer full): The shaping plan * * Since: 0.9.7 **/ @@ -445,6 +492,25 @@ hb_shape_plan_create_cached (hb_face_t *face, shaper_list); } +/** + * hb_shape_plan_create_cached2: + * @face: #hb_face_t to use + * @props: The #hb_segment_properties_t of the segment + * @user_features: (array length=num_user_features): The list of user-selected features + * @num_user_features: The number of user-selected features + * @coords: (array length=num_coords): The list of variation-space coordinates + * @num_coords: The number of variation-space coordinates + * @shaper_list: (array zero-terminated=1): List of shapers to try + * + * The variable-font version of #hb_shape_plan_create_cached. + * Creates a cached shaping plan suitable for reuse, for a combination + * of @face, @user_features, @props, and @shaper_list, plus the + * variation-space coordinates @coords. + * + * Return value: (transfer full): The shaping plan + * + * Since: 1.4.0 + **/ hb_shape_plan_t * hb_shape_plan_create_cached2 (hb_face_t *face, const hb_segment_properties_t *props, @@ -481,8 +547,8 @@ retry: for (hb_face_t::plan_node_t *node = cached_plan_nodes; node; node = node->next) if (node->shape_plan->key.equal (&key)) { - DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); - return hb_shape_plan_reference (node->shape_plan); + DEBUG_MSG_FUNC (SHAPE_PLAN, node->shape_plan, "fulfilled from cache"); + return hb_shape_plan_reference (node->shape_plan); } } diff --git a/src/hb-shape-plan.h b/src/hb-shape-plan.h index b62ae7ca3508fda86785308e77bdf83a5f86ad99..fc7c0418992f7f5c372daced0f6fffeeb70b61f8 100644 --- a/src/hb-shape-plan.h +++ b/src/hb-shape-plan.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -36,6 +36,20 @@ HB_BEGIN_DECLS +/** + * hb_shape_plan_t: + * + * Data type for holding a shaping plan. + * + * Shape plans contain information about how HarfBuzz will shape a + * particular text segment, based on the segment's properties and the + * capabilities in the font face in use. + * + * Shape plans can be queried about how shaping will perform, given a set + * of specific input parameters (script, language, direction, features, + * etc.). + * + **/ typedef struct hb_shape_plan_t hb_shape_plan_t; HB_EXTERN hb_shape_plan_t * diff --git a/src/hb-shape.cc b/src/hb-shape.cc index deff77bedcdf9f0e24360bf0db7514439361877b..c442f4403bb4f65a77c5214e24f5edf59133a6dd 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -111,10 +111,10 @@ hb_shape_list_shapers () * hb_shape_full: * @font: an #hb_font_t to use for shaping * @buffer: an #hb_buffer_t to shape - * @features: (array length=num_features) (allow-none): an array of user + * @features: (array length=num_features) (nullable): an array of user * specified #hb_feature_t or %NULL * @num_features: the length of @features array - * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated + * @shaper_list: (array zero-terminated=1) (nullable): a %NULL-terminated * array of shapers to use or %NULL * * See hb_shape() for details. If @shaper_list is not %NULL, the specified @@ -139,8 +139,6 @@ hb_shape_full (hb_font_t *font, hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); hb_shape_plan_destroy (shape_plan); - if (res) - buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; return res; } @@ -148,13 +146,15 @@ hb_shape_full (hb_font_t *font, * hb_shape: * @font: an #hb_font_t to use for shaping * @buffer: an #hb_buffer_t to shape - * @features: (array length=num_features) (allow-none): an array of user + * @features: (array length=num_features) (nullable): an array of user * specified #hb_feature_t or %NULL * @num_features: the length of @features array * * Shapes @buffer using @font turning its Unicode characters content to * positioned glyphs. If @features is not %NULL, it will be used to control the - * features applied during shaping. + * features applied during shaping. If two @features have the same tag but + * overlapping ranges the value of the feature with the higher index takes + * precedence. * * Since: 0.9.2 **/ diff --git a/src/hb-shape.h b/src/hb-shape.h index 39507ff744b54d6bc0a2f9701eb17b9183e05bd4..922f8c011ec31fb9742498a11310abfe37d56e87 100644 --- a/src/hb-shape.h +++ b/src/hb-shape.h @@ -26,7 +26,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif diff --git a/src/hb-shaper.hh b/src/hb-shaper.hh index 79dc5d07e099844165f3d88679dcfd5bc0839d3d..b4138a324ff48df823b9ec30b295a1b206d7e2c1 100644 --- a/src/hb-shaper.hh +++ b/src/hb-shaper.hh @@ -102,7 +102,7 @@ template struct hb_shaper_object static void destroy (Type *p) { HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (p); } \ }; \ \ - static_assert (true, "") /* Require semicolon. */ + static_assert (true, "") /* Require semicolon after. */ template diff --git a/src/hb-static.cc b/src/hb-static.cc index 08a2f21363e88ce44168a739b6088f5171114c1a..ec4b24147090c461707db3f077dd265187aca082 100644 --- a/src/hb-static.cc +++ b/src/hb-static.cc @@ -43,6 +43,7 @@ uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof /*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF}; +DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) = {0xFF,0xFF,0xFF,0xFF}; DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00}; DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00}; DEFINE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup) = {0x00,0x00,0x00,0x01, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00}; @@ -51,6 +52,9 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF}; const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; + +/* hb_face_t */ + unsigned int hb_face_t::load_num_glyphs () const { @@ -73,4 +77,37 @@ hb_face_t::load_upem () const return ret; } + +/* hb_user_data_array_t */ + +bool +hb_user_data_array_t::set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + if (!key) + return false; + + if (replace) { + if (!data && !destroy) { + items.remove (key, lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, lock, (bool) replace); + + return ret; +} + +void * +hb_user_data_array_t::get (hb_user_data_key_t *key) +{ + hb_user_data_item_t item = {nullptr, nullptr, nullptr}; + + return items.find (key, &item, lock) ? item.data : nullptr; +} + + #endif diff --git a/src/hb-string-array.hh b/src/hb-string-array.hh index c4cf666d72133da3100bb932d2e8ae987dfbc522..e7ac1192324ce0ee20cee83151a4acc83d0c0f0c 100644 --- a/src/hb-string-array.hh +++ b/src/hb-string-array.hh @@ -37,6 +37,7 @@ #define HB_STRING_ARRAY_TYPE_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr_t) #define HB_STRING_ARRAY_POOL_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr) #define HB_STRING_ARRAY_OFFS_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _msgidx) +#define HB_STRING_ARRAY_LENG_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _length) static const union HB_STRING_ARRAY_TYPE_NAME { struct { @@ -48,7 +49,7 @@ static const union HB_STRING_ARRAY_TYPE_NAME { #include HB_STRING_ARRAY_LIST #undef _S } st; - char str[VAR]; + char str[HB_VAR_ARRAY]; } HB_STRING_ARRAY_POOL_NAME = { @@ -66,6 +67,8 @@ static const unsigned int HB_STRING_ARRAY_OFFS_NAME[] = sizeof (HB_STRING_ARRAY_TYPE_NAME) }; +static const unsigned int HB_STRING_ARRAY_LENG_NAME = ARRAY_LENGTH_CONST (HB_STRING_ARRAY_OFFS_NAME) - 1; + static inline hb_bytes_t HB_STRING_ARRAY_NAME (unsigned int i) { @@ -77,5 +80,6 @@ HB_STRING_ARRAY_NAME (unsigned int i) #undef HB_STRING_ARRAY_TYPE_NAME #undef HB_STRING_ARRAY_POOL_NAME #undef HB_STRING_ARRAY_OFFS_NAME +#undef HB_STRING_ARRAY_LENG_NAME #endif /* HB_STRING_ARRAY_HH */ diff --git a/src/hb-style.cc b/src/hb-style.cc new file mode 100644 index 0000000000000000000000000000000000000000..2f45d119f9efba5dbe96a48868ffc8d6e4fd33e0 --- /dev/null +++ b/src/hb-style.cc @@ -0,0 +1,136 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_STYLE +#ifdef HB_EXPERIMENTAL_API + +#include "hb-ot-var-avar-table.hh" +#include "hb-ot-var-fvar-table.hh" +#include "hb-ot-stat-table.hh" +#include "hb-ot-os2-table.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-face.hh" + +/** + * hb_style_tag_t: + * @HB_STYLE_TAG_ITALIC: Used to vary between non-italic and italic. + * A value of 0 can be interpreted as "Roman" (non-italic); a value of 1 can + * be interpreted as (fully) italic. + * @HB_STYLE_TAG_OPTICAL_SIZE: Used to vary design to suit different text sizes. + * Non-zero. Values can be interpreted as text size, in points. + * @HB_STYLE_TAG_SLANT: Used to vary between upright and slanted text. Values + * must be greater than -90 and less than +90. Values can be interpreted as + * the angle, in counter-clockwise degrees, of oblique slant from whatever the + * designer considers to be upright for that font design. + * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider. + * Non-zero. Values can be interpreted as a percentage of whatever the font + * designer considers “normal width” for that font design. + * @HB_STYLE_TAG_WEIGHT: Used to vary stroke thicknesses or other design details + * to give variation from lighter to blacker. Values can be interpreted in direct + * comparison to values for usWeightClass in the OS/2 table, + * or the CSS font-weight property. + * + * Defined by https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg + * + * Since: EXPERIMENTAL + **/ +typedef enum { + HB_STYLE_TAG_ITALIC = HB_TAG ('i','t','a','l'), + HB_STYLE_TAG_OPTICAL_SIZE = HB_TAG ('o','p','s','z'), + HB_STYLE_TAG_SLANT = HB_TAG ('s','l','n','t'), + HB_STYLE_TAG_WIDTH = HB_TAG ('w','d','t','h'), + HB_STYLE_TAG_WEIGHT = HB_TAG ('w','g','h','t'), + + /*< private >*/ + _HB_STYLE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_style_tag_t; + +/** + * hb_style_get_value: + * @font: a #hb_font_t object. + * @style_tag: a style tag. + * + * Searches variation axes of a hb_font_t object for a specific axis first, + * if not set, then tries to get default style values from different + * tables of the font. + * + * Returns: Corresponding axis or default value to a style tag. + * + * Since: EXPERIMENTAL + **/ +float +hb_style_get_value (hb_font_t *font, hb_tag_t tag) +{ + hb_style_tag_t style_tag = (hb_style_tag_t) tag; + hb_face_t *face = font->face; + +#ifndef HB_NO_VAR + hb_ot_var_axis_info_t axis; + if (hb_ot_var_find_axis_info (face, style_tag, &axis)) + { + if (axis.axis_index < font->num_coords) return font->design_coords[axis.axis_index]; + /* If a face is variable, fvar's default_value is better than STAT records */ + return axis.default_value; + } +#endif + + if (style_tag == HB_STYLE_TAG_OPTICAL_SIZE && font->ptem) + return font->ptem; + + /* STAT */ + float value; + if (face->table.STAT->get_value (style_tag, &value)) + return value; + + switch ((unsigned) style_tag) + { + case HB_STYLE_TAG_ITALIC: + return face->table.OS2->is_italic () || face->table.head->is_italic () ? 1 : 0; + case HB_STYLE_TAG_OPTICAL_SIZE: + { + unsigned int lower, upper; + return face->table.OS2->v5 ().get_optical_size (&lower, &upper) + ? (float) (lower + upper) / 2.f + : 12.f; + } + case HB_STYLE_TAG_SLANT: + return face->table.post->table->italicAngle.to_float (); + case HB_STYLE_TAG_WIDTH: + return face->table.OS2->has_data () + ? face->table.OS2->get_width () + : (face->table.head->is_condensed () ? 75 : 100); + case HB_STYLE_TAG_WEIGHT: + return face->table.OS2->has_data () + ? face->table.OS2->usWeightClass + : (face->table.head->is_bold () ? 700 : 400); + default: + return 0; + } +} + +#endif +#endif diff --git a/src/dump-use-data.cc b/src/hb-style.h similarity index 74% rename from src/dump-use-data.cc rename to src/hb-style.h index d639426b733bd8c2ba1828132dbc33e1b99364ce..f5776cee58a64820a6e5a5291b62d02e1ba6a9d3 100644 --- a/src/dump-use-data.cc +++ b/src/hb-style.h @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Google, Inc. + * Copyright © 2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -20,19 +20,24 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-use.hh" +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) +#error "Include instead." +#endif + +#ifndef HB_STYLE_H +#define HB_STYLE_H + +#include "hb.h" + +HB_BEGIN_DECLS + +#ifdef HB_EXPERIMENTAL_API +HB_EXTERN float +hb_style_get_value (hb_font_t *font, hb_tag_t style_tag); +#endif + +HB_END_DECLS -int -main () -{ - for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) - { - unsigned int category = hb_use_get_category (u); - if (category != USE_O) - printf("U+%04X %u\n", u, category); - } -} +#endif /* HB_STYLE_H */ diff --git a/src/hb-subset-cff-common.cc b/src/hb-subset-cff-common.cc index b71ac57cc082947936bbaf94bcefc51adb748223..04e1db24ace4be2112f26881773ddbc54a36cbd4 100644 --- a/src/hb-subset-cff-common.cc +++ b/src/hb-subset-cff-common.cc @@ -68,8 +68,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, { /* use hb_set to determine the subset of font dicts */ hb_set_t *set = hb_set_create (); - if (set == &Null (hb_set_t)) - return false; + if (unlikely (set == &Null (hb_set_t))) return false; hb_codepoint_t prev_fd = CFF_UNDEF_CODE; for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) { @@ -109,7 +108,7 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, fdmap.add (fd); hb_set_destroy (set); if (unlikely (fdmap.get_population () != subset_fd_count)) - return false; + return false; } /* update each font dict index stored as "code" in fdselect_ranges */ @@ -159,7 +158,7 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c, { TRACE_SERIALIZE (this); FDSELECT3_4 *p = c->allocate_size (size); - if (unlikely (p == nullptr)) return_trace (false); + if (unlikely (!p)) return_trace (false); p->nRanges () = fdselect_ranges.length; for (unsigned int i = 0; i < fdselect_ranges.length; i++) { @@ -185,7 +184,7 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c, { TRACE_SERIALIZE (this); FDSelect *p = c->allocate_min (); - if (unlikely (p == nullptr)) return_trace (false); + if (unlikely (!p)) return_trace (false); p->format = fdselect_format; size -= FDSelect::min_size; @@ -195,7 +194,7 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c, case 0: { FDSelect0 *p = c->allocate_size (size); - if (unlikely (p == nullptr)) return_trace (false); + if (unlikely (!p)) return_trace (false); unsigned int range_index = 0; unsigned int fd = fdselect_ranges[range_index++].code; for (unsigned int i = 0; i < num_glyphs; i++) diff --git a/src/hb-subset-cff-common.hh b/src/hb-subset-cff-common.hh index 6c36e458f53baab17ef7e6db494f261317c576aa..422b20b8d07177fab1845fb8729f679e13642dd4 100644 --- a/src/hb-subset-cff-common.hh +++ b/src/hb-subset-cff-common.hh @@ -44,7 +44,7 @@ struct str_encoder_t void encode_byte (unsigned char b) { - if (unlikely (buff.push (b) == &Crap(unsigned char))) + if (unlikely (buff.push (b) == &Crap (unsigned char))) set_error (); } @@ -110,7 +110,11 @@ struct str_encoder_t void copy_str (const byte_str_t &str) { unsigned int offset = buff.length; - buff.resize (offset + str.length); + if (unlikely (!buff.resize (offset + str.length))) + { + set_error (); + return; + } if (unlikely (buff.length < offset + str.length)) { set_error (); @@ -128,26 +132,17 @@ struct str_encoder_t bool error; }; -struct cff_sub_table_offsets_t { - cff_sub_table_offsets_t () : privateDictsOffset (0) +struct cff_sub_table_info_t { + cff_sub_table_info_t () + : fd_array_link (0), + char_strings_link (0) { - topDictInfo.init (); - FDSelectInfo.init (); - FDArrayInfo.init (); - charStringsInfo.init (); - globalSubrsInfo.init (); - localSubrsInfos.init (); + fd_select.init (); } - ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); } - - table_info_t topDictInfo; - table_info_t FDSelectInfo; - table_info_t FDArrayInfo; - table_info_t charStringsInfo; - unsigned int privateDictsOffset; - table_info_t globalSubrsInfo; - hb_vector_t localSubrsInfos; + table_info_t fd_select; + objidx_t fd_array_link; + objidx_t char_strings_link; }; template @@ -155,40 +150,26 @@ struct cff_top_dict_op_serializer_t : op_serializer_t { bool serialize (hb_serialize_context_t *c, const OPSTR &opstr, - const cff_sub_table_offsets_t &offsets) const + const cff_sub_table_info_t &info) const { TRACE_SERIALIZE (this); switch (opstr.op) { case OpCode_CharStrings: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute)); case OpCode_FDArray: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute)); case OpCode_FDSelect: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute)); default: return_trace (copy_opstr (c, opstr)); } return_trace (true); } - - unsigned int calculate_serialized_size (const OPSTR &opstr) const - { - switch (opstr.op) - { - case OpCode_CharStrings: - case OpCode_FDArray: - case OpCode_FDSelect: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return opstr.str.length; - } - } }; struct cff_font_dict_op_serializer_t : op_serializer_t @@ -202,33 +183,17 @@ struct cff_font_dict_op_serializer_t : op_serializer_t if (opstr.op == OpCode_Private) { /* serialize the private dict size & offset as 2-byte & 4-byte integers */ - if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) || - !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset))) - return_trace (false); - - /* serialize the opcode */ - HBUINT8 *p = c->allocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - *p = OpCode_Private; - - return_trace (true); + return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) && + Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute)); } else { HBUINT8 *d = c->allocate_size (opstr.str.length); - if (unlikely (d == nullptr)) return_trace (false); + if (unlikely (!d)) return_trace (false); memcpy (d, &opstr.str[0], opstr.str.length); } return_trace (true); } - - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - if (opstr.op == OpCode_Private) - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); - else - return opstr.str.length; - } }; struct cff_private_dict_op_serializer_t : op_serializer_t @@ -238,7 +203,7 @@ struct cff_private_dict_op_serializer_t : op_serializer_t bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const unsigned int subrsOffset) const + objidx_t subrs_link) const { TRACE_SERIALIZE (this); @@ -246,31 +211,15 @@ struct cff_private_dict_op_serializer_t : op_serializer_t return true; if (opstr.op == OpCode_Subrs) { - if (desubroutinize || (subrsOffset == 0)) + if (desubroutinize || !subrs_link) return_trace (true); else - return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset)); + return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link)); } else return_trace (copy_opstr (c, opstr)); } - unsigned int calculate_serialized_size (const op_str_t &opstr, - bool has_localsubr=true) const - { - if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) - return 0; - if (opstr.op == OpCode_Subrs) - { - if (desubroutinize || !has_localsubr) - return 0; - else - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op); - } - else - return opstr.str.length; - } - protected: const bool desubroutinize; const bool drop_hints; @@ -300,14 +249,14 @@ struct subr_flattener_t hb_codepoint_t glyph; if (!plan->old_gid_for_new_gid (i, &glyph)) { - /* add an endchar only charstring for a missing glyph if CFF1 */ - if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); - continue; + /* add an endchar only charstring for a missing glyph if CFF1 */ + if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); + continue; } const byte_str_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) - return false; + return false; cs_interpreter_t interp; interp.env.init (str, acc, fd); flatten_param_t param = { flat_charstrings[i], plan->drop_hints }; @@ -456,7 +405,7 @@ struct parsed_cs_str_t : parsed_values_t bool vsindex_dropped; bool has_prefix_; op_code_t prefix_op_; - number_t prefix_num_; + number_t prefix_num_; private: typedef parsed_values_t SUPER; @@ -467,7 +416,8 @@ struct parsed_cs_str_vec_t : hb_vector_t void init (unsigned int len_ = 0) { SUPER::init (); - resize (len_); + if (unlikely (!resize (len_))) + return; for (unsigned int i = 0; i < length; i++) (*this)[i].init (); } @@ -516,19 +466,19 @@ struct subr_subset_param_t template void set_current_str (ENV &env, bool calling) { - parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); - if (likely (parsed_str != nullptr)) + parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); + if (unlikely (!parsed_str)) { - /* If the called subroutine is parsed partially but not completely yet, - * it must be because we are calling it recursively. - * Handle it as an error. */ - if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) - env.set_error (); - else - current_parsed_str = parsed_str; + env.set_error (); + return; } - else + /* If the called subroutine is parsed partially but not completely yet, + * it must be because we are calling it recursively. + * Handle it as an error. */ + if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) env.set_error (); + else + current_parsed_str = parsed_str; } parsed_cs_str_t *current_parsed_str; @@ -548,7 +498,7 @@ struct subr_remap_t : hb_inc_bimap_t /* create a remapping of subroutine numbers from old to new. * no optimization based on usage counts. fonttools doesn't appear doing that either. */ - + hb_codepoint_t old_num = HB_SET_VALUE_INVALID; while (hb_set_next (closure, &old_num)) add (old_num); @@ -583,11 +533,16 @@ struct subr_remaps_t void init (unsigned int fdCount) { - local_remaps.resize (fdCount); + if (unlikely (!local_remaps.resize (fdCount))) return; for (unsigned int i = 0; i < fdCount; i++) local_remaps[i].init (); } + bool in_error() + { + return local_remaps.in_error (); + } + void create (subr_closures_t& closures) { global_remap.create (closures.global_closure); @@ -646,10 +601,19 @@ struct subr_subsetter_t parsed_charstrings.init (plan->num_output_glyphs ()); parsed_global_subrs.init (acc.globalSubrs->count); - parsed_local_subrs.resize (acc.fdCount); + + if (unlikely (remaps.in_error() + || parsed_charstrings.in_error () + || parsed_global_subrs.in_error ())) { + return false; + } + + if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false; + for (unsigned int i = 0; i < acc.fdCount; i++) { parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count); + if (unlikely (parsed_local_subrs[i].in_error ())) return false; } if (unlikely (!closures.valid)) return false; @@ -659,11 +623,11 @@ struct subr_subsetter_t { hb_codepoint_t glyph; if (!plan->old_gid_for_new_gid (i, &glyph)) - continue; + continue; const byte_str_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) - return false; + return false; cs_interpreter_t interp; interp.env.init (str, acc, fd); @@ -677,8 +641,8 @@ struct subr_subsetter_t if (unlikely (!interp.interpret (param))) return false; - /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ - SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]); + /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ + SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]); } if (plan->drop_hints) @@ -740,13 +704,13 @@ struct subr_subsetter_t hb_codepoint_t glyph; if (!plan->old_gid_for_new_gid (i, &glyph)) { - /* add an endchar only charstring for a missing glyph if CFF1 */ - if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op); - continue; + /* add an endchar only charstring for a missing glyph if CFF1 */ + if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op); + continue; } unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) - return false; + return false; if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i]))) return false; } @@ -900,11 +864,11 @@ struct subr_subsetter_t { parsed_cs_op_t &csop = str.values[pos]; if (csop.op == OpCode_return) - break; + break; if (!csop.for_drop ()) { - drop.all_dropped = false; - break; + drop.all_dropped = false; + break; } } @@ -916,7 +880,7 @@ struct subr_subsetter_t hb_set_t *closure, const subr_subset_param_t ¶m) { - hb_set_add (closure, subr_num); + closure->add (subr_num); collect_subr_refs_in_str (subrs[subr_num], param); } @@ -986,7 +950,7 @@ struct subr_subsetter_t } protected: - const ACC &acc; + const ACC &acc; const hb_subset_plan_t *plan; subr_closures_t closures; diff --git a/src/hb-subset-cff1.cc b/src/hb-subset-cff1.cc index 21bd97fbb8000f04e2b7c3e5f78b515bda533cd6..df322f8451c911e992fd95860b50cbc8eef44b29 100644 --- a/src/hb-subset-cff1.cc +++ b/src/hb-subset-cff1.cc @@ -64,29 +64,25 @@ struct remap_sid_t : hb_inc_bimap_t static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } }; -struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t +struct cff1_sub_table_info_t : cff_sub_table_info_t { - cff1_sub_table_offsets_t () - : cff_sub_table_offsets_t (), - nameIndexOffset (0), - encodingOffset (0) - { - stringIndexInfo.init (); - charsetInfo.init (); + cff1_sub_table_info_t () + : cff_sub_table_info_t (), + encoding_link (0), + charset_link (0) + { privateDictInfo.init (); } - unsigned int nameIndexOffset; - table_info_t stringIndexInfo; - unsigned int encodingOffset; - table_info_t charsetInfo; + objidx_t encoding_link; + objidx_t charset_link; table_info_t privateDictInfo; }; /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */ struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t { - void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t)) + void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t)) { SUPER::init (); base = base_; @@ -117,13 +113,13 @@ struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t struct top_dict_modifiers_t { - top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_, - const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) - : offsets (offsets_), + top_dict_modifiers_t (const cff1_sub_table_info_t &info_, + const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) + : info (info_), nameSIDs (nameSIDs_) {} - const cff1_sub_table_offsets_t &offsets; + const cff1_sub_table_info_t &info; const unsigned int (&nameSIDs)[name_dict_values_t::ValCount]; }; @@ -139,22 +135,20 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_tallocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - *p = OpCode_Private; - } - break; + return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) && + Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute)); case OpCode_version: case OpCode_Notice: @@ -165,7 +159,7 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t::serialize (c, opstr, mod.offsets)); + return_trace (cff_top_dict_op_serializer_t::serialize (c, opstr, mod.info)); } return_trace (true); } - unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const - { - op_code_t op = opstr.op; - switch (op) - { - case OpCode_charset: - case OpCode_Encoding: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); - - case OpCode_Private: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); - - case OpCode_version: - case OpCode_Notice: - case OpCode_Copyright: - case OpCode_FullName: - case OpCode_FamilyName: - case OpCode_Weight: - case OpCode_PostScript: - case OpCode_BaseFontName: - case OpCode_FontName: - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op); - - case OpCode_ROS: - return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */; - - default: - return cff_top_dict_op_serializer_t::calculate_serialized_size (opstr); - } - } -}; - -struct font_dict_values_mod_t -{ - void init (const cff1_font_dict_values_t *base_, - unsigned int fontName_, - const table_info_t &privateDictInfo_) - { - base = base_; - fontName = fontName_; - privateDictInfo = privateDictInfo_; - } - - unsigned get_count () const { return base->get_count (); } - - const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } - - const cff1_font_dict_values_t *base; - table_info_t privateDictInfo; - unsigned int fontName; }; struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t { bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const font_dict_values_mod_t &mod) const + const cff1_font_dict_values_mod_t &mod) const { TRACE_SERIALIZE (this); if (opstr.op == OpCode_FontName) - return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName)); + return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName)); else return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); } - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - if (opstr.op == OpCode_FontName) - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName); - else - return SUPER::calculate_serialized_size (opstr); - } - private: typedef cff_font_dict_op_serializer_t SUPER; }; @@ -331,7 +268,7 @@ struct cff1_cs_opset_flatten_t : cff1_cs_opset_t { /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ - bool finalize (unsigned int last_glyph) + bool complete (unsigned int last_glyph) { bool two_byte = false; for (unsigned int i = (*this).length; i > 0; i--) @@ -389,7 +326,7 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } @@ -402,7 +339,7 @@ struct cff1_subr_subsetter_t : subr_subsetter_tset_parsed (); for (unsigned int i = 0; i < env.callStack.get_count (); i++) { - parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]); - if (likely (parsed_str != nullptr)) + parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]); + if (likely (parsed_str)) parsed_str->set_parsed (); else env.set_error (); @@ -425,16 +362,13 @@ struct cff1_subr_subsetter_t : subr_subsetter_t supp_codes; - subset_enc_code_ranges.resize (0); + if (unlikely (!subset_enc_code_ranges.resize (0))) + { + plan->check_success (false); + return; + } + supp_size = 0; supp_codes.init (); @@ -484,7 +422,7 @@ struct cff_subset_plan { hb_codepoint_t old_glyph; if (!plan->old_gid_for_new_gid (glyph, &old_glyph)) { - /* Retain the code for the old missing glyph ID */ + /* Retain the code for the old missing glyph ID */ old_glyph = glyph; } code = acc.glyph_to_code (old_glyph); @@ -501,7 +439,7 @@ struct cff_subset_plan { } last_code = code; - if (encoding != &Null(Encoding)) + if (encoding != &Null (Encoding)) { hb_codepoint_t sid = acc.glyph_to_sid (old_glyph); encoding->get_supplement_codes (sid, supp_codes); @@ -515,7 +453,7 @@ struct cff_subset_plan { } supp_codes.fini (); - subset_enc_code_ranges.finalize (glyph); + subset_enc_code_ranges.complete (glyph); assert (subset_enc_num_codes <= 0xFF); size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes; @@ -525,26 +463,26 @@ struct cff_subset_plan { subset_enc_format = 0; else subset_enc_format = 1; - - return Encoding::calculate_serialized_size ( - subset_enc_format, - subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes, - subset_enc_supp_codes.length); } - unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { unsigned int size0, size_ranges; hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE; - subset_charset_ranges.resize (0); + if (unlikely (!subset_charset_ranges.resize (0))) + { + plan->check_success (false); + return; + } + unsigned int glyph; for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) { hb_codepoint_t old_glyph; if (!plan->old_gid_for_new_gid (glyph, &old_glyph)) { - /* Retain the SID for the old missing glyph ID */ + /* Retain the SID for the old missing glyph ID */ old_glyph = glyph; } sid = acc.glyph_to_sid (old_glyph); @@ -560,7 +498,7 @@ struct cff_subset_plan { last_sid = sid; } - bool two_byte = subset_charset_ranges.finalize (glyph); + bool two_byte = subset_charset_ranges.complete (glyph); size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1); if (!two_byte) @@ -574,10 +512,6 @@ struct cff_subset_plan { subset_charset_format = 1; else subset_charset_format = 2; - - return Charset::calculate_serialized_size ( - subset_charset_format, - subset_charset_format? subset_charset_ranges.length: plan->num_output_glyphs ()); } bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) @@ -594,7 +528,7 @@ struct cff_subset_plan { } } - if (acc.fdArray != &Null(CFF1FDArray)) + if (acc.fdArray != &Null (CFF1FDArray)) for (unsigned int i = 0; i < orig_fdcount; i++) if (fdmap.has (i)) (void)sidmap.add (acc.fontDicts[i].fontName); @@ -609,7 +543,6 @@ struct cff_subset_plan { hb_codepoint_t old_glyph; if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false; - final_size = 0; num_glyphs = plan->num_output_glyphs (); orig_fdcount = acc.fdCount; drop_hints = plan->drop_hints; @@ -620,7 +553,7 @@ struct cff_subset_plan { for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++) { if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph)) - continue; + continue; if (new_glyph != old_glyph) { gid_renum = true; break; @@ -630,13 +563,6 @@ struct cff_subset_plan { subset_charset = gid_renum || !acc.is_predef_charset (); subset_encoding = !acc.is_CID() && !acc.is_predef_encoding (); - /* CFF header */ - final_size += OT::cff1::static_size; - - /* Name INDEX */ - offsets.nameIndexOffset = final_size; - final_size += acc.nameIndex->get_size (); - /* top dict INDEX */ { /* Add encoding/charset to a (copy of) top dict as necessary */ @@ -650,25 +576,16 @@ struct cff_subset_plan { if (need_to_add_set) topdict_mod.add_op (OpCode_charset); } - offsets.topDictInfo.offset = final_size; - cff1_top_dict_op_serializer_t topSzr; - unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr); - offsets.topDictInfo.offSize = calcOffSize(topDictSize); - if (unlikely (offsets.topDictInfo.offSize > 4)) - return false; - final_size += CFF1IndexOf::calculate_serialized_size - (offsets.topDictInfo.offSize, - &topdict_mod, 1, topdict_sizes, topSzr); } /* Determine re-mapping of font index as fdmap among other info */ - if (acc.fdSelect != &Null(CFF1FDSelect)) + if (acc.fdSelect != &Null (CFF1FDSelect)) { if (unlikely (!hb_plan_subset_cff_fdselect (plan, orig_fdcount, *acc.fdSelect, subset_fdcount, - offsets.FDSelectInfo.size, + info.fd_select.size, subset_fdselect_format, subset_fdselect_ranges, fdmap))) @@ -683,18 +600,11 @@ struct cff_subset_plan { if (unlikely (!collect_sids_in_dicts (acc))) return false; if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */ - return false; - if (subset_charset) - offsets.charsetInfo.size = plan_subset_charset (acc, plan); + return false; - topdict_mod.reassignSIDs (sidmap); - } + if (subset_charset) plan_subset_charset (acc, plan); - /* String INDEX */ - { - offsets.stringIndexInfo.offset = final_size; - offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap); - final_size += offsets.stringIndexInfo.size; + topdict_mod.reassignSIDs (sidmap); } if (desubroutinize) @@ -704,9 +614,6 @@ struct cff_subset_plan { flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; - - /* no global/local subroutines */ - offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0); } else { @@ -723,131 +630,48 @@ struct cff_subset_plan { if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) return false; - /* global subrs */ - unsigned int dataSize = subset_globalsubrs.total_size (); - offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); - if (unlikely (offsets.globalSubrsInfo.offSize > 4)) - return false; - offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); - /* local subrs */ - if (!offsets.localSubrsInfos.resize (orig_fdcount)) - return false; if (!subset_localsubrs.resize (orig_fdcount)) return false; for (unsigned int fd = 0; fd < orig_fdcount; fd++) { subset_localsubrs[fd].init (); - offsets.localSubrsInfos[fd].init (); if (fdmap.has (fd)) { if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) return false; - - unsigned int dataSize = subset_localsubrs[fd].total_size (); - if (dataSize > 0) - { - offsets.localSubrsInfos[fd].offset = final_size; - offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); - if (unlikely (offsets.localSubrsInfos[fd].offSize > 4)) - return false; - offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); - } } } } - /* global subrs */ - offsets.globalSubrsInfo.offset = final_size; - final_size += offsets.globalSubrsInfo.size; - /* Encoding */ - if (!subset_encoding) - offsets.encodingOffset = acc.topDict.EncodingOffset; - else - { - offsets.encodingOffset = final_size; - final_size += plan_subset_encoding (acc, plan); - } - - /* Charset */ - if (!subset_charset && acc.is_predef_charset ()) - offsets.charsetInfo.offset = acc.topDict.CharsetOffset; - else - offsets.charsetInfo.offset = final_size; - final_size += offsets.charsetInfo.size; - - /* FDSelect */ - if (acc.fdSelect != &Null(CFF1FDSelect)) - { - offsets.FDSelectInfo.offset = final_size; - final_size += offsets.FDSelectInfo.size; - } - - /* FDArray (FDIndex) */ - if (acc.fdArray != &Null(CFF1FDArray)) { - offsets.FDArrayInfo.offset = final_size; - cff1_font_dict_op_serializer_t fontSzr; - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < acc.fontDicts.length; i++) - if (fdmap.has (i)) - dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); - - offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); - if (unlikely (offsets.FDArrayInfo.offSize > 4)) - return false; - final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); - } - - /* CharStrings */ - { - offsets.charStringsInfo.offset = final_size; - unsigned int dataSize = subset_charstrings.total_size (); - offsets.charStringsInfo.offSize = calcOffSize (dataSize); - if (unlikely (offsets.charStringsInfo.offSize > 4)) - return false; - final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize); - } + if (subset_encoding) + plan_subset_encoding (acc, plan); /* private dicts & local subrs */ - offsets.privateDictInfo.offset = final_size; - for (unsigned int i = 0; i < orig_fdcount; i++) + if (!acc.is_CID ()) + fontdicts_mod.push (cff1_font_dict_values_mod_t ()); + else { - if (fdmap.has (i)) - { - bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; - cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints); - unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); - table_info_t privInfo = { final_size, priv_size, 0 }; - font_dict_values_mod_t fontdict_mod; - if (!acc.is_CID ()) - fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo ); - else - fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo ); - fontdicts_mod.push (fontdict_mod); - final_size += privInfo.size; - - if (!plan->desubroutinize && has_localsubrs) + + hb_iter (acc.fontDicts) + | hb_filter ([&] (const cff1_font_dict_values_t &_) + { return fdmap.has (&_ - &acc.fontDicts[0]); } ) + | hb_map ([&] (const cff1_font_dict_values_t &_) { - offsets.localSubrsInfos[i].offset = final_size; - final_size += offsets.localSubrsInfos[i].size; - } - } + cff1_font_dict_values_mod_t mod; + mod.init (&_, sidmap[_.fontName]); + return mod; + }) + | hb_sink (fontdicts_mod) + ; } - if (!acc.is_CID ()) - offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; - return ((subset_charstrings.length == plan->num_output_glyphs ()) && (fontdicts_mod.length == subset_fdcount)); } - unsigned int get_final_size () const { return final_size; } - - unsigned int final_size; - hb_vector_t topdict_sizes; cff1_top_dict_values_mod_t topdict_mod; - cff1_sub_table_offsets_t offsets; + cff1_sub_table_info_t info; unsigned int num_glyphs; unsigned int orig_fdcount; @@ -862,7 +686,7 @@ struct cff_subset_plan { str_buff_vec_t subset_charstrings; str_buff_vec_t subset_globalsubrs; hb_vector_t subset_localsubrs; - hb_vector_t fontdicts_mod; + hb_vector_t fontdicts_mod; bool drop_hints; @@ -883,91 +707,95 @@ struct cff_subset_plan { bool desubroutinize; }; -static inline bool _write_cff1 (const cff_subset_plan &plan, - const OT::cff1::accelerator_subset_t &acc, - unsigned int num_glyphs, - unsigned int dest_sz, - void *dest) +static bool _serialize_cff1 (hb_serialize_context_t *c, + cff_subset_plan &plan, + const OT::cff1::accelerator_subset_t &acc, + unsigned int num_glyphs) { - hb_serialize_context_t c (dest, dest_sz); - - OT::cff1 *cff = c.start_serialize (); - if (unlikely (!c.extend_min (*cff))) - return false; - - /* header */ - cff->version.major = 0x01; - cff->version.minor = 0x00; - cff->nameIndex = cff->min_size; - cff->offSize = 4; /* unused? */ - - /* name INDEX */ + /* private dicts & local subrs */ + for (int i = (int)acc.privateDicts.length; --i >= 0 ;) { - assert (cff->nameIndex == (unsigned) (c.head - c.start)); - CFF1NameIndex *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.nameIndex))) + if (plan.fdmap.has (i)) { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX"); - return false; - } - } + objidx_t subrs_link = 0; + if (plan.subset_localsubrs[i].length > 0) + { + CFF1Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i]))) + subrs_link = c->pop_pack (); + else + { + c->pop_discard (); + return false; + } + } - /* top dict INDEX */ - { - assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start)); - CFF1IndexOf *dest = c.start_embed< CFF1IndexOf> (); - if (dest == nullptr) return false; - cff1_top_dict_op_serializer_t topSzr; - top_dict_modifiers_t modifier (plan.offsets, plan.topDictModSIDs); - if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, - &plan.topdict_mod, 1, - plan.topdict_sizes, topSzr, modifier))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); - return false; + PrivateDict *pd = c->start_embed (); + if (unlikely (!pd)) return false; + c->push (); + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ + if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + { + unsigned fd = plan.fdmap[i]; + plan.fontdicts_mod[fd].privateDictInfo.size = c->length (); + plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack (); + } + else + { + c->pop_discard (); + return false; + } } } - /* String INDEX */ + if (!acc.is_CID ()) + plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo; + + /* CharStrings */ { - assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start)); - CFF1StringIndex *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap))) + CFF1CharStrings *cs = c->start_embed (); + if (unlikely (!cs)) return false; + c->push (); + if (likely (cs->serialize (c, plan.subset_charstrings))) + plan.info.char_strings_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX"); + c->pop_discard (); return false; } } - /* global subrs */ + /* FDArray (FD Index) */ + if (acc.fdArray != &Null (CFF1FDArray)) { - assert (plan.offsets.globalSubrsInfo.offset != 0); - assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start)); - - CFF1Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) + CFF1FDArray *fda = c->start_embed (); + if (unlikely (!fda)) return false; + c->push (); + cff1_font_dict_op_serializer_t fontSzr; + auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod)); + if (likely (fda->serialize (c, it, fontSzr))) + plan.info.fd_array_link = c->pop_pack (false); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); + c->pop_discard (); return false; } } - /* Encoding */ - if (plan.subset_encoding) + /* FDSelect */ + if (acc.fdSelect != &Null (CFF1FDSelect)) { - assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start)); - Encoding *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, - plan.subset_enc_format, - plan.subset_enc_num_codes, - plan.subset_enc_code_ranges, - plan.subset_enc_supp_codes))) + c->push (); + if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, + plan.subset_fdselect_format, plan.info.fd_select.size, + plan.subset_fdselect_ranges))) + plan.info.fd_select.link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding"); + c->pop_discard (); return false; } } @@ -975,129 +803,120 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, /* Charset */ if (plan.subset_charset) { - assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start)); - Charset *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, - plan.subset_charset_format, - plan.num_glyphs, - plan.subset_charset_ranges))) + Charset *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, + plan.subset_charset_format, + plan.num_glyphs, + plan.subset_charset_ranges))) + plan.info.charset_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset"); + c->pop_discard (); return false; } } - /* FDSelect */ - if (acc.fdSelect != &Null(CFF1FDSelect)) + /* Encoding */ + if (plan.subset_encoding) { - assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); - - if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *acc.fdSelect, acc.fdCount, - plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subset_fdselect_ranges))) + Encoding *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, + plan.subset_enc_format, + plan.subset_enc_num_codes, + plan.subset_enc_code_ranges, + plan.subset_enc_supp_codes))) + plan.info.encoding_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect"); + c->pop_discard (); return false; } } - /* FDArray (FD Index) */ - if (acc.fdArray != &Null(CFF1FDArray)) + /* global subrs */ { - assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); - CFF1FDArray *fda = c.start_embed (); - if (unlikely (fda == nullptr)) return false; - cff1_font_dict_op_serializer_t fontSzr; - if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - plan.fontdicts_mod, - fontSzr))) + c->push (); + CFF1Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + if (likely (dest->serialize (c, plan.subset_globalsubrs))) + c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); + c->pop_discard (); return false; } } - /* CharStrings */ + /* String INDEX */ { - assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); - CFF1CharStrings *cs = c.start_embed (); - if (unlikely (cs == nullptr)) return false; - if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) + CFF1StringIndex *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap))) + c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings"); + c->pop_discard (); return false; } } - /* private dicts & local subrs */ - assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start)); - for (unsigned int i = 0; i < acc.privateDicts.length; i++) + OT::cff1 *cff = c->allocate_min (); + if (unlikely (!cff)) + return false; + + /* header */ + cff->version.major = 0x01; + cff->version.minor = 0x00; + cff->nameIndex = cff->min_size; + cff->offSize = 4; /* unused? */ + + /* name INDEX */ + if (unlikely (!(*acc.nameIndex).copy (c))) return false; + + /* top dict INDEX */ { - if (plan.fdmap.has (i)) + /* serialize singleton TopDict */ + TopDict *top = c->start_embed (); + if (!top) return false; + c->push (); + cff1_top_dict_op_serializer_t topSzr; + unsigned top_size = 0; + top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs); + if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier))) { - PrivateDict *pd = c.start_embed (); - if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size; - bool result; - cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); - /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0; - result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); - return false; - } - if (plan.offsets.localSubrsInfos[i].size > 0) - { - CFF1Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); - return false; - } - } + top_size = c->length (); + c->pop_pack (false); } + else + { + c->pop_discard (); + return false; + } + /* serialize INDEX header for above */ + CFF1Index *dest = c->start_embed (); + if (!dest) return false; + return dest->serialize_header (c, hb_iter (hb_array_t (&top_size, 1))); } - - assert (c.head == c.end); - c.end_serialize (); - - return true; } -static inline bool +static bool _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, - const char *data, - hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) + hb_subset_context_t *c) { cff_subset_plan cff_plan; - if (unlikely (!cff_plan.create (acc, plan))) + if (unlikely (!cff_plan.create (acc, c->plan))) { DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan."); return false; } - unsigned int cff_prime_size = cff_plan.get_final_size (); - char *cff_prime_data = (char *) calloc (1, cff_prime_size); - - if (unlikely (!_write_cff1 (cff_plan, acc, plan->num_output_glyphs (), - cff_prime_size, cff_prime_data))) { - DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff."); - free (cff_prime_data); - return false; - } - - *prime = hb_blob_create (cff_prime_data, - cff_prime_size, - HB_MEMORY_MODE_READONLY, - cff_prime_data, - free); - return true; + return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()); } /** @@ -1107,17 +926,11 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, * Return value: subsetted cff table. **/ bool -hb_subset_cff1 (hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) +hb_subset_cff1 (hb_subset_context_t *c) { - hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table (plan->source); - const char *data = hb_blob_get_data(cff_blob, nullptr); - OT::cff1::accelerator_subset_t acc; - acc.init(plan->source); - bool result = likely (acc.is_valid ()) && - _hb_subset_cff1 (acc, data, plan, prime); - hb_blob_destroy (cff_blob); + acc.init (c->plan->source); + bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c); acc.fini (); return result; diff --git a/src/hb-subset-cff1.hh b/src/hb-subset-cff1.hh index 1ec8678845a2956d7b2514c54f45ee9abf9330fc..aaf5def1ed5d0e96ec3c77e8e701e12e4199adea 100644 --- a/src/hb-subset-cff1.hh +++ b/src/hb-subset-cff1.hh @@ -32,7 +32,6 @@ #include "hb-subset-plan.hh" HB_INTERNAL bool -hb_subset_cff1 (hb_subset_plan_t *plan, - hb_blob_t **cff_prime /* OUT */); +hb_subset_cff1 (hb_subset_context_t *c); #endif /* HB_SUBSET_CFF1_HH */ diff --git a/src/hb-subset-cff2.cc b/src/hb-subset-cff2.cc index e89ca695114b9533b0ea34d857062f6b76f09025..17ee040deb6ca805257c7cc96507e4a4980da9b7 100644 --- a/src/hb-subset-cff2.cc +++ b/src/hb-subset-cff2.cc @@ -38,43 +38,31 @@ using namespace CFF; -struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t +struct cff2_sub_table_info_t : cff_sub_table_info_t { - cff2_sub_table_offsets_t () - : cff_sub_table_offsets_t (), - varStoreOffset (0) + cff2_sub_table_info_t () + : cff_sub_table_info_t (), + var_store_link (0) {} - unsigned int varStoreOffset; + objidx_t var_store_link; }; struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> { bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const cff2_sub_table_offsets_t &offsets) const + const cff2_sub_table_info_t &info) const { TRACE_SERIALIZE (this); switch (opstr.op) { case OpCode_vstore: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link)); default: - return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets)); - } - } - - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - switch (opstr.op) - { - case OpCode_vstore: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr); + return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, info)); } } }; @@ -116,8 +104,8 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t 0) && (env.argStack.get_count () >= arg.numValues)))) - { + if (unlikely (!((arg.numValues > 0) && (env.argStack.get_count () >= arg.numValues)))) + { env.set_error (); return; } @@ -144,8 +132,8 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } @@ -232,7 +220,7 @@ struct cff2_subr_subsetter_t : subr_subsetter_tcount; drop_hints = plan->drop_hints; desubroutinize = plan->desubroutinize; - /* CFF2 header */ - final_size += OT::cff2::static_size; - - /* top dict */ - { - cff2_top_dict_op_serializer_t topSzr; - offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr); - final_size += offsets.topDictInfo.size; - } - if (desubroutinize) { /* Flatten global & local subrs */ @@ -297,9 +272,6 @@ struct cff2_subset_plan { flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; - - /* no global/local subroutines */ - offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0); } else { @@ -316,115 +288,41 @@ struct cff2_subset_plan { if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) return false; - /* global subrs */ - unsigned int dataSize = subset_globalsubrs.total_size (); - offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); - offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); - /* local subrs */ - if (!offsets.localSubrsInfos.resize (orig_fdcount)) - return false; if (!subset_localsubrs.resize (orig_fdcount)) return false; for (unsigned int fd = 0; fd < orig_fdcount; fd++) { subset_localsubrs[fd].init (); - offsets.localSubrsInfos[fd].init (); - if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) - return false; - - unsigned int dataSize = subset_localsubrs[fd].total_size (); - if (dataSize > 0) - { - offsets.localSubrsInfos[fd].offset = final_size; - offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); - offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); - } + if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) + return false; } } - /* global subrs */ - offsets.globalSubrsInfo.offset = final_size; - final_size += offsets.globalSubrsInfo.size; - - /* variation store */ - if (acc.varStore != &Null(CFF2VariationStore)) - { - offsets.varStoreOffset = final_size; - final_size += acc.varStore->get_size (); - } - /* FDSelect */ - if (acc.fdSelect != &Null(CFF2FDSelect)) + if (acc.fdSelect != &Null (CFF2FDSelect)) { - offsets.FDSelectInfo.offset = final_size; if (unlikely (!hb_plan_subset_cff_fdselect (plan, - orig_fdcount, - *(const FDSelect *)acc.fdSelect, - subset_fdcount, - offsets.FDSelectInfo.size, - subset_fdselect_format, - subset_fdselect_ranges, - fdmap))) + orig_fdcount, + *(const FDSelect *)acc.fdSelect, + subset_fdcount, + subset_fdselect_size, + subset_fdselect_format, + subset_fdselect_ranges, + fdmap))) return false; - - final_size += offsets.FDSelectInfo.size; } else fdmap.identity (1); - /* FDArray (FDIndex) */ - { - offsets.FDArrayInfo.offset = final_size; - cff_font_dict_op_serializer_t fontSzr; - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < acc.fontDicts.length; i++) - if (fdmap.has (i)) - dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); - - offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); - final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); - } - - /* CharStrings */ - { - offsets.charStringsInfo.offset = final_size; - unsigned int dataSize = subset_charstrings.total_size (); - offsets.charStringsInfo.offSize = calcOffSize (dataSize); - final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->num_output_glyphs (), dataSize); - } - - /* private dicts & local subrs */ - offsets.privateDictsOffset = final_size; - for (unsigned int i = 0; i < orig_fdcount; i++) - { - if (fdmap.has (i)) - { - bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; - cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints); - unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); - table_info_t privInfo = { final_size, priv_size, 0 }; - privateDictInfos.push (privInfo); - final_size += privInfo.size; - - if (!plan->desubroutinize && has_localsubrs) - { - offsets.localSubrsInfos[i].offset = final_size; - final_size += offsets.localSubrsInfos[i].size; - } - } - } - return true; } - unsigned int get_final_size () const { return final_size; } - - unsigned int final_size; - cff2_sub_table_offsets_t offsets; + cff2_sub_table_info_t info; unsigned int orig_fdcount; unsigned int subset_fdcount; + unsigned int subset_fdselect_size; unsigned int subset_fdselect_format; hb_vector_t subset_fdselect_ranges; @@ -433,200 +331,158 @@ struct cff2_subset_plan { str_buff_vec_t subset_charstrings; str_buff_vec_t subset_globalsubrs; hb_vector_t subset_localsubrs; - hb_vector_t privateDictInfos; bool drop_hints; bool desubroutinize; }; -static inline bool _write_cff2 (const cff2_subset_plan &plan, - const OT::cff2::accelerator_subset_t &acc, - unsigned int num_glyphs, - unsigned int dest_sz, - void *dest) +static bool _serialize_cff2 (hb_serialize_context_t *c, + cff2_subset_plan &plan, + const OT::cff2::accelerator_subset_t &acc, + unsigned int num_glyphs) { - hb_serialize_context_t c (dest, dest_sz); - - OT::cff2 *cff2 = c.start_serialize (); - if (unlikely (!c.extend_min (*cff2))) - return false; - - /* header */ - cff2->version.major = 0x02; - cff2->version.minor = 0x00; - cff2->topDict = OT::cff2::static_size; + /* private dicts & local subrs */ + hb_vector_t private_dict_infos; + if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false; - /* top dict */ + for (int i = (int)acc.privateDicts.length; --i >= 0 ;) { - assert (cff2->topDict == (unsigned) (c.head - c.start)); - cff2->topDictSize = plan.offsets.topDictInfo.size; - TopDict &dict = cff2 + cff2->topDict; - cff2_top_dict_op_serializer_t topSzr; - if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets))) + if (plan.fdmap.has (i)) { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict"); - return false; - } - } + objidx_t subrs_link = 0; - /* global subrs */ - { - assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start)); - CFF2Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); - return false; + if (plan.subset_localsubrs[i].length > 0) + { + CFF2Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, plan.subset_localsubrs[i]))) + subrs_link = c->pop_pack (); + else + { + c->pop_discard (); + return false; + } + } + PrivateDict *pd = c->start_embed (); + if (unlikely (!pd)) return false; + c->push (); + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + { + unsigned fd = plan.fdmap[i]; + private_dict_infos[fd].size = c->length (); + private_dict_infos[fd].link = c->pop_pack (); + } + else + { + c->pop_discard (); + return false; + } } } - /* variation store */ - if (acc.varStore != &Null(CFF2VariationStore)) + /* CharStrings */ { - assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start)); - CFF2VariationStore *dest = c.start_embed (); - if (unlikely (!dest->serialize (&c, acc.varStore))) + CFF2CharStrings *cs = c->start_embed (); + if (unlikely (!cs)) return false; + c->push (); + if (likely (cs->serialize (c, plan.subset_charstrings))) + plan.info.char_strings_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store"); + c->pop_discard (); return false; } } /* FDSelect */ - if (acc.fdSelect != &Null(CFF2FDSelect)) + if (acc.fdSelect != &Null (CFF2FDSelect)) { - assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); - - if (unlikely (!hb_serialize_cff_fdselect (&c, num_glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count, - plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subset_fdselect_ranges))) + c->push (); + if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, plan.orig_fdcount, + plan.subset_fdselect_format, plan.subset_fdselect_size, + plan.subset_fdselect_ranges))) + plan.info.fd_select.link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect"); + c->pop_discard (); return false; } } /* FDArray (FD Index) */ { - assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); - CFF2FDArray *fda = c.start_embed (); - if (unlikely (fda == nullptr)) return false; - cff_font_dict_op_serializer_t fontSzr; - if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - acc.fontDicts, plan.subset_fdcount, plan.fdmap, - fontSzr, plan.privateDictInfos))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray"); - return false; - } + c->push (); + CFF2FDArray *fda = c->start_embed (); + if (unlikely (!fda)) return false; + cff_font_dict_op_serializer_t fontSzr; + auto it = + + hb_zip (+ hb_iter (acc.fontDicts) + | hb_filter ([&] (const cff2_font_dict_values_t &_) + { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }), + hb_iter (private_dict_infos)) + ; + if (unlikely (!fda->serialize (c, it, fontSzr))) return false; + plan.info.fd_array_link = c->pop_pack (); } - /* CharStrings */ + /* variation store */ + if (acc.varStore != &Null (CFF2VariationStore)) { - assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); - CFF2CharStrings *cs = c.start_embed (); - if (unlikely (cs == nullptr)) return false; - if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings"); - return false; - } + c->push (); + CFF2VariationStore *dest = c->start_embed (); + if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false; + plan.info.var_store_link = c->pop_pack (); } - /* private dicts & local subrs */ - assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start)); - for (unsigned int i = 0; i < acc.privateDicts.length; i++) + OT::cff2 *cff2 = c->allocate_min (); + if (unlikely (!cff2)) return false; + + /* header */ + cff2->version.major = 0x02; + cff2->version.minor = 0x00; + cff2->topDict = OT::cff2::static_size; + + /* top dict */ { - if (plan.fdmap.has (i)) - { - PrivateDict *pd = c.start_embed (); - if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size; - bool result; - cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); - /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0) ? priv_size : 0; - result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); - return false; - } - if (plan.offsets.localSubrsInfos[i].size > 0) - { - CFF2Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); - return false; - } - } - } + TopDict &dict = cff2 + cff2->topDict; + cff2_top_dict_op_serializer_t topSzr; + if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false; + cff2->topDictSize = c->head - (const char *)&dict; } - assert (c.head == c.end); - c.end_serialize (); - - return true; + /* global subrs */ + { + CFF2Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + return dest->serialize (c, plan.subset_globalsubrs); + } } -static inline bool +static bool _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, - const char *data, - hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) + hb_subset_context_t *c) { cff2_subset_plan cff2_plan; - if (unlikely (!cff2_plan.create (acc, plan))) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan."); - return false; - } - - unsigned int cff2_prime_size = cff2_plan.get_final_size (); - char *cff2_prime_data = (char *) calloc (1, cff2_prime_size); - - if (unlikely (!_write_cff2 (cff2_plan, acc, plan->num_output_glyphs (), - cff2_prime_size, cff2_prime_data))) { - DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2."); - free (cff2_prime_data); - return false; - } - - *prime = hb_blob_create (cff2_prime_data, - cff2_prime_size, - HB_MEMORY_MODE_READONLY, - cff2_prime_data, - free); - return true; + if (unlikely (!cff2_plan.create (acc, c->plan))) return false; + return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ()); } /** * hb_subset_cff2: - * Subsets the CFF2 table according to a provided plan. - * - * Return value: subsetted cff2 table. + * Subsets the CFF2 table according to a provided subset context. **/ bool -hb_subset_cff2 (hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) +hb_subset_cff2 (hb_subset_context_t *c) { - hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table (plan->source); - const char *data = hb_blob_get_data(cff2_blob, nullptr); - OT::cff2::accelerator_subset_t acc; - acc.init(plan->source); - bool result = likely (acc.is_valid ()) && - _hb_subset_cff2 (acc, data, plan, prime); - - hb_blob_destroy (cff2_blob); + acc.init (c->plan->source); + bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c); acc.fini (); return result; } - #endif diff --git a/src/hb-subset-cff2.hh b/src/hb-subset-cff2.hh index a07dc290e5ce4eafcbab380d390477ff36f5e3e6..f10556ddd74bb3e04c0d9bf4f10c3387a471eb28 100644 --- a/src/hb-subset-cff2.hh +++ b/src/hb-subset-cff2.hh @@ -32,7 +32,6 @@ #include "hb-subset-plan.hh" HB_INTERNAL bool -hb_subset_cff2 (hb_subset_plan_t *plan, - hb_blob_t **cff2_prime /* OUT */); +hb_subset_cff2 (hb_subset_context_t *c); #endif /* HB_SUBSET_CFF2_HH */ diff --git a/src/hb-subset-input.cc b/src/hb-subset-input.cc index 34f1cb86394d6f98f09ff1691e2d3d0560284733..1f64bc99a0cc9ecd523fee1bfcfeaa22a7bfa4bc 100644 --- a/src/hb-subset-input.cc +++ b/src/hb-subset-input.cc @@ -46,16 +46,16 @@ hb_subset_input_create_or_fail () input->glyphs = hb_set_create (); input->name_ids = hb_set_create (); hb_set_add_range (input->name_ids, 0, 6); + input->name_languages = hb_set_create (); + hb_set_add (input->name_languages, 0x0409); input->drop_tables = hb_set_create (); input->drop_hints = false; input->desubroutinize = false; input->retain_gids = false; + input->name_legacy = false; hb_tag_t default_drop_tables[] = { // Layout disabled by default - HB_TAG ('G', 'S', 'U', 'B'), - HB_TAG ('G', 'P', 'O', 'S'), - HB_TAG ('G', 'D', 'E', 'F'), HB_TAG ('m', 'o', 'r', 'x'), HB_TAG ('m', 'o', 'r', 't'), HB_TAG ('k', 'e', 'r', 'x'), @@ -77,8 +77,6 @@ hb_subset_input_create_or_fail () HB_TAG ('G', 'l', 'o', 'c'), HB_TAG ('S', 'i', 'l', 'f'), HB_TAG ('S', 'i', 'l', 'l'), - // Colour - HB_TAG ('s', 'b', 'i', 'x') }; input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables)); @@ -116,6 +114,7 @@ hb_subset_input_destroy (hb_subset_input_t *subset_input) hb_set_destroy (subset_input->unicodes); hb_set_destroy (subset_input->glyphs); hb_set_destroy (subset_input->name_ids); + hb_set_destroy (subset_input->name_languages); hb_set_destroy (subset_input->drop_tables); free (subset_input); @@ -151,6 +150,12 @@ hb_subset_input_nameid_set (hb_subset_input_t *subset_input) return subset_input->name_ids; } +HB_EXTERN hb_set_t * +hb_subset_input_namelangid_set (hb_subset_input_t *subset_input) +{ + return subset_input->name_languages; +} + HB_EXTERN hb_set_t * hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input) { @@ -172,7 +177,7 @@ hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input) HB_EXTERN void hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, - hb_bool_t desubroutinize) + hb_bool_t desubroutinize) { subset_input->desubroutinize = desubroutinize; } @@ -206,3 +211,16 @@ hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input) { return subset_input->retain_gids; } + +HB_EXTERN void +hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input, + hb_bool_t name_legacy) +{ + subset_input->name_legacy = name_legacy; +} + +HB_EXTERN hb_bool_t +hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input) +{ + return subset_input->name_legacy; +} diff --git a/src/hb-subset-input.hh b/src/hb-subset-input.hh index f6dd4ac319733a5839ba913f8a6ce5cbed803fdd..0aeb96695b77bf35fc7ac1a00a761020bc0b8961 100644 --- a/src/hb-subset-input.hh +++ b/src/hb-subset-input.hh @@ -41,11 +41,13 @@ struct hb_subset_input_t hb_set_t *unicodes; hb_set_t *glyphs; hb_set_t *name_ids; + hb_set_t *name_languages; hb_set_t *drop_tables; bool drop_hints; bool desubroutinize; bool retain_gids; + bool name_legacy; /* TODO * * features diff --git a/src/hb-subset-plan.cc b/src/hb-subset-plan.cc index e244da199943e75084d950decbdc5a4ecce78ba7..dfb0d42f38d2ac9415fbfe5bc462018ffe9345d1 100644 --- a/src/hb-subset-plan.cc +++ b/src/hb-subset-plan.cc @@ -30,49 +30,49 @@ #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-cff1-table.hh" +#include "hb-ot-color-colr-table.hh" #include "hb-ot-var-fvar-table.hh" #include "hb-ot-stat-table.hh" -static inline void -_add_gid_and_children (const OT::glyf::accelerator_t &glyf, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) -{ - if (hb_set_has (gids_to_retain, gid)) - // Already visited this gid, ignore. - return; - - hb_set_add (gids_to_retain, gid); - - OT::glyf::CompositeGlyphHeader::Iterator composite; - if (glyf.get_composite (gid, &composite)) - { - do - { - _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain); - } while (composite.move_to_next()); - } -} +typedef hb_hashmap_t script_langsys_map; #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) + hb_codepoint_t gid, + hb_set_t *gids_to_retain) { hb_codepoint_t base_gid, accent_gid; if (cff.get_seac_components (gid, &base_gid, &accent_gid)) { - hb_set_add (gids_to_retain, base_gid); - hb_set_add (gids_to_retain, accent_gid); + gids_to_retain->add (base_gid); + gids_to_retain->add (accent_gid); } } #endif #ifndef HB_NO_SUBSET_LAYOUT +static void +_remap_indexes (const hb_set_t *indexes, + hb_map_t *mapping /* OUT */) +{ + unsigned count = indexes->get_population (); + + for (auto _ : + hb_zip (indexes->iter (), hb_range (count))) + mapping->set (_.first, _.second); + +} + static inline void -_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) +_gsub_closure_glyphs_lookups_features (hb_face_t *face, + hb_set_t *gids_to_retain, + hb_map_t *gsub_lookups, + hb_map_t *gsub_features, + script_langsys_map *gsub_langsys) { hb_set_t lookup_indices; hb_ot_layout_collect_lookups (face, @@ -84,9 +84,114 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) hb_ot_layout_lookups_substitute_closure (face, &lookup_indices, gids_to_retain); + hb_blob_ptr_t gsub = hb_sanitize_context_t ().reference_table (face); + gsub->closure_lookups (face, + gids_to_retain, + &lookup_indices); + _remap_indexes (&lookup_indices, gsub_lookups); + + // Collect and prune features + hb_set_t feature_indices; + hb_ot_layout_collect_features (face, + HB_OT_TAG_GSUB, + nullptr, + nullptr, + nullptr, + &feature_indices); + + gsub->prune_features (gsub_lookups, &feature_indices); + hb_map_t duplicate_feature_map; + gsub->find_duplicate_features (gsub_lookups, &feature_indices, &duplicate_feature_map); + + feature_indices.clear (); + gsub->prune_langsys (&duplicate_feature_map, gsub_langsys, &feature_indices); + _remap_indexes (&feature_indices, gsub_features); + + gsub.destroy (); +} + +static inline void +_gpos_closure_lookups_features (hb_face_t *face, + const hb_set_t *gids_to_retain, + hb_map_t *gpos_lookups, + hb_map_t *gpos_features, + script_langsys_map *gpos_langsys) +{ + hb_set_t lookup_indices; + hb_ot_layout_collect_lookups (face, + HB_OT_TAG_GPOS, + nullptr, + nullptr, + nullptr, + &lookup_indices); + hb_blob_ptr_t gpos = hb_sanitize_context_t ().reference_table (face); + gpos->closure_lookups (face, + gids_to_retain, + &lookup_indices); + _remap_indexes (&lookup_indices, gpos_lookups); + + // Collect and prune features + hb_set_t feature_indices; + hb_ot_layout_collect_features (face, + HB_OT_TAG_GPOS, + nullptr, + nullptr, + nullptr, + &feature_indices); + + gpos->prune_features (gpos_lookups, &feature_indices); + hb_map_t duplicate_feature_map; + gpos->find_duplicate_features (gpos_lookups, &feature_indices, &duplicate_feature_map); + + feature_indices.clear (); + gpos->prune_langsys (&duplicate_feature_map, gpos_langsys, &feature_indices); + _remap_indexes (&feature_indices, gpos_features); + + gpos.destroy (); } #endif +#ifndef HB_NO_VAR +static inline void + _collect_layout_variation_indices (hb_face_t *face, + const hb_set_t *glyphset, + const hb_map_t *gpos_lookups, + hb_set_t *layout_variation_indices, + hb_map_t *layout_variation_idx_map) +{ + hb_blob_ptr_t gdef = hb_sanitize_context_t ().reference_table (face); + hb_blob_ptr_t gpos = hb_sanitize_context_t ().reference_table (face); + + if (!gdef->has_data ()) + { + gdef.destroy (); + gpos.destroy (); + return; + } + OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups); + gdef->collect_variation_indices (&c); + + if (hb_ot_layout_has_positioning (face)) + gpos->collect_variation_indices (&c); + + gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map); + + gdef.destroy (); + gpos.destroy (); +} +#endif + +static inline void +_cmap_closure (hb_face_t *face, + const hb_set_t *unicodes, + hb_set_t *glyphset) +{ + OT::cmap::accelerator_t cmap; + cmap.init (face); + cmap.table->closure_glyphs (unicodes, glyphset); + cmap.fini (); +} + static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) @@ -102,15 +207,23 @@ _remove_invalid_gids (hb_set_t *glyphs, static void _populate_gids_to_retain (hb_subset_plan_t* plan, const hb_set_t *unicodes, - const hb_set_t *input_glyphs_to_retain, - bool close_over_gsub) + const hb_set_t *input_glyphs_to_retain, + bool close_over_gsub, + bool close_over_gpos, + bool close_over_gdef) { OT::cmap::accelerator_t cmap; OT::glyf::accelerator_t glyf; +#ifndef HB_NO_SUBSET_CFF OT::cff1::accelerator_t cff; +#endif + OT::COLR::accelerator_t colr; cmap.init (plan->source); glyf.init (plan->source); +#ifndef HB_NO_SUBSET_CFF cff.init (plan->source); +#endif + colr.init (plan->source); plan->_glyphset_gsub->add (0); // Not-def hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain); @@ -129,10 +242,15 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->_glyphset_gsub->add (gid); } + _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub); + #ifndef HB_NO_SUBSET_LAYOUT if (close_over_gsub) - // Add all glyphs needed for GSUB substitutions. - _gsub_closure (plan->source, plan->_glyphset_gsub); + // closure all glyphs/lookups/features needed for GSUB substitutions. + _gsub_closure_glyphs_lookups_features (plan->source, plan->_glyphset_gsub, plan->gsub_lookups, plan->gsub_features, plan->gsub_langsys); + + if (close_over_gpos) + _gpos_closure_lookups_features (plan->source, plan->_glyphset_gsub, plan->gpos_lookups, plan->gpos_features, plan->gpos_langsys); #endif _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ()); @@ -141,27 +259,40 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, hb_codepoint_t gid = HB_SET_VALUE_INVALID; while (plan->_glyphset_gsub->next (&gid)) { - _add_gid_and_children (glyf, gid, plan->_glyphset); + glyf.add_gid_and_children (gid, plan->_glyphset); #ifndef HB_NO_SUBSET_CFF if (cff.is_valid ()) _add_cff_seac_components (cff, gid, plan->_glyphset); #endif + if (colr.is_valid ()) + colr.closure_glyphs (gid, plan->_glyphset); } _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); +#ifndef HB_NO_VAR + if (close_over_gdef) + _collect_layout_variation_indices (plan->source, + plan->_glyphset_gsub, + plan->gpos_lookups, + plan->layout_variation_indices, + plan->layout_variation_idx_map); +#endif + +#ifndef HB_NO_SUBSET_CFF cff.fini (); +#endif glyf.fini (); cmap.fini (); } static void _create_old_gid_to_new_gid_map (const hb_face_t *face, - bool retain_gids, + bool retain_gids, const hb_set_t *all_gids_to_retain, - hb_map_t *glyph_map, /* OUT */ - hb_map_t *reverse_glyph_map, /* OUT */ - unsigned int *num_glyphs /* OUT */) + hb_map_t *glyph_map, /* OUT */ + hb_map_t *reverse_glyph_map, /* OUT */ + unsigned int *num_glyphs /* OUT */) { if (!retain_gids) { @@ -191,10 +322,10 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face, } static void -_nameid_closure (hb_face_t *face, - hb_set_t *nameids) +_nameid_closure (hb_face_t *face, + hb_set_t *nameids) { -#ifndef HB_NO_STAT +#ifndef HB_NO_STYLE face->table.STAT->collect_name_ids (nameids); #endif #ifndef HB_NO_VAR @@ -213,17 +344,23 @@ _nameid_closure (hb_face_t *face, * Since: 1.7.5 **/ hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - hb_subset_input_t *input) +hb_subset_plan_create (hb_face_t *face, + hb_subset_input_t *input) { - hb_subset_plan_t *plan = hb_object_create (); + hb_subset_plan_t *plan; + if (unlikely (!(plan = hb_object_create ()))) + return const_cast (&Null (hb_subset_plan_t)); + plan->successful = true; plan->drop_hints = input->drop_hints; plan->desubroutinize = input->desubroutinize; plan->retain_gids = input->retain_gids; + plan->name_legacy = input->name_legacy; plan->unicodes = hb_set_create (); plan->name_ids = hb_set_reference (input->name_ids); _nameid_closure (face, plan->name_ids); + plan->name_languages = hb_set_reference (input->name_languages); + plan->glyphs_requested = hb_set_reference (input->glyphs); plan->drop_tables = hb_set_reference (input->drop_tables); plan->source = hb_face_reference (face); plan->dest = hb_face_builder_create (); @@ -233,18 +370,36 @@ hb_subset_plan_create (hb_face_t *face, plan->codepoint_to_glyph = hb_map_create (); plan->glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create (); + plan->gsub_lookups = hb_map_create (); + plan->gpos_lookups = hb_map_create (); + + if (plan->check_success (plan->gsub_langsys = hb_object_create ())) + plan->gsub_langsys->init_shallow (); + if (plan->check_success (plan->gpos_langsys = hb_object_create ())) + plan->gpos_langsys->init_shallow (); + + plan->gsub_features = hb_map_create (); + plan->gpos_features = hb_map_create (); + plan->layout_variation_indices = hb_set_create (); + plan->layout_variation_idx_map = hb_map_create (); + + if (plan->in_error ()) { + return plan; + } _populate_gids_to_retain (plan, - input->unicodes, - input->glyphs, - !input->drop_tables->has (HB_OT_TAG_GSUB)); + input->unicodes, + input->glyphs, + !input->drop_tables->has (HB_OT_TAG_GSUB), + !input->drop_tables->has (HB_OT_TAG_GPOS), + !input->drop_tables->has (HB_OT_TAG_GDEF)); _create_old_gid_to_new_gid_map (face, - input->retain_gids, + input->retain_gids, plan->_glyphset, plan->glyph_map, - plan->reverse_glyph_map, - &plan->_num_output_glyphs); + plan->reverse_glyph_map, + &plan->_num_output_glyphs); return plan; } @@ -261,6 +416,8 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_set_destroy (plan->unicodes); hb_set_destroy (plan->name_ids); + hb_set_destroy (plan->name_languages); + hb_set_destroy (plan->glyphs_requested); hb_set_destroy (plan->drop_tables); hb_face_destroy (plan->source); hb_face_destroy (plan->dest); @@ -269,6 +426,32 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_map_destroy (plan->reverse_glyph_map); hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); + hb_map_destroy (plan->gsub_lookups); + hb_map_destroy (plan->gpos_lookups); + hb_map_destroy (plan->gsub_features); + hb_map_destroy (plan->gpos_features); + hb_set_destroy (plan->layout_variation_indices); + hb_map_destroy (plan->layout_variation_idx_map); + + if (plan->gsub_langsys) + { + for (auto _ : plan->gsub_langsys->iter ()) + hb_set_destroy (_.second); + + hb_object_destroy (plan->gsub_langsys); + plan->gsub_langsys->fini_shallow (); + free (plan->gsub_langsys); + } + + if (plan->gpos_langsys) + { + for (auto _ : plan->gpos_langsys->iter ()) + hb_set_destroy (_.second); + + hb_object_destroy (plan->gpos_langsys); + plan->gpos_langsys->fini_shallow (); + free (plan->gpos_langsys); + } free (plan); } diff --git a/src/hb-subset-plan.hh b/src/hb-subset-plan.hh index ee44b63a4670645135b747c6eba1a1d729be95d8..1c070f91388aa7dfe6581d839002cbf050ab27ff 100644 --- a/src/hb-subset-plan.hh +++ b/src/hb-subset-plan.hh @@ -39,9 +39,11 @@ struct hb_subset_plan_t { hb_object_header_t header; + bool successful : 1; bool drop_hints : 1; bool desubroutinize : 1; bool retain_gids : 1; + bool name_legacy : 1; // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; @@ -49,6 +51,12 @@ struct hb_subset_plan_t // name_ids we would like to retain hb_set_t *name_ids; + // name_languages we would like to retain + hb_set_t *name_languages; + + //glyph ids requested to retain + hb_set_t *glyphs_requested; + // Tables which should be dropped. hb_set_t *drop_tables; @@ -67,8 +75,33 @@ struct hb_subset_plan_t hb_set_t *_glyphset; hb_set_t *_glyphset_gsub; + //active lookups we'd like to retain + hb_map_t *gsub_lookups; + hb_map_t *gpos_lookups; + + //active langsys we'd like to retain + hb_hashmap_t *gsub_langsys; + hb_hashmap_t *gpos_langsys; + + //active features after removing redundant langsys and prune_features + hb_map_t *gsub_features; + hb_map_t *gpos_features; + + //The set of layout item variation store delta set indices to be retained + hb_set_t *layout_variation_indices; + //Old -> New layout item variation store delta set index mapping + hb_map_t *layout_variation_idx_map; + public: + bool in_error () const { return !successful; } + + bool check_success(bool success) + { + successful = (successful && success); + return successful; + } + /* * The set of input glyph ids which will be retained in the subset. * Does NOT include ids kept due to retain_gids. You probably want to use @@ -108,7 +141,7 @@ struct hb_subset_plan_t } inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, - hb_codepoint_t *new_gid) const + hb_codepoint_t *new_gid) const { hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint); if (old_gid == HB_MAP_VALUE_INVALID) @@ -118,7 +151,7 @@ struct hb_subset_plan_t } inline bool new_gid_for_old_gid (hb_codepoint_t old_gid, - hb_codepoint_t *new_gid) const + hb_codepoint_t *new_gid) const { hb_codepoint_t gid = glyph_map->get (old_gid); if (gid == HB_MAP_VALUE_INVALID) @@ -129,7 +162,7 @@ struct hb_subset_plan_t } inline bool old_gid_for_new_gid (hb_codepoint_t new_gid, - hb_codepoint_t *old_gid) const + hb_codepoint_t *old_gid) const { hb_codepoint_t gid = reverse_glyph_map->get (new_gid); if (gid == HB_MAP_VALUE_INVALID) @@ -143,12 +176,15 @@ struct hb_subset_plan_t add_table (hb_tag_t tag, hb_blob_t *contents) { - hb_blob_t *source_blob = source->reference_table (tag); - DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes", - HB_UNTAG(tag), - hb_blob_get_length (contents), - hb_blob_get_length (source_blob)); - hb_blob_destroy (source_blob); + if (HB_DEBUG_SUBSET) + { + hb_blob_t *source_blob = source->reference_table (tag); + DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %d bytes, source %d bytes", + HB_UNTAG(tag), + hb_blob_get_length (contents), + hb_blob_get_length (source_blob)); + hb_blob_destroy (source_blob); + } return hb_face_builder_add_table (dest, tag, contents); } }; @@ -157,7 +193,7 @@ typedef struct hb_subset_plan_t hb_subset_plan_t; HB_INTERNAL hb_subset_plan_t * hb_subset_plan_create (hb_face_t *face, - hb_subset_input_t *input); + hb_subset_input_t *input); HB_INTERNAL void hb_subset_plan_destroy (hb_subset_plan_t *plan); diff --git a/src/hb-subset.cc b/src/hb-subset.cc index 6235a5bf5314b00a0234d876ee5c6506bd7c90fd..d443d248be57913dae9fb807dd32d1c522cd6068 100644 --- a/src/hb-subset.cc +++ b/src/hb-subset.cc @@ -37,94 +37,96 @@ #include "hb-ot-hhea-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-maxp-table.hh" +#include "hb-ot-color-sbix-table.hh" +#include "hb-ot-color-colr-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-vorg-table.hh" #include "hb-ot-name-table.hh" +#include "hb-ot-color-cbdt-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-var-gvar-table.hh" +#include "hb-ot-var-hvar-table.hh" +#include "hb-repacker.hh" -HB_UNUSED static inline unsigned int -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, - unsigned int table_len); -static inline unsigned int -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, - unsigned int table_len) +static unsigned +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) { - unsigned int src_glyphs = plan->source->get_num_glyphs (); - unsigned int dst_glyphs = plan->glyphset ()->get_population (); + unsigned src_glyphs = plan->source->get_num_glyphs (); + unsigned dst_glyphs = plan->glyphset ()->get_population (); if (unlikely (!src_glyphs)) return 512 + table_len; - return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); + return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); +} + +/* + * Repack the serialization buffer if any offset overflows exist. + */ +static hb_blob_t* +_repack (hb_tag_t tag, const hb_serialize_context_t& c) +{ + if (tag != HB_OT_TAG_GPOS + && tag != HB_OT_TAG_GSUB) + { + // Check for overflow in a non-handled table. + return c.successful () ? c.copy_blob () : nullptr; + } + + if (!c.offset_overflow ()) + return c.copy_blob (); + + hb_vector_t buf; + int buf_size = c.end - c.start; + if (unlikely (!buf.alloc (buf_size))) + return nullptr; + + hb_serialize_context_t repacked ((void *) buf, buf_size); + hb_resolve_overflows (c.object_graph (), &repacked); + + if (unlikely (repacked.in_error ())) + // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset + // portion. + return nullptr; + + return repacked.copy_blob (); } template -static bool -_subset2 (hb_subset_plan_t *plan) +static +bool +_try_subset (const TableType *table, + hb_vector_t* buf, + unsigned buf_size, + hb_subset_context_t* c /* OUT */) { - bool result = false; - hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table (plan->source); - const TableType *table = source_blob->as (); + c->serializer->start_serialize (); - hb_tag_t tag = TableType::tableTag; - if (source_blob->data) + bool needed = table->subset (c); + if (!c->serializer->ran_out_of_room ()) { - hb_vector_t buf; - /* TODO Not all tables are glyph-related. 'name' table size for example should not be - * affected by number of glyphs. Accommodate that. */ - unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); - return false; - } - retry: - hb_serialize_context_t serializer ((void *) buf, buf_size); - serializer.start_serialize (); - hb_subset_context_t c (plan, &serializer); - bool needed = table->subset (&c); - if (serializer.ran_out_of_room) - { - buf_size += (buf_size >> 1) + 32; - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size); - if (unlikely (!buf.alloc (buf_size))) - { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size); - return false; - } - goto retry; - } - serializer.end_serialize (); + c->serializer->end_serialize (); + return needed; + } - result = !serializer.in_error (); + buf_size += (buf_size >> 1) + 32; + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", + HB_UNTAG (c->table_tag), buf_size); - if (result) - { - if (needed) - { - hb_blob_t *dest_blob = serializer.copy_blob (); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); - result = c.plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } - else - { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - } - } + if (unlikely (!buf->alloc (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", + HB_UNTAG (c->table_tag), buf_size); + return needed; } - else - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - hb_blob_destroy (source_blob); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); - return result; + c->serializer->reset (buf->arrayZ, buf_size); + return _try_subset (table, buf, buf_size, c); } template @@ -135,102 +137,76 @@ _subset (hb_subset_plan_t *plan) const TableType *table = source_blob->as (); hb_tag_t tag = TableType::tableTag; - hb_bool_t result = false; - if (source_blob->data) - result = table->subset (plan); - else - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + if (!source_blob->data) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + hb_blob_destroy (source_blob); + return false; + } + hb_vector_t buf; + /* TODO Not all tables are glyph-related. 'name' table size for example should not be + * affected by number of glyphs. Accommodate that. */ + unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); + if (unlikely (!buf.alloc (buf_size))) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + hb_blob_destroy (source_blob); + return false; + } + + bool needed = false; + hb_serialize_context_t serializer (buf.arrayZ, buf_size); + { + hb_subset_context_t c (source_blob, plan, &serializer, tag); + needed = _try_subset (table, &buf, buf_size, &c); + } hb_blob_destroy (source_blob); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); - return result; -} + if (serializer.in_error () && !serializer.only_offset_overflow ()) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset FAILED!", HB_UNTAG (tag)); + return false; + } -static bool -_subset_table (hb_subset_plan_t *plan, - hb_tag_t tag) -{ - DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG (tag)); - bool result = true; - switch (tag) { - case HB_OT_TAG_glyf: - result = _subset2 (plan); - break; - case HB_OT_TAG_hdmx: - result = _subset2 (plan); - break; - case HB_OT_TAG_name: - result = _subset2 (plan); - break; - case HB_OT_TAG_head: - // TODO that won't work well if there is no glyf - DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf"); - result = true; - break; - case HB_OT_TAG_hhea: - DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx"); - return true; - case HB_OT_TAG_hmtx: - result = _subset2 (plan); - break; - case HB_OT_TAG_vhea: - DEBUG_MSG(SUBSET, nullptr, "skip vhea handled by vmtx"); - return true; - case HB_OT_TAG_vmtx: - result = _subset2 (plan); - break; - case HB_OT_TAG_maxp: - result = _subset2 (plan); - break; - case HB_OT_TAG_loca: - DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf"); - return true; - case HB_OT_TAG_cmap: - result = _subset2 (plan); - break; - case HB_OT_TAG_OS2: - result = _subset2 (plan); - break; - case HB_OT_TAG_post: - result = _subset2 (plan); - break; + if (!needed) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + return true; + } -#ifndef HB_NO_SUBSET_CFF - case HB_OT_TAG_cff1: - result = _subset (plan); - break; - case HB_OT_TAG_cff2: - result = _subset (plan); - break; - case HB_OT_TAG_VORG: - result = _subset2 (plan); - break; -#endif + bool result = false; + hb_blob_t *dest_blob = _repack (tag, serializer); + if (dest_blob) + { + DEBUG_MSG (SUBSET, nullptr, + "OT::%c%c%c%c final subset table size: %u bytes.", + HB_UNTAG (tag), dest_blob->length); + result = plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } -#ifndef HB_NO_SUBSET_LAYOUT - case HB_OT_TAG_GDEF: - result = _subset2 (plan); - break; - case HB_OT_TAG_GSUB: - result = _subset2 (plan); - break; - case HB_OT_TAG_GPOS: - result = _subset2 (plan); - break; -#endif + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", + HB_UNTAG (tag), result ? "success" : "FAILED!"); + return result; +} - default: - hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); - if (likely (source_table)) - result = plan->add_table (tag, source_table); - else - result = false; - hb_blob_destroy (source_table); - break; +static bool +_is_table_present (hb_face_t *source, hb_tag_t tag) +{ + hb_tag_t table_tags[32]; + unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); + while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + { + for (unsigned i = 0; i < num_tables; ++i) + if (table_tags[i] == tag) + return true; + offset += num_tables; } - DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG (tag), result ? "ok" : "FAILED"); - return result; + return false; } static bool @@ -239,29 +215,80 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) if (plan->drop_tables->has (tag)) return true; - switch (tag) { - case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */ - case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */ - case HB_TAG ('f', 'p', 'g', 'm'): /* hint table, fallthrough */ - case HB_TAG ('p', 'r', 'e', 'p'): /* hint table, fallthrough */ - case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */ - case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */ - return plan->drop_hints; + switch (tag) + { + case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */ + case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */ + case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */ + case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */ + case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */ + case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */ + return plan->drop_hints; #ifdef HB_NO_SUBSET_LAYOUT // Drop Layout Tables if requested. - case HB_OT_TAG_GDEF: - case HB_OT_TAG_GPOS: - case HB_OT_TAG_GSUB: - case HB_TAG ('m', 'o', 'r', 'x'): - case HB_TAG ('m', 'o', 'r', 't'): - case HB_TAG ('k', 'e', 'r', 'x'): - case HB_TAG ('k', 'e', 'r', 'n'): - return true; + case HB_OT_TAG_GDEF: + case HB_OT_TAG_GPOS: + case HB_OT_TAG_GSUB: + case HB_TAG ('m','o','r','x'): + case HB_TAG ('m','o','r','t'): + case HB_TAG ('k','e','r','x'): + case HB_TAG ('k','e','r','n'): + return true; #endif - default: - return false; + default: + return false; + } +} + +static bool +_subset_table (hb_subset_plan_t *plan, hb_tag_t tag) +{ + DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); + switch (tag) + { + case HB_OT_TAG_glyf: return _subset (plan); + case HB_OT_TAG_hdmx: return _subset (plan); + case HB_OT_TAG_name: return _subset (plan); + case HB_OT_TAG_head: + if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) + return true; /* skip head, handled by glyf */ + return _subset (plan); + case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ + case HB_OT_TAG_hmtx: return _subset (plan); + case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ + case HB_OT_TAG_vmtx: return _subset (plan); + case HB_OT_TAG_maxp: return _subset (plan); + case HB_OT_TAG_sbix: return _subset (plan); + case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ + case HB_OT_TAG_cmap: return _subset (plan); + case HB_OT_TAG_OS2 : return _subset (plan); + case HB_OT_TAG_post: return _subset (plan); + case HB_OT_TAG_COLR: return _subset (plan); + case HB_OT_TAG_CBLC: return _subset (plan); + case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ + +#ifndef HB_NO_SUBSET_CFF + case HB_OT_TAG_cff1: return _subset (plan); + case HB_OT_TAG_cff2: return _subset (plan); + case HB_OT_TAG_VORG: return _subset (plan); +#endif + +#ifndef HB_NO_SUBSET_LAYOUT + case HB_OT_TAG_GDEF: return _subset (plan); + case HB_OT_TAG_GSUB: return _subset (plan); + case HB_OT_TAG_GPOS: return _subset (plan); + case HB_OT_TAG_gvar: return _subset (plan); + case HB_OT_TAG_HVAR: return _subset (plan); + case HB_OT_TAG_VVAR: return _subset (plan); +#endif + + default: + hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); + bool result = plan->add_table (tag, source_table); + hb_blob_destroy (source_table); + return result; } } @@ -273,33 +300,36 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) * Subsets a font according to provided input. **/ hb_face_t * -hb_subset (hb_face_t *source, - hb_subset_input_t *input) +hb_subset (hb_face_t *source, hb_subset_input_t *input) { if (unlikely (!input || !source)) return hb_face_get_empty (); hb_subset_plan_t *plan = hb_subset_plan_create (source, input); + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return hb_face_get_empty (); + } - hb_tag_t table_tags[32]; - unsigned int offset = 0, count; + hb_set_t tags_set; bool success = true; - do { - count = ARRAY_LENGTH (table_tags); - hb_face_get_table_tags (source, offset, &count, table_tags); - for (unsigned int i = 0; i < count; i++) + hb_tag_t table_tags[32]; + unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); + while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + { + for (unsigned i = 0; i < num_tables; ++i) { hb_tag_t tag = table_tags[i]; - if (_should_drop_table (plan, tag)) - { - DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag)); - continue; - } - success = success && _subset_table (plan, tag); + if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; + tags_set.add (tag); + success = _subset_table (plan, tag); + if (unlikely (!success)) goto end; } - offset += count; - } while (success && count == ARRAY_LENGTH (table_tags)); + offset += num_tables; + } +end: hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty (); + hb_subset_plan_destroy (plan); return result; } diff --git a/src/hb-subset.h b/src/hb-subset.h index c778896a202a74311dd3813bdfd1e7e6e6869831..ddf4409734e45437497fc4c6c51f0b2eaebc0487 100644 --- a/src/hb-subset.h +++ b/src/hb-subset.h @@ -57,6 +57,9 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input); HB_EXTERN hb_set_t * hb_subset_input_nameid_set (hb_subset_input_t *subset_input); +HB_EXTERN hb_set_t * +hb_subset_input_namelangid_set (hb_subset_input_t *subset_input); + HB_EXTERN hb_set_t * hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input); @@ -68,7 +71,7 @@ hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input); HB_EXTERN void hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, - hb_bool_t desubroutinize); + hb_bool_t desubroutinize); HB_EXTERN hb_bool_t hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input); @@ -78,6 +81,12 @@ hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input, HB_EXTERN hb_bool_t hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input); +HB_EXTERN void +hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input, + hb_bool_t name_legacy); +HB_EXTERN hb_bool_t +hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input); + /* hb_subset () */ HB_EXTERN hb_face_t * hb_subset (hb_face_t *source, hb_subset_input_t *input); diff --git a/src/hb-subset.hh b/src/hb-subset.hh index b8dd07ab288b01d0c3a436da955fae925a64857c..c9b01c67f3d2cd2ddb391cd0a193d7c1eb45bb07 100644 --- a/src/hb-subset.hh +++ b/src/hb-subset.hh @@ -54,15 +54,19 @@ struct hb_subset_context_t : dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN ( _dispatch (obj, hb_prioritize, hb_forward (ds)...) ) + hb_blob_t *source_blob; hb_subset_plan_t *plan; hb_serialize_context_t *serializer; - unsigned int debug_depth; + hb_tag_t table_tag; - hb_subset_context_t (hb_subset_plan_t *plan_, - hb_serialize_context_t *serializer_) : + hb_subset_context_t (hb_blob_t *source_blob_, + hb_subset_plan_t *plan_, + hb_serialize_context_t *serializer_, + hb_tag_t table_tag_) : + source_blob (source_blob_), plan (plan_), serializer (serializer_), - debug_depth (0) {} + table_tag (table_tag_) {} }; diff --git a/src/hb-ucd-table.hh b/src/hb-ucd-table.hh index 8b7d648a93017f856c0d08ef297ab62bf5ad5060..88623db33876080dc324b0e2533aa932bedabc57 100644 --- a/src/hb-ucd-table.hh +++ b/src/hb-ucd-table.hh @@ -4,7 +4,7 @@ * * ./gen-ucd-table.py ucd.nounihan.grouped.xml * - * on file with this description: Unicode 12.1.0 + * on file with this description: Unicode 13.0.0 */ #ifndef HB_UCD_TABLE_HH @@ -13,7 +13,7 @@ #include "hb.hh" static const hb_script_t -_hb_ucd_sc_map[153] = +_hb_ucd_sc_map[157] = { HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC, @@ -91,7 +91,9 @@ _hb_ucd_sc_map[153] = HB_SCRIPT_MEDEFAIDRIN, HB_SCRIPT_OLD_SOGDIAN, HB_SCRIPT_SOGDIAN, HB_SCRIPT_ELYMAIC, HB_SCRIPT_NANDINAGARI, HB_SCRIPT_NYIAKENG_PUACHUE_HMONG, - HB_SCRIPT_WANCHO, + HB_SCRIPT_WANCHO, HB_SCRIPT_CHORASMIAN, + HB_SCRIPT_DIVES_AKURU, HB_SCRIPT_KHITAN_SMALL_SCRIPT, + HB_SCRIPT_YEZIDI, }; static const uint16_t _hb_ucd_dm1_p0_map[825] = @@ -862,7 +864,7 @@ _hb_ucd_dm2_u32_map[638] = HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9u, 0x0308u, 0x04EBu), }; static const uint64_t -_hb_ucd_dm2_u64_map[387] = +_hb_ucd_dm2_u64_map[388] = { HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B8u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BCu, 0x0000u), @@ -1051,19 +1053,19 @@ _hb_ucd_dm2_u64_map[387] = HB_CODEPOINT_ENCODE3 (0x11347u, 0x11357u, 0x1134Cu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114B0u, 0x114BCu), HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BAu, 0x114BBu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BDu, 0x114BEu), HB_CODEPOINT_ENCODE3 (0x115B8u, 0x115AFu, 0x115BAu),HB_CODEPOINT_ENCODE3 (0x115B9u, 0x115AFu, 0x115BBu), - HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u), - HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x11935u, 0x11930u, 0x11938u), HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u), }; #ifndef HB_OPTIMIZE_SIZE static const uint8_t -_hb_ucd_u8[32102] = +_hb_ucd_u8[32480] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 26, 26, @@ -1077,7 +1079,7 @@ _hb_ucd_u8[32102] = 26, 57, 58, 59, 59, 59, 59, 59, 26, 26, 60, 59, 59, 59, 59, 59, 59, 59, 26, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 26, 62, 59, 63, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 64, 26, 65, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 26, 26, 26, 64, 26, 26, 65, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 66, 67, 59, 59, 59, 59, 68, 59, 59, 59, 59, 59, 59, 59, 59, 59, 69, 70, 71, 72, 73, 74, 59, 59, 75, 76, 59, 59, 77, 59, 78, 79, 80, 81, 73, 82, 83, 84, 59, 59, @@ -1089,6 +1091,7 @@ _hb_ucd_u8[32102] = 26, 26, 26, 85, 26, 26, 26, 26, 26, 26, 26, 86, 87, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 88, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 89, 59, 59, 59, 59, 59, 59, 26, 90, 59, 59, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 91, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, @@ -1176,8 +1179,7 @@ _hb_ucd_u8[32102] = 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 91, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 92, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, @@ -1192,7 +1194,7 @@ _hb_ucd_u8[32102] = 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 92, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -1200,7 +1202,7 @@ _hb_ucd_u8[32102] = 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21, @@ -1274,7 +1276,8 @@ _hb_ucd_u8[32102] = 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 2, 2, 21, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, + 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, @@ -1306,7 +1309,7 @@ _hb_ucd_u8[32102] = 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12, 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 2, 2, - 2, 2, 2, 2, 2, 2, 12, 10, 2, 2, 2, 2, 7, 7, 2, 7, + 2, 2, 2, 2, 2, 12, 12, 10, 2, 2, 2, 2, 7, 7, 2, 7, 26, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 7, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7, 7, 2, 7, 7, 7, 7, 2, 2, 2, 7, 7, 2, 7, 2, 7, 7, @@ -1326,12 +1329,12 @@ _hb_ucd_u8[32102] = 10, 10, 10, 10, 10, 2, 12, 10, 10, 2, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 10, 10, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 12, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, + 12, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 7, 10, 10, 10, 12, 12, 12, 12, 2, 10, 10, 10, 2, 10, 10, 10, 12, 7, 26, 2, 2, 2, 2, 7, 7, 7, 10, 15, 15, 15, 15, 15, 15, 15, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 7, 7, 7, 7, 7, 7, - 2, 2, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 12, 2, 2, 2, 2, 10, @@ -1415,7 +1418,8 @@ _hb_ucd_u8[32102] = 12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12, 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 2, 2, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 2, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12, + 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 10, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, @@ -1464,7 +1468,6 @@ _hb_ucd_u8[32102] = 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 9, 26, 26, 26, 26, 9, 26, 26, 5, 9, 9, 9, 5, 5, 9, 9, 9, 5, 26, 9, 26, 26, 25, 9, 9, 9, 9, 9, 26, 26, 26, 26, 26, 26, 9, 26, 9, 26, 9, 26, 9, 9, 9, 9, 26, 5, @@ -1505,7 +1508,7 @@ _hb_ucd_u8[32102] = 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 9, 5, 9, 9, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9, @@ -1522,6 +1525,7 @@ _hb_ucd_u8[32102] = 20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21, 17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 26, 26, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1554,10 +1558,10 @@ _hb_ucd_u8[32102] = 9, 5, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9, 9, 9, 5, 9, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, - 2, 2, 9, 5, 9, 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 7, 6, 6, 5, 7, 7, 7, 7, 7, + 2, 2, 9, 5, 9, 9, 9, 9, 5, 9, 5, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 9, 5, 7, 6, 6, 5, 7, 7, 7, 7, 7, 7, 7, 12, 7, 7, 7, 12, 7, 7, 7, 7, 12, 7, 7, 7, 7, - 7, 7, 7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 2, 2, 2, 2, + 7, 7, 7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 12, 2, 2, 2, 15, 15, 15, 15, 15, 15, 26, 26, 23, 26, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, @@ -1585,7 +1589,7 @@ _hb_ucd_u8[32102] = 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 6, 6, 6, 6, - 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 24, 24, 2, 2, 2, 2, 7, 7, 7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12, 2, 2, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7, @@ -1601,14 +1605,12 @@ _hb_ucd_u8[32102] = 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 18, 22, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 23, 26, 2, 2, 21, 21, 21, 21, 21, 21, 21, 22, 18, 21, 2, 2, 2, 2, 2, 2, 21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16, 21, 21, 21, 2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21, 21, 21, 25, 17, 25, 25, 25, 2, 21, 23, 21, 21, 2, 2, 2, 2, - 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 1, 2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 22, @@ -1625,6 +1627,7 @@ _hb_ucd_u8[32102] = 15, 15, 15, 15, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 2, 2, 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, @@ -1668,8 +1671,11 @@ _hb_ucd_u8[32102] = 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 12, 12, 17, 2, 2, + 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 7, 2, 2, 2, 2, 2, 2, 2, 2, 12, 15, 15, 15, 15, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 10, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 2, 2, @@ -1680,10 +1686,10 @@ _hb_ucd_u8[32102] = 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 12, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 21, 21, 21, 21, 7, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 21, 21, 21, 21, 7, 10, 10, 7, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 12, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, - 10, 7, 7, 7, 7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 2, 2, + 10, 7, 7, 7, 7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 10, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 21, 7, 21, 21, 21, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1702,7 +1708,7 @@ _hb_ucd_u8[32102] = 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12, 10, 12, 7, 7, 7, 7, 21, 21, 21, 21, 21, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 21, 2, 21, 12, 7, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 21, 12, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12, 12, 10, 12, 12, 7, 7, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, @@ -1718,6 +1724,10 @@ _hb_ucd_u8[32102] = 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26, 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 2, 2, 2, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 2, 7, 7, 7, 7, + 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 2, 12, 12, 10, 12, 7, + 10, 7, 10, 12, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 2, 2, 12, 12, 10, 10, 10, 10, 12, 7, 21, 7, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -1759,7 +1769,8 @@ _hb_ucd_u8[32102] = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 21, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 6, 6, 21, 6, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 26, 12, 12, 21, @@ -1832,334 +1843,338 @@ _hb_ucd_u8[32102] = 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 25, 25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, - 26, 26, 2, 26, 26, 26, 26, 2, 2, 2, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 2, 2, 2, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 26, 26, 26, - 26, 26, 26, 26, 2, 2, 2, 2, 26, 26, 26, 2, 2, 2, 2, 2, - 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 2, 2, 2, 26, 26, 26, 2, 2, 2, 2, 2, + 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, - 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 0, 0, 15, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 0, 0, - 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 25, 0, 0, - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 12, 12, 13, 14, 12, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 24, 25, + 0, 26, 27, 0, 28, 29, 30, 31, 32, 33, 0, 34, 0, 0, 0, 0, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 0, 0, 0, 0, + 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 27, 0, 28, 29, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 33, 0, - 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 37, 0, 0, 38, 0, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 0, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, + 43, 44, 45, 46, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 56, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 58, 54, 59, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, - 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, - 0, 16, 0, 0, 0, 0, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, - 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, 30, 31, 32, - 0, 0, 0, 0, 0, 30, 31, 0, 0, 33, 0, 0, 0, 30, 31, 0, - 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 30, 31, 0, - 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 31, 34, - 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 35, 31, 0, - 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 37, 38, 0, - 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 41, 0, 42, 0, 0, - 0, 43, 44, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0, - 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 49, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, - 54, 55, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 57, 49, 0, - 58, 59, 0, 0, 60, 0, 0, 0, 61, 62, 0, 0, 0, 63, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 64, 65, 66, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 67, 68, 1, 69, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 70, 71, 72, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, - 0, 75, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 76, 0, 0, 0, - 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 73, 78, 0, 79, 0, 0, 0, 0, 0, 74, 80, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 49, 0, 1, 74, 0, 0, 81, 0, 0, 82, - 0, 0, 0, 0, 0, 83, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 84, 85, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 86, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, - 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 91, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 93, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 94, 88, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, - 0, 75, 0, 0, 0, 95, 0, 0, 0, 0, 96, 0, 0, 97, 0, 0, - 0, 83, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 99, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 0,101, 31, 0, - 102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 33, - 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75,106, 0, 0, 0, 0, 0, 0, 75, 0, 0, - 0, 0, 0, 0, 0,107, 0, 0, 0, 0, 0, 0,108, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 49,109, 0, - 0, 0, 0,110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 0, - 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 0, 0, 0,113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 115,116,117, 0,118, 0, 0, 0, 0, 0, 0, 0, 0, 0,119, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,121,122, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 51, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 0, 0, 57, 58, 0, + 59, 60, 61, 62, 63, 64, 65, 0, 66, 67, 0, 68, 69, 70, 71, 0, + 60, 0, 72, 73, 74, 75, 0, 0, 69, 0, 76, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,123, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0,125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230, - 230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,232, - 220,220,220,220,232,216,220,220,220,220,220,202,202,220,220,220, - 220,202,202,220,220,220,220,220,220,220,220,220,220,220, 1, 1, - 1, 1, 1,220,220,220,220,230,230,230,230,230,230,230,230,240, - 230,220,220,220,230,230,230,220,220, 0,230,230,230,220,220,220, - 220,230,232,220,220,230,233,234,234,233,234,234,233,230,230,230, - 230,230,230,230,230,230,230,230,230,230, 0, 0, 0,230,230,230, - 230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0,220,230,230,230,230, - 220,230,230,230,222,220,230,230,230,230,230,230,220,220,220,220, - 220,220,230,230,220,230,230,222,228,230, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, - 0, 18, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230, - 230,230, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220, - 220,230,230,230,230,230,220,230,230,220, 35, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 230,230,230,230,230,230,230, 0, 0,230,230,230,230,220,230, 0, - 0,230,230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,220,230,230,220,230, - 230,220,220,220,230,220,220,230,220,230,230,230,220,230,220,230, - 220,230,220,230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,230,230,230,230,230,230,230,220,230, 0, 0, - 0, 0, 0, 0, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, - 230,230,230,230, 0,230,230,230,230,230,230,230,230,230, 0,230, - 230,230, 0,230,230,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,220,220,220, 0, 0, 0, 0, 0, 0, 0,220,230,230, - 230,230,230,230,230,230,230,230,230,230,230,230, 0,220,230,230, - 220,230,230,220,230,230,230,220,220,220, 27, 28, 29,230,230,230, - 220,230,230,220,220,230,230,230,230,230, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,230, 0, 0, 0, 0, 0, 0, 84, - 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,103,103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,107,107,107,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,118,118, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,122,122,122,122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,220,220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,220, - 0,220, 0,216, 0, 0, 0, 0, 0, 0, 0,129,130, 0,132, 0, - 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, 9, 0, - 230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 7, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, 0, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,222,230,220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,230,220, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230, - 230,230,230,230,230,230,230, 0, 0,220,230,230,230,230,230,220, - 220,220,220,220,220,230,230,220, 0, 0, 0, 0, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,230,220,230,230,230,230,230,230,230, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 1,220, - 220,220,220,220,230,230,220,220,220,220,230, 0, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 0,220, 0, 0, 0, 0, 0, 0,230, 0, - 0, 0,230,230, 0, 0, 0, 0, 0, 0,230,230,220,230,230,230, - 230,230,230,230,220,230,230,234,214,220,202,230,230,230,230,230, - 230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, - 232,228,228,220, 0,230,233,220,230,220,230,230, 1, 1,230,230, - 230,230, 1, 1, 1,230,230, 0, 0, 0, 0,230, 0, 0, 0, 1, - 1,230,220,230, 1, 1,220,220,220,220,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,218,228,232,222,224,224, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230, - 230,230,230,230,230,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,230,230, 0, 0, 0, 0, 0, 0, - 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,220,220,220, 0, 0, 0, 0, 0, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230, 0,230,230,220, 0, - 0,230,230, 0, 0, 0, 0, 0,230,230, 0,230, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 26, 0,230,230,230,230,230,230, - 230,220,220,220,220,220,220,220,230,230,220, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 230,230,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,220, 0,230, 0, 0, 0, 0, 0, 0, - 0, 0,230, 1,220, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,230, - 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230, - 230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 220,220,230,230,230,220,230,220,220,220, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 7, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, - 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 230,230,230,230,230,230,230, 0, 0, 0,230,230,230,230,230, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230, - 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,216, - 216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0, 0, 0, - 0, 0, 0, 0, 0,220,220,220,220,220,220,220,220, 0, 0,230, - 230,230,230,230,220,220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 0,230,230,230, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 0, 79, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 1, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 14, 15, 16, 17, 18, 19, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 21, 0, 0, 0, 0, 0, 22, 23, 24, + 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27, + 28, 29, 0, 0, 0, 0, 30, 0, 0, 0, 31, 32, 33, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 13, 35, 36, 0, 0, 26, 37, 38, 39, 0, 0, 0, 0, 0, 40, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 1, + 42, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, 48, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 50, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 54, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 56, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 58, 59, 0, 0, 0, 0, + 0, 0, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, + 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 68, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 71, 72, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 66, 74, 0, 0, 0, 0, 0, 0, 75, 76, 72, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 67, 0, 0, 0, + 0, 77, 78, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, + 80, 0, 79, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 82, + 83, 84, 85, 86, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 89, 1, + 1, 1, 90, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 93, + 94, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 71, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 71,100,101, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 86, 0,102, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, + 1, 1, 86, 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0,104, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 73, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106,107,108, 0, 0, 0, + 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 47, 0, 0, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26,112, 0,113, 0, 0, 0, 0, 0,114, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 115, 0, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117,118, 72, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, + 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0,119, 0, 0, 0, 0, + 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, + 0, 0,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73,120, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,122, 0, 0, 0, 0, 0, 0, 0, 0, 0,123, 0, 47, 0, 0, + 26,124,124, 0, 0, 0, 0, 0, 0, 0, 0, 0,125, 0, 0, 49, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,127, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,129,105, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 97, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,131, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,132, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,134, 0, 0, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 136,137,138,139,140,141, 0, 0, 0,142, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,143, 0, 0, 0, + 0, 0, 0, 0,133, 1, 1,144,145,112, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,146, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100,147, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230, + 230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216, + 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220, + 220,220,220,220,220,220,220,220, 1, 1, 1, 1, 1,220,220,220, + 220,230,230,230,230,230,230,230,230,240,230,220,220,220,230,230, + 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230, + 233,234,234,233,234,234,233,230,230,230,230,230, 0, 0, 0,230, + 230,230,230,230, 0,220,230,230,230,230,220,230,230,230,222,220, + 230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230, + 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, + 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, + 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, + 230,220,220,230,230,230,230,230,220,230,230,220, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230, - 230, 0,230,230,230,230,230,230,230,230,230,230,230,230,230,230, - 230,230,230, 0, 0,230,230,230,230,230,230,230, 0,230,230, 0, - 230,230,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,230,230,230,230,220,220,220,220,220,220, - 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230, - 230,230,230,230, 7, 0, 0, 0, 0, 0, 16, 17, 17, 17, 17, 17, - 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169, - 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 230, 0, 0,230,230,230,230,220,230, 0, 0,230,230, 0,220,230, + 230,220, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0,230,220,230,230, + 220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230, + 220,230,220,230,220,230,230, 0, 0, 0, 0, 0,230,230,220,230, + 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0, 0,230,230, 0,230, + 230,230,230,230,230,230,230,230, 0,230,230,230, 0,230,230,230, + 230,230, 0, 0, 0,220,220,220, 0, 0, 0, 0, 0, 0, 0,220, + 230,230,230,230,230,230, 0,220,230,230,220,230,230,220,230,230, + 230,220,220,220, 27, 28, 29,230,230,230,220,230,230,220,220,230, + 230,230,230,230, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0, 0, 0, + 0, 0,230, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,103,103, 9, 0, + 0, 0, 0, 0,107,107,107,107, 0, 0, 0, 0,118,118, 9, 0, + 0, 0, 0, 0,122,122,122,122, 0, 0, 0, 0,220,220, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0,220, 0,216, 0, 0, + 0, 0, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130, + 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0, 0, 0, + 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, 0,230, 0, 0, 0,228, 0, 0, + 0, 0, 0, 0, 0,222,230,220, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,230,220, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0,230,230,230,230,230, 0, 0,220,230,230,230,230, + 230,220,220,220,220,220,220,230,230,220, 0,220, 0, 0, 0,230, + 220,230,230,230,230,230,230,230, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,230,230,230, 0, + 1,220,220,220,220,220,230,230,220,220,220,220,230, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, + 230, 0, 0, 0,230,230, 0, 0, 0, 0, 0, 0,230,230,220,230, + 230,230,230,230,230,230,220,230,230,234,214,220,202,230,230,230, + 230,230,230,230,230,230,230,230,230,230,232,228,228,220, 0,230, + 233,220,230,220,230,230, 1, 1,230,230,230,230, 1, 1, 1,230, + 230, 0, 0, 0, 0,230, 0, 0, 0, 1, 1,230,220,230, 1, 1, + 220,220,220,220,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230,230,230, + 230,230, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,220, + 220,220, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 0, 0,230, 0,230,230,220, 0, 0,230,230, 0, 0, 0, + 0, 0,230,230, 0,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 0,230,230,230,230,230,230,230,220,220,220,220,220, + 220,220,230,230,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,220, 0,230,230, 1,220, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0,230,220, 0, 0, 0, 0,230,230, 0, 0, 0, 0, 0, 0, 0, + 0, 0,220,220,230,230,230,220,230,220,220,220, 0, 9, 7, 0, + 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 0, 0, 0,230,230,230,230,230, 0, 0, 0, 0, 0, 9, 0, + 0, 0, 7, 0, 0, 0, 9, 7, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, + 0, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 9, 9, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,230,230,230,230, + 230,230,230, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0,216,216, 1, 1, 1, 0, 0, + 0,226,216,216,216,216,216, 0, 0, 0, 0, 0, 0, 0, 0,220, + 220,220,220,220,220,220,220, 0, 0,230,230,230,230,230,220,220, + 0, 0, 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 0,230,230, + 230, 0, 0, 0,230, 0, 0,230,230,230,230,230,230,230, 0,230, + 230, 0,230,230,220,220,220,220,220,220,220, 0,230,230, 7, 0, + 0, 0, 0, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19, + 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, - 3, 4, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17,237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, + 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, + 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, + 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, + 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, + 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, - 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, - 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, - 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, - 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, - 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, + 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20, + 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0, + 0, 40, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 21, + 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45, + 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 21, 32, 4, 0, 10, - 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, - 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, - 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 21, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, - 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, - 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 1, 20, - 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, - 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, - 3, 4, 0, 0, 0, 0, 0, 0, 3, 4, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 17, 19, 20, - 21, 22, 23, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 27, 28, 28, 29, 30, 31, 32, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 35, 35, 35, - 35, 35, 59, 59, 60, 35, 35, 35, 35, 35, 35, 35, 61, 62, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 63, 64, - 35, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 66, 68, + 25, 25, 25, 27, 28, 28, 29, 30, 31, 32, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 69, 70, 35, 35, 35, 35, 71, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 72, 73, 74, 75, 76, 77, 35, 35, 78, 79, 35, 35, 80, 35, - 81, 82, 83, 84, 17, 85, 86, 87, 35, 35, 25, 25, 25, 25, 25, 25, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 35, 35, 35, 35, 35, 59, 59, 60, 35, + 35, 35, 35, 35, 35, 35, 61, 62, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 63, 64, 35, 65, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 67, 66, 68, 69, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 70, 71, 35, 35, + 35, 35, 72, 35, 35, 35, 35, 35, 35, 35, 35, 35, 73, 74, 75, 76, + 77, 78, 35, 35, 79, 80, 35, 35, 81, 35, 82, 83, 84, 85, 17, 86, + 87, 88, 35, 35, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 88, 25, 25, - 25, 25, 25, 25, 25, 89, 90, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 91, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92, - 35, 35, 35, 35, 35, 35, 25, 93, 35, 35, 35, 35, 35, 35, 35, 35, + 25, 25, 25, 25, 25, 25, 25, 89, 25, 25, 25, 25, 25, 25, 25, 90, + 91, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 93, 35, 35, 35, 35, 35, 35, + 25, 94, 35, 35, 25, 25, 25, 25, 25, 25, 25, 25, 25, 95, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, @@ -2247,653 +2262,663 @@ _hb_ucd_u8[32102] = 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 94, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, + 35, 35, 35, 35, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, - 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, - 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, - 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 4, 4, 4, + 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, + 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, + 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, + 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 0, 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, - 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 0, 3, 2, 3, 0, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, + 2, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 3, 2, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, 37, 37, + 3, 3, 3, 0, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, + 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, + 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, + 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, - 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, - 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, + 95, 95, 2, 2, 95, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, + 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, + 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, + 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, + 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, + 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, - 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, - 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, - 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, - 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, - 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 11, 11, 2, - 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, - 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, - 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, - 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, - 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, - 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, - 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, - 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, - 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, - 2, 2, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, - 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, - 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, - 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, - 22, 2, 2, 2, 22, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, - 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 22, 2, 2, 2, - 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, + 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, + 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, + 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 2, 11, 2, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, + 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, + 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, + 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, + 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, + 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, + 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, + 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, + 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, + 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, + 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, + 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, + 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, + 22, 22, 22, 22, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 23, 23, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, - 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, - 2, 23, 23, 2, 23, 23, 23, 2, 2, 2, 2, 2, 23, 23, 23, 23, - 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 2, 2, - 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, - 2, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 2, 16, 16, 16, 16, - 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, - 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, + 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, + 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, + 23, 2, 2, 2, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, + 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, + 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 2, + 2, 2, 2, 2, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 36, 36, - 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 36, 36, 36, 36, - 36, 36, 36, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, - 36, 2, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, - 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 36, 36, - 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, + 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 2, 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 36, 36, + 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, - 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, + 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, + 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, - 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, + 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, + 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 2, 25, 25, 25, + 25, 25, 25, 2, 2, 2, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, - 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, + 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, + 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2, + 2, 2, 2, 8, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, + 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 2, + 30, 30, 30, 30, 2, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, - 30, 30, 30, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 2, 30, 30, - 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 2, 30, 30, - 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 2, 2, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, + 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 29, 29, + 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, + 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 45, 45, 45, 45, 45, 45, - 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 43, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 31, 31, 31, 31, + 35, 0, 0, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 2, + 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 2, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, - 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, - 28, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 48, 48, 48, + 31, 31, 31, 31, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, + 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, - 52, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, + 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, + 58, 58, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, + 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, + 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 2, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 76, 76, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, - 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 2, 2, 8, 8, 8, 76, 76, 76, 76, - 76, 76, 76, 76, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, - 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, - 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 9, 9, 9, 9, - 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, - 9, 9, 9, 9, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, + 62, 62, 2, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 2, 2, 2, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, + 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, + 2, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, + 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 2, 2, 8, 8, 8, 76, 76, 76, 76, 76, 76, 76, 76, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 6, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, + 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, + 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, - 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, - 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 2, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 1, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 19, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 56, 56, 56, 56, + 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, - 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 30, 30, 30, 30, - 30, 30, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, - 30, 30, 30, 2, 30, 30, 30, 30, 30, 30, 30, 2, 13, 13, 13, 13, + 56, 56, 56, 56, 56, 2, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, + 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, + 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 61, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, - 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 13, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 0, 0, 0, - 0, 0, 0, 0, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 1, 1, 1, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, + 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1, + 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, - 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, + 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 17, 17, 17, 17, - 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, + 12, 12, 12, 12, 12, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, - 39, 39, 39, 2, 2, 2, 2, 2, 2, 2, 2, 2, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, + 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 0, 0, 0, 19, 19, 19, 19, 19, 2, 2, 19, 19, - 19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, + 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, + 0, 19, 19, 19, 19, 19, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, + 60, 60, 60, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 2, 2, + 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, + 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, - 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, + 84, 84, 84, 84, 2, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 30, 30, 30, - 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 30, 30, 30, - 30, 30, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 9, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, - 12, 12, 12, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, - 19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, - 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, - 14, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 3, 3, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, + 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 30, + 30, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, + 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, + 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, + 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, - 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, - 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, + 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, + 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, + 12, 12, 12, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, - 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, + 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, + 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118,118,118, + 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118, 118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, - 118,118,118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, 53, 53, + 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, + 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 2, 2, 2, 2, 2, 2,135,135,135,135, + 50, 50, 50, 50, 2, 2, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135, + 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,135,135, 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, - 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135,135,135, - 135,135,135,135,135,135,135,135, 2, 2, 2, 2,106,106,106,106, - 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, - 106,106,106,106, 2, 2, 2, 2, 2, 2, 2, 2,104,104,104,104, - 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,110,110,110,110, - 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, - 110,110,110, 2, 2, 2, 2, 2, 2, 2, 2, 2,110,110,110,110, - 110,110, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,110,110,110,110, - 110,110,110,110, 2, 2, 2, 2, 2, 2, 2, 2, 47, 47, 47, 47, - 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,106,106, + 106,106,106,106,106,106,106,106,106,106,106,106,106,106, 2, 2, + 2, 2, 2, 2, 2, 2,104,104,104,104,104,104,104,104,104,104, + 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,104,110,110,110,110,110,110,110,110,110,110, + 110,110,110,110,110,110,110,110,110,110,110,110,110, 2, 2, 2, + 2, 2, 2, 2, 2, 2,110,110,110,110,110,110, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,110,110,110,110,110,110,110,110, 2, 2, + 2, 2, 2, 2, 2, 2, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 2, 81, 81, 81, 81, 81, 81, 81, 81, 81,120,120,120,120, - 120,120,120,120,120,120,120,120,120,120,120,120,116,116,116,116, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, + 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81, 81, 81, + 81, 81, 81, 81, 81, 81,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116, 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, - 116,116,116,116,116,116,116,116,116,116,116, 2, 2, 2, 2, 2, - 2, 2, 2,116,116,116,116,116,116,116,116,116,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, 2, - 128,128, 2, 2, 2, 2, 2,128,128,128,128,128, 66, 66, 66, 66, + 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,116,116, + 116,116,116,116,116,116,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2, + 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, + 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, - 2, 57, 57, 2, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, - 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, + 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2, + 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, - 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 2, 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,117,117,117,117, - 117,117,117,117,117,117,117,117,117,117,117,117,112,112,112,112, - 112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, - 112,112,112, 2, 2, 2, 2,112,112,112,112,112,112,112,112,112, - 112,112,112, 2, 2, 2, 2, 2, 2, 2, 2, 2, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 2, 2, 83, 83, 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, - 2, 2, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82,122,122,122,122, - 122,122,122,122,122,122,122,122,122,122,122,122,122,122, 2, 2, - 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2,122,122,122,122,122,122,122, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 2, 2, 2, 2, 2, 2, 2,130,130,130,130, - 130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,130,130,130, 2, - 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144,144,144, - 144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, - 144,144,144,144, 2, 2, 2, 2, 2, 2, 2, 2,144,144,144,144, - 144,144,144,144,144,144, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,147,147,147,147, - 147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, - 147,147,147,147, 2, 2, 2, 2, 2, 2, 2, 2,148,148,148,148, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, + 57, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, + 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,117,117, + 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112, + 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, + 2,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, + 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 83, 83, + 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2, 82, 82, + 82, 82, 82, 82, 82, 82,122,122,122,122,122,122,122,122,122,122, + 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122, + 122,122,122, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,122, + 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2, + 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130, + 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,130,130,130, 2, 2, 2, 2, 2, 2, 2, + 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144, + 144,144,144,144,144,144,144,144,144,144,144,144,144,144, 2, 2, + 2, 2, 2, 2, 2, 2,144,144,144,144,144,144,144,144,144,144, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2,156,156,156,156,156,156,156,156,156,156, + 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, + 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,147,147, + 147,147,147,147,147,147,147,147,147,147,147,147,147,147, 2, 2, + 2, 2, 2, 2, 2, 2,148,148,148,148,148,148,148,148,148,148, 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, - 148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,149,149,149,149, - 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, - 149,149,149, 2, 2, 2, 2, 2, 2, 2, 2, 2, 94, 94, 94, 94, + 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153, + 153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, + 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101,101,101, - 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, - 101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101,101,101, - 101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 2, 2, 2, 2, 2, 2, 2, 2, 2,111,111,111,111, - 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, - 111,111,111, 2, 2, 2, 2, 2, 2, 2, 2, 2,100,100,100,100, - 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, - 100,100,100,100,100,100,100,100,100,100, 2, 2, 2, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,108,108,108,108, - 108,108,108,108,108,108,108,108,108,108,108,108,108,108, 2,108, + 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101,101, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, 2, + 2, 2, 2, 2, 2, 2,101,101,101,101,101,101,101,101,101,101, + 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 2, + 2, 2, 2, 2, 2, 2,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111, 2, 2, 2, + 2, 2, 2, 2, 2, 2,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,108,108,108,108,108,108,108,108,108,108, + 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108, 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, - 108,108,108,108,108,108,108,108,108,108,108, 2,129,129,129,129, - 129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129,129,129, - 129,129,129,129,129,129,129,129,129,129, 2,129,129,129,129,129, - 129,129,129,129,129,129, 2, 2, 2, 2, 2, 2,109,109,109,109, + 108,108,108,108,108, 2,129,129,129,129,129,129,129, 2,129, 2, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, - 109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109,109,109, - 109,109,109,109,109,109, 2, 2, 2, 2, 2, 2,107,107,107,107, - 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2, 2,107, - 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, - 107,107,107,107,107, 2,107,107,107,107,107,107,107, 2,107,107, - 2,107,107,107,107,107, 2, 1,107,107,107,107,107,107,107,107, - 107, 2, 2,107,107, 2, 2,107,107,107, 2, 2,107, 2, 2, 2, - 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107,107,107, - 2, 2,107,107,107,107,107,107,107, 2, 2, 2,107,107,107,107, - 107, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,137,137,137,137, + 109, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, + 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107, + 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2, + 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107, + 2, 1,107,107,107,107,107,107,107,107,107, 2, 2,107,107, 2, + 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, + 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107, + 107,107,107, 2, 2, 2,107,107,107,107,107, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,137,137,137,137,137,137,137,137,137,137, 137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, - 137,137,137,137,137,137, 2,137, 2,137,137,137,124,124,124,124, - 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, - 124,124,124,124, 2, 2, 2, 2, 2, 2, 2, 2,124,124,124,124, - 124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123,123,123, + 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, + 124,124,124,124,124,124,124,124,124,124,124,124,124,124, 2, 2, + 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, + 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123, + 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,123,123, 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, - 123,123, 2, 2,123,123,123,123,123,123,123,123,123,123,123,123, - 123,123,123,123,123,123,123,123,123,123, 2, 2,114,114,114,114, - 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, - 114, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,114,114,114,114, - 114,114,114,114,114,114, 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2,102,102,102,102, - 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, - 102,102,102,102,102, 2, 2, 2, 2, 2, 2, 2,102,102,102,102, - 102,102,102,102,102,102, 2, 2, 2, 2, 2, 2,126,126,126,126, + 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114, + 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,114,114,114,114,114,114,114,114,114,114, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, + 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, 2, + 2, 2, 2, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, + 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126, 126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, - 126,126,126,126,126,126,126, 2, 2,126,126,126,126,126,126,126, - 126,126,126,126,126,126,126,126, 2, 2, 2, 2,142,142,142,142, + 126, 2, 2,126,126,126,126,126,126,126,126,126,126,126,126,126, + 126,126, 2, 2, 2, 2,142,142,142,142,142,142,142,142,142,142, 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, - 142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125,125,125, - 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,150,150,150,150, - 150,150,150,150, 2, 2,150,150,150,150,150,150,150,150,150,150, + 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125, + 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, + 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2, + 2,154,154,154,154,154,154,154,154,154,154,154,154, 2, 2, 2, + 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154,154,154,154, + 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2, 150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, - 150, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,141,141,141,141, - 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, - 141,141,141,141, 2, 2, 2, 2, 2, 2, 2, 2,140,140,140,140, - 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,121,121,121,121, - 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, - 121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2,133,133,133,133, - 133,133,133,133,133, 2,133,133,133,133,133,133,133,133,133,133, + 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,141,141,141,141,141,141,141,141,141,141, + 141,141,141,141,141,141,141,141,141,141,141,141,141,141, 2, 2, + 2, 2, 2, 2, 2, 2,140,140,140,140,140,140,140,140,140,140, + 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121,121, + 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, 2, + 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2, 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, - 133,133,133, 2,133,133,133,133,133,133,133,133,133,133,133,133, - 133,133, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,133,133,133,133, - 133,133,133,133,133,133,133,133,133, 2, 2, 2,134,134,134,134, - 134,134,134,134,134,134,134,134,134,134,134,134, 2, 2,134,134, - 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, - 134,134,134,134, 2,134,134,134,134,134,134,134,134,134,134,134, - 134,134,134, 2, 2, 2, 2, 2, 2, 2, 2, 2,138,138,138,138, - 138,138,138, 2,138,138, 2,138,138,138,138,138,138,138,138,138, - 138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, - 138,138,138, 2, 2, 2,138, 2,138,138, 2,138,138,138,138,138, - 138,138,138,138, 2, 2, 2, 2, 2, 2, 2, 2,138,138,138,138, - 138,138,138,138,138,138, 2, 2, 2, 2, 2, 2,143,143,143,143, - 143,143, 2,143,143, 2,143,143,143,143,143,143,143,143,143,143, + 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133,133, + 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134,134,134,134,134,134,134, 2,134, + 134,134,134,134,134,134,134,134,134,134,134,134,134, 2, 2, 2, + 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138, 2,138,138, + 2,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, + 138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, 2, + 138, 2,138,138, 2,138,138,138,138,138,138,138,138,138, 2, 2, + 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138,138,138,138, + 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2, + 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, - 143,143,143,143,143,143,143,143,143,143,143, 2,143,143, 2,143, - 143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143,143,143, - 143,143,143,143,143,143, 2, 2, 2, 2, 2, 2,145,145,145,145, - 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, - 145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, + 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2, + 2, 2, 2, 2, 2, 2,143,143,143,143,143,143,143,143,143,143, + 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145,145, + 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, 2, + 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, - 63, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 80, 80, 80, 80, + 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 2, 2, 2, 2, 2, 2, 2,127,127,127,127, - 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, - 127,127,127, 2, 2, 2, 2, 2, 2, 2, 2, 2, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 2, 2, 2, 2, 2, 2, 2,115,115,115,115, + 80, 80, 80, 80, 80, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, + 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127, + 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2, + 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115, 115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, - 115,115,115,115,115,115,115,115,115,115,115, 2,115,115,115,115, - 115,115,115,115,115,115, 2, 2, 2, 2,115,115,103,103,103,103, + 115,115,115,115,115, 2,115,115,115,115,115,115,115,115,115,115, + 2, 2, 2, 2,115,115,103,103,103,103,103,103,103,103,103,103, 103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, - 103,103,103,103,103,103,103,103,103,103, 2, 2,103,103,103,103, - 103,103, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,119,119,119,119, - 119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, - 119,119, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,119,119,119,119, - 119,119,119,119,119,119, 2,119,119,119,119,119,119,119, 2,119, - 119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, - 119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146,146,146, + 103,103,103,103, 2, 2,103,103,103,103,103,103, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119, + 2,119,119,119,119,119,119,119, 2,119,119,119,119,119,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119,119,119, 2, 2, + 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146, 146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, - 146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99, 99, 99, + 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 2, 2, 2, 2, 2, 2, 2, 99,136,139, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,136,136,136,136, - 136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, - 136,136,136,136, 2, 2, 2, 2, 2, 2, 2, 2,136,136,136, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 15, 15, 15, + 99, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, + 2, 2, 2, 2, 2, 99,136,139, 0, 0,155, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136,136, + 136,136,136,136,136,136,136,136,136,136,136,136,136,136, 2, 2, + 2, 2, 2, 2, 2, 2,155,155,155,155,155,155,155,155,155,155, + 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136, 2, + 2, 2, 2, 2, 2, 2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 15, 15, 15, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 17, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2, 2,139,139,139,139, + 15, 15, 15, 15, 15, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 2, + 2, 2, 2, 2, 2, 2,139,139,139,139,139,139,139,139,139,139, 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, - 139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105,105,105, + 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, - 105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105,105,105, - 105,105,105,105,105,105,105,105,105, 2, 2, 2,105,105,105,105, - 105,105,105,105,105, 2, 2, 2, 2, 2, 2, 2,105,105,105,105, - 105,105,105,105,105,105, 2, 2,105,105,105,105, 0, 0, 0, 0, - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 9, 9, 9, 9, - 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 2, - 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, - 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,131,131,131,131, + 105, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 105,105,105, 2, 2, 2,105,105,105,105,105,105,105,105,105, 2, + 2, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 2, 2,105,105,105,105, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 9, 9, 9, 9, 9, 9, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 0, 0,131,131,131,131,131,131,131,131,131,131, 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, - 131,131,131,131,131,131,131,131, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,131,131, - 131,131,131,131,131,131,131,131,131,131,131,131, 56, 56, 56, 56, - 56, 56, 56, 2, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, - 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2,151,151,151,151, + 131,131, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2,131,131,131,131,131, 2,131,131,131,131,131,131,131,131,131, + 131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2, + 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56, + 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151, 151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, - 151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151,151,151, - 151,151,151,151,151,151,151,151,151,151, 2, 2,151,151,151,151, - 151,151,151,151,151,151, 2, 2, 2, 2,151,151,152,152,152,152, + 151,151,151, 2, 2, 2,151,151,151,151,151,151,151,151,151,151, + 151,151,151,151, 2, 2,151,151,151,151,151,151,151,151,151,151, + 2, 2, 2, 2,151,151,152,152,152,152,152,152,152,152,152,152, 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, - 152,152,152,152,152,152, 2, 2, 2, 2, 2,152,113,113,113,113, - 113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, - 113, 2, 2,113,113,113,113,113,113,113,113,113,113,113,113,113, - 113,113,113, 2, 2, 2, 2, 2, 2, 2, 2, 2,132,132,132,132, + 2, 2, 2, 2, 2,152,113,113,113,113,113,113,113,113,113,113, + 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, + 113,113,113,113,113,113,113,113,113,113,113,113,113, 2, 2, 2, + 2, 2, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132, 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, - 132,132,132,132,132,132,132,132, 2, 2, 2, 2,132,132,132,132, - 132,132,132,132,132,132, 2, 2, 2, 2,132,132, 0, 0, 0, 0, - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 3, 3, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, - 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, - 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, - 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, 3, 2, - 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, - 3, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, - 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, - 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, - 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, - 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, - 13, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, - 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 13, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 13, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, - 2, 3, 4, 5, 6, 0, 0, 0, 0, 7, 8, 9, 10, 11, 0, 12, - 0, 0, 0, 0, 13, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 16, 0, 17, 18, 19, 0, 0, 0, 20, 21, 22, 0, 23, 0, 24, - 0, 25, 0, 26, 0, 0, 0, 0, 0, 27, 28, 0, 29, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 132,132, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132, + 2, 2, 2, 2,132,132, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, + 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, + 0, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0, + 0, 0, 0, 7, 8, 9, 10, 11, 0, 12, 0, 0, 0, 0, 13, 0, + 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 0, 17, 18, 19, + 0, 0, 0, 20, 21, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 0, + 0, 0, 0, 27, 28, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 0, 0, - 41, 0, 42, 43, 44, 45, 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 52, + 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 0, 0, 0, 41, 0, 42, 43, 44, 45, + 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 50, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2943,14 +2968,15 @@ _hb_ucd_u8[32102] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, - 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, - 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2996,8 +3022,8 @@ _hb_ucd_u8[32102] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 68, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3070,11 +3096,10 @@ _hb_ucd_u8[32102] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 0, + 0, 0, 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 78, 79, 80, 0, }; static const uint16_t -_hb_ucd_u16[11168] = +_hb_ucd_u16[11328] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -3084,186 +3109,188 @@ _hb_ucd_u16[11168] = 13, 13, 13, 42, 9, 43, 11, 11, 44, 45, 32, 46, 47, 48, 49, 50, 51, 52, 48, 48, 53, 32, 54, 55, 48, 48, 48, 48, 48, 56, 57, 58, 59, 60, 48, 32, 61, 48, 48, 48, 48, 48, 62, 63, 64, 48, 65, 66, - 48, 67, 68, 69, 48, 70, 71, 72, 72, 72, 48, 73, 72, 74, 75, 32, - 76, 48, 48, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 83, 84, 91, 92, 93, 94, 95, 96, 97, 84, 98, 99, 100, 88, 101, - 102, 83, 84, 103, 104, 105, 88, 106, 107, 108, 109, 110, 111, 112, 94, 113, - 114, 115, 84, 116, 117, 118, 88, 119, 120, 115, 84, 121, 122, 123, 88, 124, - 125, 115, 48, 126, 127, 128, 88, 129, 130, 131, 48, 132, 133, 134, 94, 135, - 136, 48, 48, 137, 138, 139, 72, 72, 140, 48, 141, 142, 143, 144, 72, 72, - 145, 146, 147, 148, 149, 48, 150, 151, 152, 153, 32, 154, 155, 156, 72, 72, - 48, 48, 157, 158, 159, 160, 161, 162, 163, 164, 9, 9, 165, 11, 11, 166, + 48, 67, 68, 69, 48, 70, 71, 72, 72, 72, 48, 73, 74, 75, 76, 32, + 77, 48, 48, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 84, 85, 92, 93, 94, 95, 96, 97, 98, 85, 99, 100, 101, 89, 102, + 103, 84, 85, 104, 105, 106, 89, 107, 108, 109, 110, 111, 112, 113, 95, 114, + 115, 116, 85, 117, 118, 119, 89, 120, 121, 116, 85, 122, 123, 124, 89, 125, + 126, 116, 48, 127, 128, 129, 89, 130, 131, 132, 48, 133, 134, 135, 95, 136, + 137, 48, 48, 138, 139, 140, 72, 72, 141, 48, 142, 143, 144, 145, 72, 72, + 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 72, 72, + 48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 167, 168, 48, 48, 167, 48, 48, 169, 170, 171, 48, 48, - 48, 170, 48, 48, 48, 172, 173, 174, 48, 175, 9, 9, 9, 9, 9, 176, - 177, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 168, 169, 48, 48, 168, 48, 48, 170, 171, 172, 48, 48, + 48, 171, 48, 48, 48, 173, 174, 175, 48, 176, 9, 9, 9, 9, 9, 177, + 178, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 178, 48, 179, 180, 48, 48, 48, 48, 181, 182, - 183, 184, 48, 185, 48, 186, 183, 187, 48, 48, 48, 188, 189, 190, 191, 192, - 193, 191, 48, 48, 194, 48, 48, 195, 196, 48, 197, 48, 48, 48, 48, 198, - 48, 199, 200, 201, 202, 48, 203, 204, 48, 48, 205, 48, 206, 207, 208, 208, - 48, 209, 48, 48, 48, 210, 211, 212, 191, 191, 213, 214, 72, 72, 72, 72, - 215, 48, 48, 216, 217, 159, 218, 219, 220, 48, 221, 64, 48, 48, 222, 223, - 48, 48, 224, 225, 226, 64, 48, 227, 228, 9, 9, 229, 230, 231, 232, 233, - 11, 11, 234, 27, 27, 27, 235, 236, 11, 237, 27, 27, 32, 32, 32, 238, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 239, 13, 13, 13, 13, 13, 13, - 240, 241, 240, 240, 241, 242, 240, 243, 244, 244, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260, 72, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 270, 271, 272, 273, 208, 274, 275, 208, 276, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 278, 208, 279, 208, 208, 208, 208, 280, 208, 281, 277, 282, 208, 283, 284, 208, - 208, 208, 285, 72, 286, 72, 269, 269, 269, 287, 208, 208, 208, 208, 288, 269, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 289, 290, 208, 208, 291, - 208, 208, 208, 208, 208, 208, 292, 208, 208, 208, 208, 208, 208, 208, 208, 208, - 208, 208, 208, 208, 208, 208, 293, 294, 269, 295, 208, 208, 296, 277, 297, 277, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, - 277, 277, 277, 277, 277, 277, 277, 277, 298, 299, 277, 277, 277, 300, 277, 301, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 208, 208, 208, 277, 302, 208, 208, 303, 208, 304, 208, 208, 208, 208, 208, 208, - 9, 9, 305, 11, 11, 306, 307, 308, 13, 13, 13, 13, 13, 13, 309, 310, - 11, 11, 311, 48, 48, 48, 312, 313, 48, 314, 315, 315, 315, 315, 32, 32, - 316, 317, 318, 319, 320, 72, 72, 72, 208, 321, 208, 208, 208, 208, 208, 322, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323, 72, 324, - 325, 326, 327, 328, 136, 48, 48, 48, 48, 329, 177, 48, 48, 48, 48, 330, - 331, 48, 48, 136, 48, 48, 48, 48, 199, 332, 48, 71, 208, 208, 322, 48, - 208, 333, 334, 208, 335, 336, 208, 208, 334, 208, 208, 336, 208, 208, 208, 208, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183, + 184, 185, 48, 186, 48, 187, 184, 188, 48, 48, 48, 189, 190, 191, 192, 193, + 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199, + 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209, + 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 72, 72, 72, + 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225, + 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235, + 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 240, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 241, 13, 13, 13, 13, 13, 13, + 242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262, 72, 263, 264, 216, + 265, 266, 267, 268, 269, 270, 271, 271, 272, 273, 274, 209, 275, 276, 209, 277, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 209, 280, 209, 209, 209, 209, 281, 209, 282, 278, 283, 209, 284, 285, 209, + 209, 209, 286, 72, 287, 72, 270, 270, 270, 288, 209, 209, 209, 209, 289, 270, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 290, 291, 209, 209, 292, + 209, 209, 209, 209, 209, 209, 293, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 294, 295, 270, 296, 209, 209, 297, 278, 298, 278, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 278, 278, 278, 278, 278, 278, 278, 278, 299, 300, 278, 278, 278, 301, 278, 302, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 209, 209, 209, 278, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209, + 9, 9, 306, 11, 11, 307, 308, 309, 13, 13, 13, 13, 13, 13, 310, 311, + 11, 11, 312, 48, 48, 48, 313, 314, 48, 315, 316, 316, 316, 316, 32, 32, + 317, 318, 319, 320, 321, 322, 72, 72, 209, 323, 209, 209, 209, 209, 209, 324, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 325, 72, 326, + 327, 328, 329, 330, 137, 48, 48, 48, 48, 331, 178, 48, 48, 48, 48, 332, + 333, 48, 48, 137, 48, 48, 48, 48, 200, 334, 48, 48, 209, 209, 324, 48, + 209, 335, 336, 209, 337, 338, 209, 209, 336, 209, 209, 338, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 198, 208, 208, 208, 208, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 72, - 48, 337, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 151, + 48, 339, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 150, 208, 208, 208, 285, 48, 48, 227, + 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 286, 48, 48, 229, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 338, 48, 339, 72, 13, 13, 340, 341, 13, 342, 48, 48, 48, 48, 343, 344, - 31, 345, 346, 347, 13, 13, 13, 348, 349, 350, 351, 352, 353, 72, 72, 354, - 355, 48, 356, 357, 48, 48, 48, 358, 359, 48, 48, 360, 361, 191, 32, 362, - 64, 48, 363, 48, 364, 365, 48, 150, 76, 48, 48, 366, 367, 368, 369, 370, - 48, 48, 371, 372, 373, 374, 48, 375, 48, 48, 48, 376, 377, 378, 379, 380, - 381, 382, 315, 11, 11, 383, 384, 11, 11, 11, 11, 11, 48, 48, 385, 191, + 340, 48, 341, 72, 13, 13, 342, 343, 13, 344, 48, 48, 48, 48, 345, 346, + 31, 347, 348, 349, 13, 13, 13, 350, 351, 352, 353, 354, 355, 72, 72, 356, + 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364, + 64, 48, 365, 48, 366, 367, 48, 151, 77, 48, 48, 368, 369, 370, 371, 372, + 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382, + 383, 384, 316, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 386, 48, 387, 48, 48, 205, - 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, - 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, 388, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 388, 48, 389, 48, 48, 206, + 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, + 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 203, 48, 48, 48, 48, 48, 48, 206, 72, 72, - 390, 391, 392, 393, 394, 48, 48, 48, 48, 48, 48, 395, 396, 397, 48, 48, + 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 72, 72, + 392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 398, 72, 48, 48, 48, 48, 399, 48, 48, 400, 72, 72, 401, - 32, 402, 32, 403, 404, 405, 406, 407, 48, 48, 48, 48, 48, 48, 48, 408, - 409, 2, 3, 4, 5, 410, 411, 412, 48, 413, 48, 199, 414, 415, 416, 417, - 418, 48, 171, 419, 203, 203, 72, 72, 48, 48, 48, 48, 48, 48, 48, 71, - 420, 269, 269, 421, 270, 270, 270, 422, 423, 324, 424, 72, 72, 208, 208, 425, - 72, 72, 72, 72, 72, 72, 72, 72, 48, 150, 48, 48, 48, 100, 426, 427, - 48, 48, 428, 48, 429, 48, 48, 430, 48, 431, 48, 48, 432, 433, 72, 72, - 9, 9, 434, 11, 11, 48, 48, 48, 48, 203, 191, 9, 9, 435, 11, 436, - 48, 48, 400, 48, 48, 48, 437, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 400, 72, 48, 48, 48, 48, 401, 48, 48, 74, 72, 72, 402, + 32, 403, 32, 404, 405, 406, 407, 73, 48, 48, 48, 48, 48, 48, 48, 408, + 409, 2, 3, 4, 5, 410, 411, 412, 48, 413, 48, 200, 414, 415, 416, 417, + 418, 48, 172, 419, 204, 204, 72, 72, 48, 48, 48, 48, 48, 48, 48, 71, + 420, 270, 270, 421, 271, 271, 271, 422, 423, 424, 425, 72, 72, 209, 209, 426, + 72, 72, 72, 72, 72, 72, 72, 72, 48, 151, 48, 48, 48, 101, 427, 428, + 48, 48, 429, 48, 430, 48, 48, 431, 48, 432, 48, 48, 433, 434, 72, 72, + 9, 9, 435, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 436, 11, 437, + 48, 48, 74, 48, 48, 48, 438, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 314, 48, 198, 400, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 438, 48, 48, 439, 48, 440, 48, 441, 48, 199, 442, 72, 72, 72, 48, 443, - 48, 444, 48, 445, 72, 72, 72, 72, 48, 48, 48, 446, 269, 447, 269, 269, - 448, 449, 48, 450, 451, 452, 48, 453, 48, 454, 72, 72, 455, 48, 456, 457, - 48, 48, 48, 458, 48, 459, 48, 460, 48, 461, 462, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 195, 72, 72, 72, 9, 9, 9, 463, 11, 11, 11, 464, - 48, 48, 465, 191, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 269, 466, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 454, 467, 48, 62, 468, 72, 72, 72, 72, 72, 72, 72, 72, 48, 314, - 469, 48, 48, 470, 471, 447, 472, 473, 220, 48, 48, 474, 475, 48, 195, 191, - 476, 48, 477, 478, 479, 48, 48, 480, 220, 48, 48, 481, 482, 483, 484, 485, - 48, 97, 486, 487, 72, 72, 72, 72, 488, 489, 490, 48, 48, 491, 492, 191, - 493, 83, 84, 494, 495, 496, 497, 498, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 499, 500, 501, 72, 72, 48, 48, 48, 502, 503, 191, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 504, 505, 506, 507, 72, 72, - 48, 48, 48, 508, 509, 191, 510, 72, 48, 48, 511, 512, 191, 72, 72, 72, - 48, 172, 513, 514, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 486, 515, 72, 72, 72, 72, 72, 72, 9, 9, 11, 11, 147, 516, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 517, 48, 48, 518, 519, 72, - 520, 48, 48, 521, 522, 523, 48, 48, 524, 525, 526, 72, 48, 48, 48, 195, + 48, 48, 48, 315, 48, 199, 74, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 439, 48, 48, 440, 48, 441, 48, 442, 48, 200, 443, 72, 72, 72, 48, 444, + 48, 445, 48, 446, 72, 72, 72, 72, 48, 48, 48, 447, 270, 448, 270, 270, + 449, 450, 48, 451, 452, 453, 48, 454, 48, 455, 72, 72, 456, 48, 457, 458, + 48, 48, 48, 459, 48, 460, 48, 461, 48, 462, 463, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 196, 72, 72, 72, 9, 9, 9, 464, 11, 11, 11, 465, + 48, 48, 466, 192, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 270, 467, 48, 48, 468, 469, 72, 72, 72, 72, + 48, 455, 470, 48, 62, 471, 72, 72, 72, 72, 72, 48, 472, 72, 48, 315, + 473, 48, 48, 474, 475, 448, 476, 477, 222, 48, 48, 478, 479, 48, 196, 192, + 480, 48, 481, 482, 483, 48, 48, 484, 222, 48, 48, 485, 486, 487, 488, 489, + 48, 98, 490, 491, 72, 72, 72, 72, 492, 493, 494, 48, 48, 495, 496, 192, + 497, 84, 85, 498, 499, 500, 501, 502, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 503, 504, 505, 469, 72, 48, 48, 48, 506, 507, 192, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 508, 509, 510, 511, 72, 72, + 48, 48, 48, 512, 513, 192, 514, 72, 48, 48, 515, 516, 192, 72, 72, 72, + 48, 173, 517, 518, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 490, 519, 72, 72, 72, 72, 72, 72, 9, 9, 11, 11, 148, 520, + 521, 522, 48, 523, 524, 192, 72, 72, 72, 72, 525, 48, 48, 526, 527, 72, + 528, 48, 48, 529, 530, 531, 48, 48, 532, 533, 534, 72, 48, 48, 48, 196, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 84, 48, 504, 527, 528, 147, 174, 529, 48, 530, 531, 532, 72, 72, 72, 72, - 533, 48, 48, 534, 535, 191, 536, 48, 537, 538, 191, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 539, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 269, 540, 541, 542, + 85, 48, 508, 535, 536, 148, 175, 537, 48, 538, 539, 540, 72, 72, 72, 72, + 541, 48, 48, 542, 543, 192, 544, 48, 545, 546, 192, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 547, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 101, 270, 548, 549, 550, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 206, 72, 72, 72, 72, 72, 72, - 270, 270, 270, 270, 270, 270, 543, 544, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 386, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 207, 72, 72, 72, 72, 72, 72, + 271, 271, 271, 271, 271, 271, 551, 552, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 388, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 199, 545, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 200, 553, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 314, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 315, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 195, 48, 199, 368, 72, 72, 72, 72, 72, 72, 48, 203, 546, - 48, 48, 48, 547, 548, 549, 550, 551, 48, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 9, 9, 11, 11, 269, 552, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 553, 554, 555, 555, 556, 557, 72, 72, 72, 72, 558, 72, + 48, 48, 48, 196, 48, 200, 370, 72, 72, 72, 72, 72, 72, 48, 204, 554, + 48, 48, 48, 555, 556, 557, 558, 559, 48, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 9, 9, 11, 11, 270, 560, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 561, 562, 563, 563, 564, 565, 72, 72, 72, 72, 566, 567, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 400, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 559, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 74, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 72, 72, + 196, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 199, 72, 72, 72, 559, 560, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 205, + 48, 200, 72, 72, 72, 568, 569, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 206, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 48, 48, 71, 150, 195, 561, 562, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 71, 151, 196, 570, 571, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323, - 208, 208, 563, 208, 208, 208, 564, 565, 566, 208, 567, 208, 208, 208, 568, 72, - 208, 208, 208, 208, 569, 72, 72, 72, 72, 72, 72, 72, 72, 72, 269, 570, - 208, 208, 208, 208, 208, 285, 269, 451, 72, 72, 72, 72, 72, 72, 72, 72, - 9, 571, 11, 572, 573, 574, 240, 9, 575, 576, 577, 578, 579, 9, 571, 11, - 580, 581, 11, 582, 583, 584, 585, 9, 586, 11, 9, 571, 11, 572, 573, 11, - 240, 9, 575, 585, 9, 586, 11, 9, 571, 11, 587, 9, 588, 589, 590, 591, - 11, 592, 9, 593, 594, 595, 596, 11, 597, 9, 598, 11, 599, 600, 600, 600, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, - 32, 32, 32, 601, 32, 32, 602, 603, 604, 605, 45, 72, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 325, + 209, 209, 572, 209, 209, 209, 573, 574, 575, 209, 576, 209, 209, 209, 577, 72, + 209, 209, 209, 209, 578, 72, 72, 72, 72, 72, 72, 72, 72, 72, 270, 579, + 209, 209, 209, 209, 209, 286, 270, 452, 72, 72, 72, 72, 72, 72, 72, 72, + 9, 580, 11, 581, 582, 583, 242, 9, 584, 585, 586, 587, 588, 9, 580, 11, + 589, 590, 11, 591, 592, 593, 594, 9, 595, 11, 9, 580, 11, 581, 582, 11, + 242, 9, 584, 594, 9, 595, 11, 9, 580, 11, 596, 9, 597, 598, 599, 600, + 11, 601, 9, 602, 603, 604, 605, 11, 606, 9, 607, 11, 608, 609, 609, 609, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 32, 32, 32, 610, 32, 32, 611, 612, 613, 614, 45, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 606, 607, 608, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 150, 609, 610, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 611, 612, + 615, 616, 617, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 151, 618, 619, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 620, 621, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 613, 614, 72, 72, - 9, 9, 575, 11, 615, 368, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 484, 269, 269, 616, 617, 72, 72, 72, 72, - 484, 269, 618, 619, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 620, 48, 621, 622, 623, 624, 625, 626, 627, 205, 628, 205, 72, 72, 72, 629, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 622, 623, 72, 72, + 9, 9, 584, 11, 624, 370, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 488, 270, 270, 625, 626, 72, 72, 72, 72, + 488, 270, 627, 628, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 629, 48, 630, 631, 632, 633, 634, 635, 636, 206, 637, 206, 72, 72, 72, 638, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 208, 208, 324, 208, 208, 208, 208, 208, 208, 322, 333, 630, 630, 630, 208, 323, - 174, 208, 208, 208, 208, 208, 631, 208, 208, 208, 631, 72, 72, 72, 632, 208, - 633, 208, 208, 324, 568, 634, 323, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 635, - 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 323, 631, 286, - 208, 208, 208, 208, 208, 208, 208, 322, 208, 208, 208, 208, 208, 568, 324, 72, - 324, 208, 208, 208, 636, 175, 208, 208, 636, 208, 637, 72, 72, 72, 72, 72, - 638, 208, 208, 208, 208, 208, 208, 639, 208, 208, 640, 208, 641, 208, 208, 208, - 208, 208, 208, 208, 208, 322, 637, 642, 633, 323, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 314, 72, 72, + 209, 209, 326, 209, 209, 209, 209, 209, 209, 324, 335, 639, 639, 639, 209, 325, + 640, 209, 209, 209, 209, 209, 209, 209, 209, 209, 641, 72, 72, 72, 642, 209, + 643, 209, 209, 326, 577, 644, 325, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 645, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 646, 424, 424, + 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 577, 326, 72, + 326, 209, 209, 209, 646, 176, 209, 209, 646, 209, 641, 644, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 647, 209, 209, 209, 209, 648, 209, 209, 209, + 209, 209, 209, 209, 209, 324, 641, 649, 286, 209, 577, 286, 643, 286, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 650, 209, 209, 287, 72, 72, 192, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 72, 72, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 203, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 205, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 643, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 469, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 72, - 48, 203, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 101, 72, + 48, 204, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, - 644, 72, 645, 645, 645, 645, 645, 645, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 71, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 651, 72, 652, 652, 652, 652, 652, 652, 72, 72, 72, 72, 72, 72, 72, 72, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 72, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 646, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, - 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 389, 647, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 653, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 654, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, @@ -3272,31 +3299,31 @@ _hb_ucd_u16[11168] = 14, 14, 14, 16, 17, 18, 17, 17, 19, 20, 21, 21, 22, 21, 23, 24, 25, 26, 27, 27, 28, 29, 27, 30, 27, 27, 27, 27, 27, 31, 27, 27, 32, 33, 33, 33, 34, 27, 27, 27, 35, 35, 35, 36, 37, 37, 37, 38, - 39, 39, 40, 41, 42, 43, 44, 45, 45, 45, 27, 46, 45, 47, 48, 27, - 49, 49, 49, 49, 49, 50, 51, 49, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 110, 111, 112, 113, 110, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 123, 124, 123, 125, 45, 45, 126, 127, 128, 129, 130, 131, 45, 45, - 132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137, 45, 45, - 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143, - 143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153, - 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, - 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, - 154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170, - 171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176, - 177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168, - 188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 195, 45, 45, 45, 45, - 196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201, - 202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211, - 4, 4, 212, 4, 4, 213, 214, 215, 4, 4, 4, 216, 8, 8, 8, 217, + 39, 39, 40, 41, 42, 43, 44, 45, 45, 45, 27, 46, 47, 48, 49, 27, + 50, 50, 50, 50, 50, 51, 52, 50, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 111, 112, 113, 114, 111, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 124, 125, 124, 126, 45, 45, 127, 128, 129, 130, 131, 132, 45, 45, + 133, 133, 133, 133, 134, 133, 135, 136, 133, 134, 133, 137, 137, 138, 45, 45, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, 141, 140, 140, 142, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 144, 144, 144, 144, 145, 146, 144, 144, 145, 144, 144, 147, 148, 149, 144, 144, + 144, 148, 144, 144, 144, 150, 144, 151, 144, 152, 153, 153, 153, 153, 153, 154, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 156, 157, 158, 158, 158, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, 169, 169, 169, 170, 171, 171, + 172, 173, 174, 174, 174, 174, 174, 175, 174, 174, 176, 155, 155, 155, 155, 177, + 178, 179, 180, 180, 181, 182, 183, 184, 185, 185, 186, 185, 187, 188, 169, 169, + 189, 190, 191, 191, 191, 192, 191, 193, 194, 194, 195, 8, 196, 45, 45, 45, + 197, 197, 197, 197, 198, 197, 197, 199, 200, 200, 200, 200, 201, 201, 201, 202, + 203, 203, 203, 204, 205, 206, 206, 206, 207, 140, 140, 208, 209, 210, 211, 212, + 4, 4, 213, 4, 4, 214, 215, 216, 4, 4, 4, 217, 8, 8, 8, 218, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 11, 218, 11, 11, 218, 219, 11, 220, 11, 11, 11, 221, 221, 222, 11, 223, - 224, 0, 0, 0, 0, 0, 225, 226, 227, 228, 0, 0, 45, 8, 8, 229, + 11, 219, 11, 11, 219, 220, 11, 221, 11, 11, 11, 222, 222, 223, 11, 224, + 225, 0, 0, 0, 0, 0, 226, 227, 228, 229, 0, 0, 45, 8, 8, 196, 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3307,46 +3334,46 @@ _hb_ucd_u16[11168] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 237, 0, 238, 0, 0, 0, 0, 0, 0, 239, 239, 240, 239, 239, 240, 4, 4, 241, 241, 241, 241, 241, 241, 241, 242, - 139, 139, 140, 243, 243, 243, 244, 245, 143, 246, 247, 247, 247, 247, 14, 14, - 0, 0, 0, 0, 0, 45, 45, 45, 248, 249, 248, 248, 248, 248, 248, 250, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 45, 252, - 253, 0, 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 260, 260, 261, - 262, 263, 263, 264, 142, 142, 142, 142, 265, 0, 263, 266, 0, 0, 267, 260, - 142, 265, 0, 0, 0, 0, 142, 268, 0, 0, 0, 0, 0, 260, 260, 269, - 260, 260, 260, 260, 260, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 0, 0, 0, 0, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 45, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, 271, - 271, 271, 271, 271, 271, 271, 271, 271, 272, 271, 271, 271, 273, 274, 274, 274, - 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, 275, - 275, 275, 276, 45, 14, 14, 14, 14, 14, 14, 277, 277, 277, 277, 277, 278, - 0, 0, 279, 4, 4, 4, 4, 4, 280, 4, 4, 4, 281, 45, 45, 282, - 283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290, 49, 49, - 291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299, - 300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308, - 309, 310, 247, 4, 4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 315, 142, 316, 142, 142, 317, + 140, 140, 141, 243, 243, 243, 244, 245, 144, 246, 247, 247, 247, 247, 14, 14, + 0, 0, 0, 0, 0, 248, 45, 45, 249, 250, 249, 249, 249, 249, 249, 251, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 252, 45, 253, + 254, 0, 255, 256, 257, 258, 258, 258, 258, 259, 260, 261, 261, 261, 261, 262, + 263, 264, 264, 265, 143, 143, 143, 143, 266, 0, 264, 264, 0, 0, 267, 261, + 143, 266, 0, 0, 0, 0, 143, 268, 0, 0, 0, 0, 0, 261, 261, 269, + 261, 261, 261, 261, 261, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 0, 0, 0, 0, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 271, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 273, 272, 272, 272, 274, 275, 275, 275, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 277, 45, 14, 14, 14, 14, 14, 14, 278, 278, 278, 278, 278, 279, + 0, 0, 280, 4, 4, 4, 4, 4, 281, 4, 4, 4, 282, 45, 45, 283, + 284, 284, 285, 286, 287, 287, 287, 288, 289, 289, 289, 289, 290, 291, 50, 50, + 292, 292, 293, 294, 294, 295, 143, 296, 297, 297, 297, 297, 298, 299, 139, 300, + 301, 301, 301, 302, 303, 304, 139, 139, 305, 305, 305, 305, 306, 307, 308, 309, + 310, 311, 247, 4, 4, 312, 313, 153, 153, 153, 153, 153, 308, 308, 314, 315, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 316, 143, 317, 143, 143, 318, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 45, 45, - 320, 321, 21, 322, 323, 27, 27, 27, 27, 27, 27, 27, 324, 47, 27, 27, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 319, 249, 249, 249, 249, 249, 249, 320, 45, 45, + 321, 322, 21, 323, 324, 27, 27, 27, 27, 27, 27, 27, 325, 48, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 325, 45, 27, 27, 27, 27, 326, 27, 27, 327, 45, 45, 328, - 8, 285, 329, 0, 0, 330, 331, 332, 27, 27, 27, 27, 27, 27, 27, 333, - 334, 0, 1, 2, 1, 2, 335, 259, 260, 336, 142, 265, 337, 338, 339, 340, - 341, 342, 343, 344, 345, 345, 45, 45, 342, 342, 342, 342, 342, 342, 342, 346, - 347, 0, 0, 348, 11, 11, 11, 11, 349, 252, 350, 45, 45, 0, 0, 351, - 45, 45, 45, 45, 45, 45, 45, 45, 352, 353, 354, 354, 354, 355, 356, 252, + 27, 27, 27, 326, 45, 27, 27, 27, 27, 327, 27, 27, 47, 45, 45, 328, + 8, 286, 329, 0, 0, 330, 331, 46, 27, 27, 27, 27, 27, 27, 27, 332, + 333, 0, 1, 2, 1, 2, 334, 260, 261, 335, 143, 266, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 344, 45, 45, 341, 341, 341, 341, 341, 341, 341, 345, + 346, 0, 0, 347, 11, 11, 11, 11, 348, 349, 350, 45, 45, 0, 0, 351, + 45, 45, 45, 45, 45, 45, 45, 45, 352, 353, 354, 354, 354, 355, 356, 253, 357, 357, 358, 359, 360, 361, 361, 362, 363, 364, 365, 365, 366, 367, 45, 45, 368, 368, 368, 368, 368, 369, 369, 369, 370, 371, 372, 373, 373, 374, 373, 375, 376, 376, 377, 378, 378, 378, 379, 45, 45, 45, 45, 45, 45, 45, 45, 45, @@ -3358,101 +3385,105 @@ _hb_ucd_u16[11168] = 413, 413, 413, 414, 415, 416, 417, 418, 419, 420, 421, 45, 45, 45, 45, 45, 422, 422, 422, 422, 423, 45, 45, 45, 424, 424, 424, 425, 424, 424, 424, 426, 427, 427, 428, 429, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 27, 430, 45, 45, 45, 45, 45, 45, 45, 45, - 431, 431, 432, 433, 433, 434, 45, 45, 45, 45, 45, 45, 45, 45, 435, 436, - 437, 437, 437, 437, 438, 439, 437, 440, 441, 441, 441, 441, 442, 443, 444, 445, - 446, 446, 446, 447, 448, 449, 449, 450, 451, 451, 451, 451, 452, 451, 453, 454, - 455, 456, 455, 457, 45, 45, 45, 45, 458, 459, 460, 461, 461, 461, 462, 463, - 464, 465, 466, 467, 468, 469, 470, 471, 45, 45, 45, 45, 45, 45, 45, 45, - 472, 472, 472, 472, 472, 473, 45, 45, 474, 474, 474, 474, 475, 476, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 477, 477, 477, 478, 477, 479, 45, 45, - 480, 480, 480, 480, 481, 482, 483, 45, 484, 484, 484, 485, 486, 45, 45, 45, - 487, 488, 489, 487, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 490, 490, 490, 491, 45, 45, 45, 45, 45, 45, 492, 492, 492, 492, 492, 493, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 494, 495, 495, 494, 496, 45, - 497, 497, 497, 497, 498, 499, 499, 499, 499, 499, 500, 45, 501, 501, 501, 502, + 45, 45, 45, 45, 45, 45, 27, 430, 431, 431, 432, 433, 45, 45, 45, 45, + 434, 434, 435, 436, 436, 437, 45, 45, 45, 45, 45, 438, 439, 45, 440, 441, + 442, 442, 442, 442, 443, 444, 442, 445, 446, 446, 446, 446, 447, 448, 449, 450, + 451, 451, 451, 452, 453, 454, 454, 455, 456, 456, 456, 456, 456, 456, 457, 458, + 459, 460, 459, 461, 45, 45, 45, 45, 462, 463, 464, 465, 465, 465, 466, 467, + 468, 469, 470, 471, 472, 473, 474, 475, 45, 45, 45, 45, 45, 45, 45, 45, + 476, 476, 476, 476, 476, 477, 478, 45, 479, 479, 479, 479, 480, 481, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 482, 482, 482, 483, 482, 484, 45, 45, + 485, 485, 485, 485, 486, 487, 488, 45, 489, 489, 489, 490, 491, 45, 45, 45, + 492, 493, 494, 492, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 495, 495, 495, 496, 45, 45, 45, 45, 45, 45, 497, 497, 497, 497, 497, 498, + 499, 500, 501, 502, 503, 504, 45, 45, 45, 45, 505, 506, 506, 505, 507, 45, + 508, 508, 508, 508, 509, 510, 510, 510, 510, 510, 511, 45, 512, 512, 512, 513, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 503, 504, 504, 505, 506, 504, 507, 508, 508, 509, 510, 511, 45, 45, 45, 45, - 512, 513, 513, 514, 515, 516, 517, 518, 519, 520, 521, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 522, 523, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 524, 524, 524, 525, - 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, - 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, - 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, - 526, 526, 526, 526, 526, 526, 526, 526, 526, 527, 45, 45, 45, 45, 45, 45, - 526, 526, 526, 526, 526, 526, 528, 529, 526, 526, 526, 526, 526, 526, 526, 526, - 526, 526, 526, 526, 530, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, - 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, 531, - 531, 531, 532, 533, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, - 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, 534, - 534, 534, 534, 534, 535, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 277, 277, 277, 536, 537, 538, 539, 45, 45, 45, 45, 45, 45, 540, 541, 542, - 543, 543, 543, 543, 544, 545, 546, 547, 543, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 548, 548, 548, 548, 548, 549, 45, 45, 45, 45, 45, 45, - 550, 550, 550, 550, 551, 550, 550, 550, 552, 550, 45, 45, 45, 45, 553, 45, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 556, + 514, 515, 515, 516, 517, 515, 518, 519, 519, 520, 521, 522, 45, 45, 45, 45, + 523, 524, 524, 525, 526, 527, 528, 529, 530, 531, 532, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 533, 534, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 535, 536, 536, 536, 537, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 539, 45, 45, 45, 45, 45, 45, + 538, 538, 538, 538, 538, 538, 540, 541, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 542, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, + 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, + 543, 543, 544, 545, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 557, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, - 257, 558, 45, 45, 45, 559, 560, 561, 561, 561, 561, 561, 561, 561, 561, 561, - 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 562, + 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, + 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, + 546, 546, 546, 546, 547, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 563, 563, 563, 563, 563, 563, 564, 565, 566, 567, 267, 45, 45, 45, 45, 45, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 548, 549, 550, 551, 45, 45, 45, 45, 45, 45, 552, 553, 554, + 555, 555, 555, 555, 556, 557, 558, 559, 555, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 560, 560, 560, 560, 560, 561, 45, 45, 45, 45, 45, 45, + 562, 562, 562, 562, 563, 562, 562, 562, 564, 562, 45, 45, 45, 45, 565, 566, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 568, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, + 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 570, 45, 45, + 571, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 572, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, + 258, 573, 45, 45, 45, 574, 575, 576, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 577, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 568, - 0, 0, 569, 0, 0, 0, 570, 571, 572, 0, 573, 0, 0, 0, 574, 45, - 11, 11, 11, 11, 575, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 267, - 0, 0, 0, 0, 0, 234, 0, 574, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 0, 0, 0, 225, 0, 0, 0, 576, 577, 578, 579, 0, 0, 0, - 580, 581, 0, 582, 583, 584, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 585, 0, 0, 0, - 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, - 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, - 586, 586, 586, 586, 586, 586, 586, 586, 587, 588, 589, 45, 45, 45, 45, 45, + 578, 578, 578, 578, 578, 578, 579, 580, 581, 582, 267, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 590, 591, 592, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 593, 593, 594, 595, 596, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 597, 597, 597, 598, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 583, + 0, 0, 584, 0, 0, 0, 585, 586, 587, 0, 588, 0, 0, 0, 589, 45, + 11, 11, 11, 11, 590, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 267, + 0, 0, 0, 0, 0, 234, 0, 589, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 226, 0, 0, 0, 591, 592, 593, 594, 0, 0, 0, + 595, 596, 0, 597, 598, 599, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 600, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 601, 0, 0, 0, + 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 602, 603, 604, 605, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 600, 601, 45, 45, - 602, 602, 602, 602, 603, 604, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 334, 0, 0, 0, 605, 45, 45, 45, 45, - 334, 0, 0, 606, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 607, 27, 608, 609, 610, 611, 612, 613, 614, 615, 616, 615, 45, 45, 45, 324, + 606, 607, 608, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 609, 609, 610, 611, 612, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 613, 613, 613, 614, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 252, 0, 0, 0, 0, 0, 0, 267, 227, 334, 334, 334, 0, 568, - 617, 0, 0, 0, 0, 0, 617, 0, 0, 0, 617, 45, 45, 45, 618, 0, - 619, 0, 0, 252, 574, 620, 568, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 568, 617, 235, - 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 574, 252, 45, - 252, 0, 0, 0, 621, 285, 0, 0, 621, 0, 606, 45, 45, 45, 45, 45, - 622, 0, 0, 0, 0, 0, 0, 623, 0, 0, 624, 0, 625, 0, 0, 0, - 0, 0, 0, 0, 0, 267, 606, 626, 627, 568, 45, 45, 45, 45, 45, 45, + 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 616, 617, 45, 45, + 618, 618, 618, 618, 619, 620, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 333, 0, 0, 0, 621, 45, 45, 45, 45, + 333, 0, 0, 622, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 623, 27, 624, 625, 626, 627, 628, 629, 630, 631, 632, 631, 45, 45, 45, 325, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 628, 45, 45, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 629, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 630, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, - 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 631, 45, - 248, 318, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 253, 0, 0, 0, 0, 0, 0, 267, 228, 333, 333, 333, 0, 583, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 622, 45, 45, 45, 633, 0, + 634, 0, 0, 253, 589, 635, 583, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 636, 349, 349, + 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 589, 253, 45, + 253, 0, 0, 0, 636, 286, 0, 0, 636, 0, 622, 635, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 637, 0, 0, 0, 0, 638, 0, 0, 0, + 0, 0, 0, 0, 0, 267, 622, 639, 234, 0, 589, 234, 248, 234, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 235, 45, 45, 286, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 319, 45, 45, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 640, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 319, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 566, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 641, 45, + 249, 319, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 632, 45, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 642, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 643, 45, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3727,14 +3758,18 @@ _hb_ucd_u16[11168] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1948,1949, - 1950,1951,1952,1953,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950, + 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956,1957,1959,1958, - 1960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959, + 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -3801,7 +3836,7 @@ _hb_ucd_gc (unsigned u) static inline uint_fast8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[14026+(((_hb_ucd_u8[13034+(((_hb_ucd_u8[12544+(u>>4>>4)])<<4)+((u>>4)&15u))])<<4)+((u)&15u))]:0; + return u<125259u?_hb_ucd_u8[15060+(((_hb_ucd_u8[13636+(((_hb_ucd_u8[12656+(u>>3>>4)])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:0; } static inline unsigned _hb_ucd_b4 (const uint8_t* a, unsigned i) @@ -3811,24 +3846,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i) static inline int_fast16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16170+(((_hb_ucd_b4(16042+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0; + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16372+(((_hb_ucd_b4(16244+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0; } static inline uint_fast8_t _hb_ucd_sc (unsigned u) { - return u<918000u?_hb_ucd_u8[18924+(((_hb_ucd_u16[3008+(((_hb_ucd_u8[17130+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2; + return u<918000u?_hb_ucd_u8[19126+(((_hb_ucd_u16[3040+(((_hb_ucd_u8[17332+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2; } static inline uint_fast16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[6048+(((_hb_ucd_u8[29052+(u>>6)])<<6)+((u)&63u))]:0; + return u<195102u?_hb_ucd_u16[6144+(((_hb_ucd_u8[29430+(u>>6)])<<6)+((u)&63u))]:0; } #elif !defined(HB_NO_UCD_UNASSIGNED) static const uint8_t -_hb_ucd_u8[17198] = +_hb_ucd_u8[17508] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 7, 7, 7, 7, 12, 13, 14, 14, 14, 15, @@ -3836,6 +3871,7 @@ _hb_ucd_u8[17198] = 25, 26, 21, 21, 21, 21, 27, 28, 21, 21, 29, 30, 31, 32, 33, 34, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 35, 7, 36, 37, 7, 38, 7, 7, 7, 39, 21, 40, + 7, 7, 41, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, @@ -3857,13 +3893,12 @@ _hb_ucd_u8[17198] = 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 42, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 41, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 43, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 44, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43, @@ -3881,33 +3916,34 @@ _hb_ucd_u8[17198] = 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, 108,108, 34, 34,109,110,111,112, 34, 34,113,114,115,116,117,118, 119,120,121,122,123,124,125,126,127,128,129,123, 34, 34,130,123, - 131,132,133,134,135,136,137,138,139,140,141,123,142,123,143,144, - 145,146,147,148,149,150,151,123,152,153,123,154,155,156,157,123, - 158,159,123,160,161,162,123,123,163,164,165,166,123,167,123,168, - 34, 34, 34, 34, 34, 34, 34,169,170, 34,171,123,123,123,123,123, + 131,132,133,134,135,136,137,138,139,140,141,123,142,143,144,145, + 146,147,148,149,150,151,152,123,153,154,123,155,156,157,158,123, + 159,160,161,162,163,164,123,123,165,166,167,168,123,169,123,170, + 34, 34, 34, 34, 34, 34, 34,171,172, 34,173,123,123,123,123,123, 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, - 34, 34, 34, 34, 34, 34, 34, 34,172,123,123,123,123,123,123,123, - 123,123,123,123,123,123,123,123, 34, 34, 34, 34,173,123,123,123, - 34, 34, 34, 34,174,175,176,177,123,123,123,123,178,179,180,181, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,182, - 34, 34, 34, 34, 34,183,123,123,123,123,123,123,123,123,123,123, - 34, 34,184, 34, 34,185,123,123,123,123,123,123,123,123,123,123, - 123,123,123,123,123,123,123,123,186,187,123,123,123,123,123,123, - 69,188,189,190,191,192,193,123,194,195,196,197,198,199,200,201, - 69, 69, 69, 69,202,203,123,123,123,123,123,123,123,123,123,123, - 204,123,205,123,123,206,123,123,123,123,123,123,123,123,123,123, - 34,207,208,123,123,123,123,123,209,210,211,123,212,213,123,123, - 214,215,216,217,218,123, 69,219, 69, 69, 69, 69, 69,220,221,222, - 223,224,225,226,227,228,123,123,123,123,123,123,123,123,123,123, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,229, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,230, 34, - 231, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,232, 34, 34, - 34, 34, 34, 34, 34, 34, 34,233,123,123,123,123,123,123,123,123, - 34, 34, 34, 34,234,123,123,123,123,123,123,123,123,123,123,123, - 235,123,236,237,123,123,123,123,123,123,123,123,123,123,123,123, - 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,238, - 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,239, + 34, 34, 34, 34, 34, 34, 34, 34,174,123,123,123,123,123,123,123, + 123,123,123,123,123,123,123,123, 34, 34, 34, 34,175,123,123,123, + 34, 34, 34, 34,176,177,178,179,123,123,123,123,180,181,182,183, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,184, + 34, 34, 34, 34, 34, 34, 34, 34, 34,185,186,123,123,123,123,123, + 34, 34,187, 34, 34,188,123,123,123,123,123,123,123,123,123,123, + 123,123,123,123,123,123,123,123,189,190,123,123,123,123,123,123, + 69,191,192,193,194,195,196,123,197,198,199,200,201,202,203,204, + 69, 69, 69, 69,205,206,123,123,123,123,123,123,123,123,123,123, + 207,123,208,123,123,209,123,123,123,123,123,123,123,123,123,123, + 34,210,211,123,123,123,123,123,212,213,214,123,215,216,123,123, + 217,218,219,220,221,123, 69,222, 69, 69, 69, 69, 69,223,224,225, + 226,227,228,229,230,231, 69,232,123,123,123,123,123,123,123,123, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,233, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,234, 34, + 235, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,236, 34, 34, + 34, 34, 34, 34, 34, 34, 34,237,123,123,123,123,123,123,123,123, + 34, 34, 34, 34,238,123,123,123,123,123,123,123,123,123,123,123, + 34, 34, 34, 34, 34, 34,239,123,123,123,123,123,123,123,123,123, + 240,123,241,242,123,123,123,123,123,123,123,123,123,123,123,123, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,243, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,244, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, @@ -3944,78 +3980,79 @@ _hb_ucd_u8[17198] = 43, 43, 40, 21, 2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43, 43, 43, 75, 43, 75, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 64, 36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 61, 36, 36, 36, 36, 44, - 44, 57, 43, 43, 43, 43, 43, 43, 43, 82, 43, 43, 43, 43, 43, 43, - 43, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 83, 71, 84, - 85, 43, 43, 43, 83, 84, 85, 84, 70, 43, 43, 43, 36, 36, 36, 36, - 36, 43, 2, 7, 7, 7, 7, 7, 86, 36, 36, 36, 36, 36, 36, 36, - 70, 84, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 84, - 85, 43, 80, 87, 88, 87, 85, 61, 44, 44, 44, 87, 44, 44, 36, 62, - 36, 43, 44, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 56, 63, 80, - 57, 83, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 84, - 85, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61, - 44, 44, 44, 7, 7, 7, 7, 7, 43, 36, 70, 64, 44, 44, 44, 44, - 57, 83, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, - 61, 36, 62, 36, 36, 44, 71, 84, 85, 43, 43, 57, 83, 87, 85, 44, - 61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43, - 57, 84, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 85, - 85, 43, 80, 87, 88, 87, 85, 44, 44, 44, 44, 83, 44, 44, 36, 62, - 78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36, - 61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36, - 36, 36, 36, 36, 36, 44, 44, 84, 83, 88, 44, 84, 88, 84, 85, 44, - 61, 44, 44, 87, 44, 44, 44, 44, 27, 89, 67, 67, 56, 90, 44, 44, - 83, 84, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 44, 62, 43, 83, 84, 88, 43, 80, 43, 43, 44, - 44, 44, 57, 80, 36, 61, 44, 44, 44, 44, 44, 91, 27, 27, 27, 89, - 70, 84, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 85, - 84, 84, 88, 83, 88, 84, 43, 44, 44, 44, 87, 88, 44, 44, 44, 61, - 62, 61, 44, 44, 44, 44, 44, 44, 43, 84, 62, 36, 36, 36, 61, 36, - 36, 36, 36, 36, 36, 70, 71, 84, 85, 43, 80, 84, 88, 84, 85, 77, - 44, 44, 36, 92, 27, 27, 27, 93, 27, 27, 27, 27, 89, 36, 36, 36, - 44, 84, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36, - 36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 87, - 84, 43, 80, 80, 84, 84, 84, 84, 44, 84, 64, 44, 44, 44, 44, 44, - 62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 94, - 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44, - 62, 61, 61, 36, 36, 61, 36, 36, 36, 36, 62, 62, 36, 36, 36, 36, - 70, 36, 43, 43, 43, 43, 71, 44, 36, 36, 61, 81, 43, 43, 43, 44, - 7, 7, 7, 7, 7, 44, 36, 36, 77, 67, 2, 2, 2, 2, 2, 2, - 2, 95, 95, 67, 43, 67, 67, 67, 7, 7, 7, 7, 7, 27, 27, 27, - 27, 27, 50, 50, 50, 4, 4, 84, 36, 36, 36, 36, 62, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 61, 44, 57, 43, 43, 43, 43, 43, 43, 83, - 43, 43, 60, 43, 36, 36, 70, 43, 43, 43, 43, 43, 57, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 80, 67, 67, 67, 67, 76, 67, 67, 90, 67, - 2, 2, 95, 67, 21, 64, 44, 44, 36, 36, 36, 36, 36, 92, 85, 43, - 83, 43, 43, 43, 85, 83, 85, 71, 7, 7, 7, 7, 7, 2, 2, 2, - 36, 36, 36, 84, 43, 36, 36, 43, 71, 84, 96, 92, 84, 84, 84, 36, - 70, 43, 71, 36, 36, 36, 36, 36, 36, 83, 85, 83, 84, 84, 85, 92, - 7, 7, 7, 7, 7, 84, 85, 67, 11, 11, 11, 48, 44, 44, 48, 44, - 16, 16, 16, 16, 16, 53, 45, 16, 36, 36, 36, 36, 61, 36, 36, 44, - 36, 36, 36, 61, 61, 36, 36, 44, 61, 36, 36, 44, 36, 36, 36, 61, - 61, 36, 36, 44, 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 61, 57, 43, 2, 2, 2, 2, 97, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 98, 44, 67, 67, 67, 67, 67, 44, 44, 44, - 11, 11, 11, 44, 16, 16, 16, 44, 99, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 77, 72,100, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36,101,102, 44, 36, 36, 36, 36, 36, 63, 2,103, - 104, 36, 36, 36, 61, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36, - 36, 43, 80, 44, 44, 44, 44, 44, 36, 43, 60, 64, 44, 44, 44, 44, - 36, 43, 44, 44, 44, 44, 44, 44, 61, 43, 44, 44, 44, 44, 44, 44, - 36, 36, 43, 85, 43, 43, 43, 84, 84, 84, 84, 83, 85, 43, 43, 43, - 43, 43, 2, 86, 2, 66, 70, 44, 7, 7, 7, 7, 7, 44, 44, 44, - 27, 27, 27, 27, 27, 44, 44, 44, 2, 2, 2,105, 2, 59, 43, 68, - 36,106, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 44, 44, - 36, 36, 70, 71, 36, 36, 36, 36, 36, 36, 36, 36, 70, 61, 44, 44, - 36, 36, 36, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 61, - 43, 83, 84, 85, 83, 84, 44, 44, 84, 83, 84, 84, 85, 43, 44, 44, - 90, 44, 2, 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 44, - 36, 36, 61, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 44, 44, - 36, 36, 36, 36, 36, 44, 44, 44, 7, 7, 7, 7, 7, 98, 44, 67, - 67, 67, 67, 67, 67, 67, 67, 67, 36, 36, 36, 70, 83, 85, 44, 2, - 36, 36, 92, 83, 43, 43, 43, 80, 83, 83, 85, 43, 43, 43, 83, 84, - 84, 85, 43, 43, 43, 43, 80, 57, 2, 2, 2, 86, 2, 2, 2, 44, - 43, 43, 43, 43, 43, 43, 43,107, 43, 43, 96, 36, 36, 36, 36, 36, + 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 44, 44, 44, 44, 44, 57, 43, 43, 43, 43, 43, 43, + 43, 82, 43, 43, 43, 43, 43, 43, 43, 83, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 83, 71, 84, 85, 43, 43, 43, 83, 84, 85, 84, + 70, 43, 43, 43, 36, 36, 36, 36, 36, 43, 2, 7, 7, 7, 7, 7, + 86, 36, 36, 36, 36, 36, 36, 36, 70, 84, 62, 36, 36, 36, 61, 62, + 61, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, + 61, 61, 44, 36, 36, 44, 71, 84, 85, 43, 80, 87, 88, 87, 85, 61, + 44, 44, 44, 87, 44, 44, 36, 62, 36, 43, 44, 7, 7, 7, 7, 7, + 36, 20, 27, 27, 27, 56, 63, 80, 57, 83, 62, 36, 36, 61, 44, 62, + 61, 36, 62, 61, 36, 44, 80, 84, 85, 80, 44, 57, 80, 57, 43, 44, + 57, 44, 44, 44, 62, 36, 61, 61, 44, 44, 44, 7, 7, 7, 7, 7, + 43, 36, 70, 64, 44, 44, 44, 44, 57, 83, 62, 36, 36, 36, 36, 62, + 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, 36, 36, 44, 71, 84, + 85, 43, 43, 57, 83, 87, 85, 44, 61, 44, 44, 44, 44, 44, 44, 44, + 66, 44, 44, 44, 62, 43, 43, 43, 57, 84, 62, 36, 36, 36, 61, 62, + 61, 36, 62, 36, 36, 44, 71, 85, 85, 43, 80, 87, 88, 87, 85, 44, + 44, 44, 57, 83, 44, 44, 36, 62, 78, 27, 27, 27, 44, 44, 44, 44, + 44, 71, 62, 36, 36, 61, 44, 36, 61, 36, 36, 44, 62, 61, 61, 36, + 44, 62, 61, 44, 36, 61, 44, 36, 36, 36, 36, 36, 36, 44, 44, 84, + 83, 88, 44, 84, 88, 84, 85, 44, 61, 44, 44, 87, 44, 44, 44, 44, + 27, 89, 67, 67, 56, 90, 44, 44, 83, 84, 71, 36, 36, 36, 61, 36, + 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 62, 43, + 83, 84, 88, 43, 80, 43, 43, 44, 44, 44, 57, 80, 36, 61, 44, 44, + 44, 44, 44, 91, 27, 27, 27, 89, 70, 84, 72, 36, 36, 36, 61, 36, + 36, 36, 62, 36, 36, 44, 71, 85, 84, 84, 88, 83, 88, 84, 43, 44, + 44, 44, 87, 88, 44, 44, 44, 61, 62, 61, 44, 44, 44, 44, 44, 44, + 43, 84, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 70, 71, 84, + 85, 43, 80, 84, 88, 84, 85, 77, 44, 44, 36, 92, 27, 27, 27, 93, + 27, 27, 27, 27, 89, 36, 36, 36, 57, 84, 62, 36, 36, 36, 36, 36, + 36, 36, 36, 61, 44, 36, 36, 36, 36, 62, 36, 36, 36, 36, 62, 44, + 36, 36, 36, 61, 44, 80, 44, 87, 84, 43, 80, 80, 84, 84, 84, 84, + 44, 84, 64, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, 36, + 70, 36, 43, 43, 43, 80, 44, 94, 36, 36, 36, 75, 43, 43, 43, 60, + 7, 7, 7, 7, 7, 2, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36, + 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44, + 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36, + 77, 67, 2, 2, 2, 2, 2, 2, 2, 95, 95, 67, 43, 67, 67, 67, + 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 84, + 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, + 57, 43, 43, 43, 43, 43, 43, 83, 43, 43, 60, 43, 36, 36, 70, 43, + 43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67, + 67, 67, 67, 76, 67, 67, 90, 67, 2, 2, 95, 67, 21, 64, 44, 44, + 36, 36, 36, 36, 36, 92, 85, 43, 83, 43, 43, 43, 85, 83, 85, 71, + 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 84, 43, 36, 36, 43, + 71, 84, 96, 92, 84, 84, 84, 36, 70, 43, 71, 36, 36, 36, 36, 36, + 36, 83, 85, 83, 84, 84, 85, 92, 7, 7, 7, 7, 7, 84, 85, 67, + 11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16, + 36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, + 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36, + 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43, + 2, 2, 2, 2, 97, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, + 67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44, + 99, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72, + 100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,101,102, 44, + 36, 36, 36, 36, 36, 63, 2,103,104, 36, 36, 36, 61, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 61, 36, 36, 43, 80, 44, 44, 44, 44, 44, + 36, 43, 60, 64, 44, 44, 44, 44, 36, 43, 44, 44, 44, 44, 44, 44, + 61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 85, 43, 43, 43, 84, + 84, 84, 84, 83, 85, 43, 43, 43, 43, 43, 2, 86, 2, 66, 70, 44, + 7, 7, 7, 7, 7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44, + 2, 2, 2,105, 2, 59, 43, 68, 36,106, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36, + 36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 36, 61, 43, 83, 84, 85, 83, 84, 44, 44, + 84, 83, 84, 84, 85, 43, 44, 44, 90, 44, 2, 7, 7, 7, 7, 7, + 36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44, + 7, 7, 7, 7, 7, 98, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 36, 36, 36, 70, 83, 85, 44, 2, 36, 36, 92, 83, 43, 43, 43, 80, + 83, 83, 85, 43, 43, 43, 83, 84, 84, 85, 43, 43, 43, 43, 80, 57, + 2, 2, 2, 86, 2, 2, 2, 44, 43, 43, 43, 43, 43, 43, 43,107, + 80, 44, 44, 44, 44, 44, 44, 44, 43, 43, 96, 36, 36, 36, 36, 36, 36, 36, 83, 43, 43, 83, 83, 84, 84, 83, 96, 36, 36, 36, 44, 44, 95, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 90, 44, 43, 96, 36, 36, 36, 36, 36, 36, 92, 43, 43, 84, 43, 85, 43, 36, @@ -4039,118 +4076,119 @@ _hb_ucd_u8[17198] = 65, 65, 68, 65, 65, 65, 65, 65,130, 44, 27, 27, 27, 8,127,131, 27, 27, 27, 27, 27, 8,127,102, 40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,132, 51, - 133, 51,133, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44, - 67,134, 67,135, 67, 34, 11, 16, 11, 32,135, 67, 49, 11, 11, 67, - 67, 67,134,134,134, 11, 11,136, 11, 11, 35, 36, 39, 67, 16, 11, - 8, 8, 49, 16, 16, 26, 67,137, 27, 27, 27, 27, 27, 27, 27, 27, - 103,103,103,103,103,103,103,103,103,138,139,103,140, 67, 44, 44, - 8, 8,141, 67, 67, 8, 67, 67,141, 26, 67,141, 67, 67, 67,141, - 67, 67, 67, 67, 67, 67, 67, 8, 67,141,141, 67, 67, 67, 67, 67, - 67, 67, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 67, 67, 67, 67, 4, 4, 67, 67, 8, 67, 67, 67,142,143, 67, 67, - 67, 67, 67, 67, 67, 67,141, 67, 67, 67, 67, 67, 67, 26, 8, 8, - 8, 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8, - 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 90, 44, 44, 27, 27, 27, 27, 27, 27, 67, 67, - 67, 67, 67, 67, 67, 27, 27, 27, 67, 67, 67, 26, 67, 67, 67, 67, - 26, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8, 8, 8, - 67, 67, 67, 67, 67, 67, 67, 26, 67, 67, 67, 67, 4, 4, 4, 4, - 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, - 8, 8,127,144, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, - 8,127,145,145,145,145,145,145,145,145,145,145,144, 8, 8, 8, - 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, - 8, 8,141, 26, 8, 8,141, 67, 67, 67, 44, 67, 67, 67, 67, 67, - 67, 67, 67, 44, 67, 67, 67, 67, 11, 11, 11, 11, 11, 11, 11, 47, - 16, 16, 16, 16, 16, 16, 16,108, 32, 11, 32, 34, 34, 34, 34, 11, - 32, 32, 34, 16, 16, 16, 40, 11, 32, 32,137, 67, 67,135, 34,146, - 43, 32, 44, 44, 91, 2, 97, 2, 16, 16, 16,147, 44, 44,147, 44, - 36, 36, 36, 36, 44, 44, 44, 52, 64, 44, 44, 44, 44, 44, 44, 57, - 36, 36, 36, 61, 44, 44, 44, 44, 36, 36, 36, 61, 36, 36, 36, 61, - 2,119,119, 2,123,124,119, 2, 2, 2, 2, 6, 2,105,119, 2, - 119, 4, 4, 4, 4, 2, 2, 86, 2, 2, 2, 2, 2,118, 2, 2, - 105,148, 2, 2, 2, 2, 2, 2, 67, 67, 67, 67, 67, 55, 67, 67, + 107, 51,107, 43, 43, 43, 43, 43, 67,133, 67,134, 67, 34, 11, 16, + 11, 32,134, 67, 49, 11, 11, 67, 67, 67,133,133,133, 11, 11,135, + 11, 11, 35, 36, 39, 67, 16, 11, 8, 8, 49, 16, 16, 26, 67,136, + 27, 27, 27, 27, 27, 27, 27, 27,103,103,103,103,103,103,103,103, + 103,137,138,103,139, 67, 44, 44, 8, 8,140, 67, 67, 8, 67, 67, + 140, 26, 67,140, 67, 67, 67,140, 67, 67, 67, 67, 67, 67, 67, 8, + 67,140,140, 67, 67, 67, 67, 67, 67, 67, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 67, 67, 67, 67, 4, 4, 67, 67, + 8, 67, 67, 67,141,142, 67, 67, 67, 67, 67, 67, 67, 67,140, 67, + 67, 67, 67, 67, 67, 26, 8, 8, 8, 8, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 8, 8, 8, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 90, 44, 44, 44, 44, 67, 67, 67, 67, 67, 90, 44, 44, + 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, + 67, 67, 67, 26, 67, 67, 67, 67, 26, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 8, 8, 8, 8, 67, 67, 67, 67, 67, 67, 67, 26, + 67, 67, 67, 67, 4, 4, 4, 4, 4, 4, 4, 27, 27, 27, 27, 27, + 27, 27, 67, 67, 67, 67, 67, 67, 8, 8,127,143, 8, 8, 8, 8, + 8, 8, 8, 4, 4, 4, 4, 4, 8,127,144,144,144,144,144,144, + 144,144,144,144,143, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8, + 8, 8, 8, 8, 8, 8, 4, 8, 8, 8,140, 26, 8, 8,140, 67, + 67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, + 11, 11, 11, 11, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16,108, + 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11, + 32, 32,136, 67, 67,134, 34,145, 43, 32, 44, 44, 91, 2, 97, 2, + 16, 16, 16,146, 44, 44,146, 44, 36, 36, 36, 36, 44, 44, 44, 52, + 64, 44, 44, 44, 44, 44, 44, 57, 36, 36, 36, 61, 44, 44, 44, 44, + 36, 36, 36, 61, 36, 36, 36, 61, 2,119,119, 2,123,124,119, 2, + 2, 2, 2, 6, 2,105,119, 2,119, 4, 4, 4, 4, 2, 2, 86, + 2, 2, 2, 2, 2,118, 2, 2,105,147, 2, 2, 2, 2, 2, 2, + 67, 64, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44, 67, 67, 67, 44, 44, 44, 44, 44, - 67, 67, 67, 67, 67, 67, 44, 44, 1, 2,149,150, 4, 4, 4, 4, - 4, 67, 4, 4, 4, 4,151,152,153,103,103,103,103, 43, 43, 84, - 154, 40, 40, 67,103,155, 63, 67, 36, 36, 36, 61, 57,156,157, 69, + 67, 67, 67, 67, 67, 67, 44, 44, 1, 2,148,149, 4, 4, 4, 4, + 4, 67, 4, 4, 4, 4,150,151,152,103,103,103,103, 43, 43, 84, + 153, 40, 40, 67,103,154, 63, 67, 36, 36, 36, 61, 57,155,156, 69, 36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, - 158, 27, 27, 27, 27, 27, 27, 27, 36, 36,106, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36,159, 2, 7, 7, 7, 7, 7, 36, 44, 44, - 32, 32, 32, 32, 32, 32, 32, 70, 51,160, 43, 43, 43, 43, 43, 86, + 157, 27, 27, 27, 27, 27, 27, 27, 36, 36,106, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36,158, 2, 7, 7, 7, 7, 7, 36, 44, 44, + 32, 32, 32, 32, 32, 32, 32, 70, 51,159, 43, 43, 43, 43, 43, 86, 32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36,103,103,103,103,103, - 43, 2, 2, 2, 44, 44, 44, 44, 41, 41, 41,157, 40, 40, 40, 40, + 43, 2, 2, 2, 44, 44, 44, 44, 41, 41, 41,156, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, - 45, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,161, 34, 35, + 45, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,160, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32, - 11, 11, 32, 32, 32, 32, 32, 32, 44, 32, 11, 47, 44, 44, 44, 44, - 44, 44, 44, 62, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36, - 36, 92, 85, 83, 67, 67, 44, 44, 27, 27, 27, 67,162, 44, 44, 44, + 11, 11, 32, 32, 32, 32, 32, 32, 44, 32, 11, 11, 34,108, 44, 44, + 44, 44, 48, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36, + 36, 92, 85, 83, 67, 67, 80, 44, 27, 27, 27, 67,161, 44, 44, 44, 36, 36, 2, 2, 44, 44, 44, 44, 84, 36, 36, 36, 36, 36, 36, 36, 36, 36, 84, 84, 84, 84, 84, 84, 84, 84, 43, 44, 44, 44, 44, 2, 43, 36, 36, 36, 2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43, 2, 36, 36, 36, 70, 43, 43, 43, 43, 43, 84, 44, 44, 44, 44, 44, 91, - 36, 70, 84, 43, 43, 84, 43, 84,163, 2, 2, 2, 2, 2, 2, 52, + 36, 70, 84, 43, 43, 84, 43, 84,162, 2, 2, 2, 2, 2, 2, 52, 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 70, 69, 36, 36, 36, 36, 7, 7, 7, 7, 7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 83, 85, 83, 85, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 83, 44, 7, 7, 7, 7, 7, 44, 2, 2, 69, 36, 36, 77, 67, 92, 83, 36, 71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 62,106, 2, 36, 36, 36, 36, 36, 92, 43, 84, - 2,106,164, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61, + 2,106,163, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61, 62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,112, 40, 40, - 16, 16, 16, 16, 44, 44, 44, 44, 36, 92, 85, 84, 83,163, 85, 44, + 16, 16, 16, 16,109, 41, 44, 44, 36, 92, 85, 84, 83,162, 85, 44, 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36, - 165,165,165,165,165,165,165,165,166,166,166,166,166,166,166,166, - 16, 16, 16,108, 44, 44, 44, 44, 44,147, 16, 16, 44, 44, 62, 71, - 36, 36, 36, 36,167, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61, + 164,164,164,164,164,164,164,164,165,165,165,165,165,165,165,165, + 16, 16, 16,108, 44, 44, 44, 44, 44,146, 16, 16, 44, 44, 62, 71, + 36, 36, 36, 36,166, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61, 36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41, 41, 44, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36,145, 44, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36,162, 44, - 2, 2, 2,168,128, 44, 44, 44, 6,169,170,145,145,145,145,145, - 145,145,128,168,128, 2,125,171, 2, 64, 2, 2,151,145,145,128, - 2,172, 8,173, 66, 2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36,144, 44, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36,161, 44, 2, 2, 2,167,128, 44, 44, 44, + 6,168,169,144,144,144,144,144,144,144,128,167,128, 2,125,170, + 2, 64, 2, 2,150,144,144,128, 2,171, 8,172, 66, 2, 44, 44, 36, 36, 36, 36, 36, 36, 61, 79, 91, 2, 3, 2, 4, 5, 6, 2, 16, 16, 16, 16, 16, 17, 18,127,128, 4, 2, 36, 36, 36, 36, 36, 69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44, - 20,174, 56,175, 26, 8,141, 90, 44, 44, 44, 44, 79, 65, 67, 44, + 20,173, 56,174, 26, 8,140, 90, 44, 44, 44, 44, 79, 65, 67, 44, 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, - 2, 64, 44,176, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67, - 103,103,140, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 90, - 90, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 50, 44, - 177, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 44, 44, - 27, 27, 44, 44, 44, 44, 62, 36,150, 36, 36, 36, 36,178, 44, 44, - 36, 36, 36, 43, 43, 80, 44, 44, 36, 36, 36, 36, 36, 36, 36, 91, - 36, 36, 44, 44, 36, 36, 36, 36,179,103,103, 44, 44, 44, 44, 44, - 11, 11, 11, 11, 16, 16, 16, 16, 11, 11, 44, 44, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 44, 44, 36, 36, 44, 44, 44, 44, 44, 91, - 36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62, - 36, 36, 36, 91, 27, 27, 27, 27, 36, 36, 36, 77,158, 27, 27, 27, - 44, 44, 44,176, 27, 27, 27, 27, 36, 61, 36, 44, 44,176, 27, 27, - 36, 36, 36, 27, 27, 27, 44, 91, 36, 36, 36, 36, 36, 44, 44, 91, - 36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27, - 70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36, - 36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27, 98, 44, 44, 44, - 2, 2, 2, 2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,180, 30, - 36, 36, 36, 36, 36, 36,180, 27, 36, 36, 36, 36, 78, 36, 36, 36, - 36, 36, 70, 80, 44,176, 27, 27, 2, 2, 2, 64, 44, 44, 44, 44, - 36, 36, 36, 44, 91, 2, 2, 2, 36, 36, 36, 44, 27, 27, 27, 27, - 36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 91, 2, 64, 44, - 44, 44, 44, 44,176, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44, - 16,108, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44, - 27, 27, 27, 27, 27, 27, 27, 98, 27, 27, 27, 93, 44, 44, 44, 44, - 177, 27, 30, 2, 2, 44, 44, 44, 85, 96, 36, 36, 36, 36, 36, 36, + 2, 64, 44,175, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67, + 103,103,139, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 90, + 67, 67, 67, 67, 67, 67, 90, 44, 90, 44, 44, 44, 44, 44, 44, 44, + 67, 67, 67, 67, 67, 67, 50, 44,176, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36, + 149, 36, 36, 36, 36,177, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44, + 36, 36, 36, 36, 36, 36, 36, 91, 36, 36, 44, 44, 36, 36, 36, 36, + 178,103,103, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16, + 11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44, + 36, 36, 44, 44, 44, 44, 44, 91, 36, 36, 36, 44, 61, 36, 36, 36, + 36, 36, 36, 62, 61, 44, 61, 62, 36, 36, 36, 91, 27, 27, 27, 27, + 36, 36, 36, 77,157, 27, 27, 27, 44, 44, 44,175, 27, 27, 27, 27, + 36, 61, 36, 44, 44,175, 27, 27, 36, 36, 36, 27, 27, 27, 44, 91, + 36, 36, 36, 36, 36, 44, 44, 91, 36, 36, 36, 36, 44, 44, 27, 36, + 44, 27, 27, 27, 27, 27, 27, 27, 70, 43, 57, 80, 44, 44, 43, 43, + 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, 44, 43, 80, 44, 57, + 27, 27, 27, 27, 98, 44, 44, 44, 2, 2, 2, 2, 64, 44, 44, 44, + 36, 36, 36, 36, 36, 36,179, 30, 36, 36, 36, 36, 36, 36,179, 27, + 36, 36, 36, 36, 78, 36, 36, 36, 36, 36, 70, 80, 44,175, 27, 27, + 2, 2, 2, 64, 44, 44, 44, 44, 36, 36, 36, 44, 91, 2, 2, 2, + 36, 36, 36, 44, 27, 27, 27, 27, 36, 61, 44, 44, 27, 27, 27, 27, + 36, 44, 44, 44, 91, 2, 64, 44, 44, 44, 44, 44,175, 27, 27, 27, + 11, 47, 44, 44, 44, 44, 44, 44, 16,108, 44, 44, 44, 27, 27, 27, + 36, 36, 43, 43, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27, 98, + 36, 36, 36, 36, 36, 57,180, 44, 36, 44, 44, 44, 44, 44, 44, 44, + 27, 27, 27, 93, 44, 44, 44, 44,176, 27, 30, 2, 2, 44, 44, 44, + 36, 36,179, 27, 27, 27, 44, 44, 85, 96, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44, 27, 27, 27, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 57, 84, 85, 43, 83, 85, 60,181, 2, 2, 44, 44, 44, 44, 44, 79, 44, 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 85, 43, - 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 92, 88, 44, 44, 44, 44, + 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 92, 96, 44, 44, 44, 44, 36, 70, 2, 61, 44, 44, 44, 44, 36, 92, 84, 43, 43, 43, 43, 83, - 96, 36, 63, 2, 59, 43, 60, 44, 7, 7, 7, 7, 7, 63, 63, 2, - 176, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, 44, 44, 44, 44, + 96, 36, 63, 2, 59, 43, 60, 85, 7, 7, 7, 7, 7, 63, 63, 2, + 175, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 84, 85, 43, 84, 83, 43, 2, 2, 2, 80, 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70, @@ -4158,7 +4196,7 @@ _hb_ucd_u8[17198] = 61, 36, 62, 36, 36, 57, 71, 84, 83, 84, 88, 87, 88, 87, 84, 44, 61, 44, 44, 87, 44, 44, 62, 36, 36, 84, 44, 43, 43, 43, 80, 44, 43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 92, 84, 43, 43, 43, 43, - 84, 43, 83, 71, 36, 63, 2, 2, 7, 7, 7, 7, 7, 91, 91, 71, + 84, 43, 83, 71, 36, 63, 2, 2, 7, 7, 7, 7, 7, 2, 91, 71, 84, 85, 43, 43, 83, 83, 84, 85, 83, 43, 36, 72, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 92, 84, 43, 43, 44, 84, 84, 43, 85, 60, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 43, 44, @@ -4166,7 +4204,9 @@ _hb_ucd_u8[17198] = 2, 2, 2, 2, 2, 2, 64, 44, 36, 36, 36, 36, 36, 70, 85, 84, 43, 43, 43, 85, 61, 44, 44, 44, 84, 43, 43, 85, 43, 43, 44, 44, 7, 7, 7, 7, 7, 27, 2, 95, 43, 43, 43, 43, 85, 60, 44, 44, - 27, 98, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 44, 36, 36, 36, + 27, 98, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36, + 36, 36, 62, 61, 36, 36, 36, 36, 84, 84, 84, 87, 88, 57, 83, 71, + 96, 85, 2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36, 92, 84, 43, 43, 44, 43, 84, 84, 71, 72, 88, 44, 44, 44, 44, 44, 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 83, 70, 43, 60, 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 83, 85, 43, 36, 36, @@ -4177,199 +4217,202 @@ _hb_ucd_u8[17198] = 83, 43, 85, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36, 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44, 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 84, 84, 88, - 43, 87, 85, 85, 61, 44, 44, 44, 36, 70, 83,163, 64, 44, 44, 44, - 27, 27, 89, 67, 67, 67, 56, 20,162, 67, 67, 67, 67, 67, 67, 67, - 67, 44, 44, 44, 44, 44, 44, 91,103,103,103,103,103,103,103,178, + 43, 87, 85, 85, 61, 44, 44, 44, 36, 70, 83,162, 64, 44, 44, 44, + 27, 27, 89, 67, 67, 67, 56, 20,161, 67, 67, 67, 67, 67, 67, 67, + 67, 44, 44, 44, 44, 44, 44, 91,103,103,103,103,103,103,103,177, 2, 2, 64, 44, 44, 44, 44, 44, 65, 65, 65, 65, 68, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60, 2, 2, 67, 67, - 40, 40, 95, 44, 44, 44, 44, 44, 7, 7, 7, 7, 7,176, 27, 27, + 40, 40, 95, 44, 44, 44, 44, 44, 7, 7, 7, 7, 7,175, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44, 36, 36, 36, 36, 36, 61, 44, 57, 92, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40, - 40, 86, 44, 44, 44, 44, 44, 44, 36, 61, 44, 44, 44, 44, 44, 44, - 44, 44, 36, 36, 44, 44, 44, 44, 36, 36, 36, 36, 36, 44, 50, 60, - 65, 65, 44, 44, 44, 44, 44, 44, 67, 67, 67, 90, 55, 67, 67, 67, - 67, 67,182, 85, 43, 67,182, 84, 84,183, 65, 65, 65, 82, 43, 43, - 43, 76, 50, 43, 43, 43, 67, 67, 67, 67, 67, 67, 67, 43, 43, 67, - 67, 67, 67, 67, 90, 44, 44, 44, 67, 43, 76, 44, 44, 44, 44, 44, - 27, 27, 44, 44, 44, 44, 44, 44, 11, 11, 11, 11, 11, 16, 16, 16, - 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16, - 16, 16,108, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 47, 11, 44, 47, 48, 47, 48, 11, 47, 11, - 11, 11, 11, 16, 16,147,147, 16, 16, 16,147, 16, 16, 16, 16, 16, - 16, 16, 11, 48, 11, 47, 48, 11, 11, 11, 47, 11, 11, 11, 47, 16, - 16, 16, 16, 16, 11, 48, 11, 47, 11, 11, 47, 47, 44, 11, 11, 11, - 47, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11, - 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 44, 11, 11, 11, 11, - 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, - 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, - 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, - 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 44, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 43, 43, 43, 76, 67, 50, 43, 43, - 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67, - 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43, - 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43, - 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44, - 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 43, 43, - 7, 7, 7, 7, 7, 44, 44, 94, 36, 36, 61,176, 27, 27, 27, 27, - 43, 43, 43, 80, 44, 44, 44, 44, 16, 16, 43, 43, 43, 74, 44, 44, - 27, 27, 27, 27, 27, 27,158, 27,184, 27, 98, 44, 44, 44, 44, 44, - 27, 27, 27, 27, 27, 27, 27,158, 27, 27, 27, 27, 27, 27, 27, 44, - 36, 36, 62, 36, 36, 36, 36, 36, 62, 61, 61, 62, 62, 36, 36, 36, - 36, 61, 36, 36, 62, 62, 44, 44, 44, 61, 44, 62, 62, 62, 62, 36, - 62, 61, 61, 62, 62, 62, 62, 62, 62, 61, 61, 62, 36, 61, 36, 36, - 36, 61, 36, 36, 62, 36, 61, 61, 36, 36, 36, 36, 36, 62, 36, 36, - 62, 36, 62, 36, 36, 62, 36, 36, 8, 44, 44, 44, 44, 44, 44, 44, - 55, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, 44, + 40, 86, 80, 44, 44, 44, 44, 44, 84, 44, 44, 44, 44, 44, 44, 44, + 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44, + 67, 67, 67, 90, 55, 67, 67, 67, 67, 67,182, 85, 43, 67,182, 84, + 84,183, 65, 65, 65, 82, 43, 43, 43, 76, 50, 43, 43, 43, 67, 67, + 67, 67, 67, 67, 67, 43, 43, 67, 67, 67, 67, 67, 90, 44, 44, 44, + 67, 43, 76, 44, 44, 44, 44, 44, 27, 27, 44, 44, 44, 44, 44, 44, + 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 16, 16, 16,108, 16, 16, 16, 16, 16, + 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 47, 11, + 44, 47, 48, 47, 48, 11, 47, 11, 11, 11, 11, 16, 16,146,146, 16, + 16, 16,146, 16, 16, 16, 16, 16, 16, 16, 11, 48, 11, 47, 48, 11, + 11, 11, 47, 11, 11, 11, 47, 16, 16, 16, 16, 16, 11, 48, 11, 47, + 11, 11, 47, 47, 44, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, + 16, 16, 16, 44, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, + 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, + 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, + 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, + 16, 33, 16, 16, 16, 32, 44, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 43, 43, 43, 76, 67, 50, 43, 43, 43, 43, 43, 43, 43, 43, 76, 67, + 67, 67, 50, 67, 67, 67, 67, 67, 67, 67, 76, 21, 2, 2, 44, 44, + 44, 44, 44, 44, 44, 57, 43, 43, 43, 43, 43, 80, 43, 43, 43, 43, + 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44, + 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77, + 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 94, + 36, 36, 61,175, 27, 27, 27, 27, 43, 43, 43, 80, 44, 44, 44, 44, + 16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,157, 27, + 184, 27, 98, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,157, + 27, 27, 27, 27, 27, 27, 27, 44, 36, 36, 62, 36, 36, 36, 36, 36, + 62, 61, 61, 62, 62, 36, 36, 36, 36, 61, 36, 36, 62, 62, 44, 44, + 44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62, + 62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61, + 36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36, + 8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, + 27, 27, 27, 27, 27, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41, - 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 67, 44, - 67, 67, 67, 67, 67, 67, 55, 67, 67, 55, 67, 90, 44, 67, 67, 67, - 67, 90, 55, 67, 67, 90, 44, 67, 67, 67, 67, 67, 67, 90, 55, 67, - 67, 67, 44, 44, 67, 90, 44, 44, 36, 44, 44, 44, 44, 44, 44, 44, - 79, 44, 44, 44, 44, 44, 44, 44, 65, 65, 65, 65, 65, 65, 65, 65, - 166,166,166,166,166,166,166, 44,166,166,166,166,166,166,166, 0, - 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, - 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, - 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20, - 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25, - 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5, - 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2, - 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26, - 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21, - 21, 2, 1, 1, 21, 23, 26, 26, 1, 2, 6, 7, 7, 12, 12, 7, - 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1, - 12, 2, 6, 2, 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, - 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, - 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, - 14, 7, 17, 21, 7, 6, 11, 2, 5, 2, 5, 6, 8, 8, 8, 24, - 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, - 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, - 18, 21, 21, 29, 15, 6, 18, 6, 12, 11, 11, 12, 9, 26, 26, 9, - 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, - 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, 26, 6, 7, 14, 17, 22, - 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, - 11, 21, 24, 9, 23, 26, 10, 21, 6, 10, 4, 4, 3, 3, 7, 25, - 21, 22, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 23, 2, - 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, 21, 1, 26, 10, 10, 1, - 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, - 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, - 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 0, 0, 0, 0, - 0, 0, 38, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, - 0, 0, 0, 0, 6, 7, 8, 0, 9, 0, 10, 11, 0, 0, 12, 13, - 14, 15, 16, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 0, 21, 22, - 0, 23, 24, 0, 0, 23, 25, 26, 0, 23, 25, 0, 0, 23, 25, 0, - 0, 23, 25, 0, 0, 0, 25, 0, 0, 0, 27, 0, 0, 23, 25, 0, - 0, 28, 25, 0, 0, 0, 29, 0, 0, 30, 31, 0, 0, 32, 33, 0, - 34, 35, 0, 36, 37, 0, 38, 0, 0, 39, 0, 0, 40, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 42, 42, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 44, 0, 0, - 0, 45, 0, 0, 0, 0, 0, 0, 46, 0, 0, 47, 0, 48, 0, 0, - 0, 49, 50, 51, 0, 52, 0, 53, 0, 54, 0, 0, 0, 0, 55, 56, - 0, 0, 0, 0, 0, 0, 57, 58, 0, 0, 0, 0, 0, 0, 59, 60, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, - 0, 0, 0, 62, 0, 0, 0, 63, 0, 64, 0, 0, 65, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 67, 0, 0, 68, - 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 50, 70, - 0, 71, 72, 0, 0, 73, 74, 0, 0, 0, 0, 0, 0, 75, 76, 77, - 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, - 78, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 81, - 0, 0, 0, 82, 0, 0, 0, 0, 83, 84, 0, 0, 0, 0, 0, 85, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 69, 62, 0, 88, 0, 0, - 89, 90, 0, 73, 0, 0, 91, 0, 0, 92, 0, 0, 0, 0, 0, 93, - 0, 94, 25, 95, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 97, 0, - 0, 0, 0, 0, 0, 62, 98, 0, 0, 62, 0, 0, 0, 99, 0, 0, - 0,100, 0, 0, 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 74, 0, 42,101, 0,102, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, - 0, 0,103, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, - 0,106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,108,109,110, 0, 0, 0, 0,111, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,112,113, 0, 0, 0, 0, 0, 0, - 0,106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,114, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115, 0, + 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 90, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 90, 44, 67, 90, 44, 44, + 67, 90, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44, + 65, 65, 65, 65, 65, 65, 65, 65,165,165,165,165,165,165,165, 44, + 165,165,165,165,165,165,165, 0, 0, 0, 29, 21, 21, 21, 23, 21, + 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, + 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, + 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, + 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, + 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, + 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11, + 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12, + 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26, + 1, 2, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, + 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 1, 12, 12, 10, + 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, + 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, + 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 17, 21, 7, 6, 11, 12, + 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, + 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, + 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6, + 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, + 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, + 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, + 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 23, 26, 10, 21, 6, 10, + 4, 4, 3, 3, 7, 25, 21, 22, 17, 16, 16, 22, 16, 16, 25, 17, + 25, 2, 25, 24, 23, 2, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, + 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, + 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 41, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, + 9, 0, 10, 11, 0, 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, + 18, 19, 20, 0, 0, 0, 21, 22, 0, 23, 24, 0, 0, 23, 25, 26, + 0, 23, 25, 0, 0, 23, 25, 0, 0, 23, 25, 0, 0, 0, 25, 0, + 0, 0, 27, 0, 0, 23, 25, 0, 0, 28, 25, 0, 0, 0, 29, 0, + 0, 30, 31, 0, 0, 32, 33, 0, 34, 35, 0, 36, 37, 0, 38, 0, + 0, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 42, 0, 0, 0, 0, 43, 0, + 0, 0, 0, 0, 0, 44, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, + 46, 0, 0, 47, 0, 48, 49, 0, 0, 50, 51, 52, 0, 53, 0, 54, + 0, 55, 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 0, 58, 59, + 0, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 0, 0, 0, 64, + 0, 65, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67, 68, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, + 70, 71, 0, 0, 0, 0, 51, 72, 0, 73, 74, 0, 0, 75, 76, 0, + 0, 0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 0, 0, 25, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 83, 0, 0, 0, 0, + 84, 85, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, + 0, 0, 70, 63, 0, 90, 0, 0, 91, 92, 0, 75, 0, 0, 93, 0, + 0, 94, 0, 0, 0, 0, 0, 95, 0, 96, 25, 97, 0, 0, 0, 0, + 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 63,100, 0, + 0, 63, 0, 0, 0,101, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, + 0, 90, 0, 0, 0, 0, 0, 0, 0,103,104, 0, 0, 0, 0, 76, + 0, 42,105, 0,106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,108, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,109, 0,110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, + 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113,114,115, 0, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, - 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 0, 0, 0, 0, - 19, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 1, - 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, - 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 38, 1, 39, - 14, 39, 40, 41, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, - 0, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 0, 0, - 0, 0, 19, 1, 21, 0, 0, 47, 0, 0, 0, 0, 0, 38, 48, 1, - 1, 49, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, - 0, 0, 0, 0, 52, 1, 1, 1, 53, 21, 43, 54, 55, 21, 35, 1, - 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 57, 58, 59, 0, 0, - 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, - 0, 0, 0, 57, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, - 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, - 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, - 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, - 0, 0, 0, 0, 0, 70, 71, 0, 0, 0, 0, 0, 72, 73, 74, 75, - 76, 77, 0, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 79, 80, 0, 0, 0, 0, 47, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 63, 0, 0, - 0, 0, 0, 0, 64, 0, 0, 81, 0, 0, 82, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 19, 84, 0, - 63, 0, 0, 0, 0, 49, 1, 85, 0, 0, 0, 0, 1, 54, 15, 41, + 117,118, 0, 0, 0, 0, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, + 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, + 18, 1, 1, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, + 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 31, 0, + 0, 0, 32, 33, 34, 35, 1, 36, 0, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 43, 36, 44, 45, + 21, 45, 46, 0, 0, 0, 0, 0, 0, 0, 19, 1, 21, 0, 0, 47, + 0, 0, 0, 0, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 52, 1, 1, 1, + 53, 21, 43, 54, 55, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 56, + 0, 0, 0, 57, 58, 59, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 57, 0, 61, 0, 0, + 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 70, 71, 0, + 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, + 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 80, 0, + 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, + 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 64, 0, 0, 81, + 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, + 0, 0, 0, 0, 0, 19, 84, 0, 63, 0, 0, 0, 0, 49, 1, 85, + 0, 0, 0, 0, 1, 54, 15, 86, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, - 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, - 0, 87, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, - 0, 0, 0, 0, 88, 9, 12, 4, 89, 8, 90, 47, 0, 59, 50, 0, - 21, 1, 21, 91, 92, 1, 1, 1, 1, 1, 1, 1, 1, 93, 94, 95, - 0, 0, 0, 0, 96, 1, 97, 59, 81, 98, 99, 4, 59, 0, 0, 0, + 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, + 0, 0, 0, 0, 89, 9, 12, 4, 90, 8, 91, 47, 0, 59, 50, 0, + 21, 1, 21, 92, 93, 1, 1, 1, 1, 1, 1, 1, 1, 94, 95, 96, + 0, 0, 0, 0, 97, 1, 98, 59, 81, 99,100, 4, 59, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,100,101, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 19, 0, 1, 1, 50, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,101,102, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 19, 0, 1, 1, 50, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 50, 0, 0, 0, - 0, 64, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 50, 0, 0, 0, - 0, 0, 52, 69, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, - 0, 0, 0, 0, 79, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,103,104, 59, 38, 81, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, - 1, 14, 4, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, - 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 88, 0, - 0, 0, 0,106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 62, - 0,108, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, - 0,109, 14, 54, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0,110, 0, - 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, - 63, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,110, 0, 0, - 0, 0,111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 56, - 0, 38, 1, 59, 1, 59, 0, 0, 64, 87, 0, 0, 0, 0, 0, 60, - 112, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,112, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, - 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, - 87,113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, - 0, 0, 0, 0, 8, 90, 0, 0, 0, 0, 0, 0, 1, 88, 0, 0, - 0, 0, 0, 0, 0, 0, 0,114, 0,115,116,117,118, 0, 52, 4, - 119, 49, 23, 0, 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0, - 38, 59, 0, 0, 0, 0, 0, 0, 1, 88, 1, 1, 1, 1, 39, 1, - 48,103, 88, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 4,119, 0, 0, 0, 1,120, 0, 0, 0, 0, 0, + 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, + 1, 1, 1, 1, 50, 0, 0, 0, 0, 0, 52, 69, 0, 0, 0, 0, + 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, + 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104,105, 59, 38, + 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0,106, 1, 14, 4, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 38, 89, 0, + 0, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 62, + 0,109, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 19, 59, 0, 0, 0, 0, 0,110, 14, 54, 84, 0, 0, 0, + 0, 0, 0, 0, 0, 0,111, 0, 89, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 62, 63, 0, 0, 63, 0, 88, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,111, 0, 0, 0, 0,112, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 79, 56, 0, 38, 1, 59, 1, 59, 0, 0, + 64, 88, 0, 0, 0, 0, 0, 60,113, 0, 0, 0, 0, 0, 0, 0, + 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, 0, 0, + 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 79, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 57, 0, 88,114, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 8, 91, 0, 0, + 0, 0, 0, 0, 1, 89, 0, 0, 0, 0, 0, 0,115, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,116, 0,117,118,119,120, 0, 52, 4, + 121, 49, 23, 0, 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0, + 38, 59, 0, 0, 0, 0, 0, 0, 1, 89, 1, 1, 1, 1, 39, 1, + 48,104, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 4,121, 0, 0, 0, 1,122, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216, 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220, @@ -4391,58 +4434,58 @@ _hb_ucd_u8[17198] = 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0, 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220, - 220, 0, 0, 0,230, 0, 0,220, 0, 0, 9, 9, 0, 0, 7, 0, - 230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220, - 202,230,230,230,230,230,232,228,228,220, 0,230,233,220,230,220, - 230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, - 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,230, 0,230,230, - 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, - 0,230,220, 0, 0, 0,220,220, 0, 9, 7, 0, 0, 7, 9, 0, - 0, 0, 9, 7, 9, 9, 0, 0, 0, 0, 1, 0, 0,216,216, 1, - 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,220,220,220, 0, - 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19, - 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17, + 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220, 0, 0, 9, 9, + 0, 0, 7, 0,230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0, + 230,234,214,220,202,230,230,230,230,230,232,228,228,220, 0,230, + 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230, + 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, + 230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230, + 230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 9, 7, 0, + 0, 7, 9, 0, 0, 0, 9, 7, 9, 9, 0, 0, 6, 6, 0, 0, + 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216, + 216,216,216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, + 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113, + 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, - 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28, - 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 0, 0, - 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, - 0, 0, 0, 0, 1, 2, 39, 40, 0, 1, 2, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, - 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, - 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, - 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12, - 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19, - 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8, - 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27, - 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0, - 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20, - 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20, - 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20, - 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0, - 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0, - 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45, - 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1, - 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 20, 20, - 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 12, 12, 12, 12, 13, 14, - 14, 14, 14, 15, 16, 17, 18, 19, 20, 14, 21, 14, 22, 14, 14, 14, - 14, 23, 24, 24, 25, 26, 14, 14, 14, 14, 27, 28, 14, 14, 29, 30, - 31, 32, 33, 34, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 35, 7, 36, 37, 7, 38, 7, 7, - 7, 39, 14, 40, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, + 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, + 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, + 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, + 0, 0, 0, 33, 34, 35, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 1, 2, 39, 40, + 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, + 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, + 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, + 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, + 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, + 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, + 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, + 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, + 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, + 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, + 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, + 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, + 10, 11, 12, 12, 12, 12, 13, 14, 14, 14, 14, 15, 16, 17, 18, 19, + 20, 14, 21, 14, 22, 14, 14, 14, 14, 23, 24, 24, 25, 26, 14, 14, + 14, 14, 27, 28, 14, 14, 29, 30, 31, 32, 33, 34, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 35, 7, 36, 37, 7, 38, 7, 7, 7, 39, 14, 40, 7, 7, 41, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, @@ -4464,75 +4507,76 @@ _hb_ucd_u8[17198] = 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 41, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37, - 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59, - 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42, 0, 0, 1, + 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56, + 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61, + 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 79, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 80, 81, 81, 81, 81, 81, 81, 81, 81, 81, 82, - 83, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 32, 32, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 80, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, 98, 99,100,101,102,102, - 103,104,105,106,107,108,109,110,111,112, 97,113,114,115,116,117, - 118, 97,119,119,120, 97,121,122,123,124,125,126,127,128,129,130, - 131, 97,132, 97,133,134,135,136,137,138,139,140,141, 97,142,143, - 97,144,145,146,147, 97,148,149, 97,150,151,152, 97, 97,153,154, - 155,156, 97,157, 97,158,159,159,159,159,159,159,159,160,161,159, - 162, 97, 97, 97, 97, 97,163,163,163,163,163,163,163,163,164, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,165,165, - 165,165,166, 97, 97, 97,167,167,167,167,168,169,170,171, 97, 97, - 97, 97,172,173,174,175,176,176,176,176,176,176,176,176,176,176, - 176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, - 176,176,176,176,176,177,176,176,176,176,176,178, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97,179,180,181,182,182,183, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,184,185, - 97, 97, 97, 97, 97, 97, 59,186,187,188,189,190,191, 97,192,193, - 194, 59, 59,195, 59,196,197,197,197,197,197,198, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97,199, 97,200, 97, 97,201, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97,202,203,204, 97, 97, 97, 97, 97,205,206, - 207, 97,208,209, 97, 97,210,211,212,213,214, 97, 59, 59, 59, 59, - 59, 59, 59,215,216,217,218,219,220,221,222,223, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70,224, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70,225, 70,226, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 70, 70, 98, 99,100,101,102,102,103,104,105,106,107,108,109,110, + 111,112, 97,113,114,115,116,117,118, 97,119,119,120, 97,121,122, + 123,124,125,126,127,128,129,130,131, 97,132,133,134,135,136,137, + 138,139,140,141,142, 97,143,144, 97,145,146,147,148, 97,149,150, + 151,152,153,154, 97, 97,155,156,157,158, 97,159, 97,160,161,161, + 161,161,161,161,161,162,163,161,164, 97, 97, 97, 97, 97,165,165, + 165,165,165,165,165,165,166, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97,167,167,167,167,168, 97, 97, 97,169,169, + 169,169,170,171,172,173, 97, 97, 97, 97,174,175,176,177,178,178, + 178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, + 178,178,178,178,178,178,178,178,178,178,178,178,178,179,178,178, + 178,178,178,178,180,180,180,181,182, 97, 97, 97, 97, 97,183,184, + 185,186,186,187, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97,188,189, 97, 97, 97, 97, 97, 97, 59,190, + 191,192,193,194,195, 97,196,197,198, 59, 59,199, 59,200,201,201, + 201,201,201,202, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,203, 97, + 204, 97, 97,205, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,206,207, + 208, 97, 97, 97, 97, 97,209,210,211, 97,212,213, 97, 97,214,215, + 59,216,217, 97, 59, 59, 59, 59, 59, 59, 59,218,219,220,221,222, + 223,224,225,226, 59,227, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,228, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,229, 70,230, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70,227, 70, 70, 70, 70, 70, 70, 70, 70, 70,228, 97, 97, - 97, 97, 97, 97, 97, 97, 70, 70, 70, 70,229, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 97, 97,230, 97,231,232, 0, 1, 2, 2, 0, 1, - 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, - 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19, - 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19, - 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, - 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, - 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, - 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 0, - 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14, - 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3, - 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 2, 3, 0, 0, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37, - 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, - 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95, - 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37, - 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,231, 70, 70, 70, 70, + 70, 70, 70, 70, 70,232, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, + 70, 70,233, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, + 70, 70, 70, 70,234, 97, 97, 97, 97, 97, 97, 97, 97, 97,235, 97, + 236,237, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, + 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, + 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, + 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, + 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, + 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 3, 2, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, + 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, + 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, @@ -4557,7 +4601,7 @@ _hb_ucd_u8[17198] = 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, - 2, 2, 2, 2, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, + 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, @@ -4573,76 +4617,75 @@ _hb_ucd_u8[17198] = 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 20, 20, - 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, - 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 2, - 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, - 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2, - 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, - 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18, - 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, - 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, - 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25, - 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, - 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2, - 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12, - 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, - 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, - 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30, - 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2, - 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 2, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2, - 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32, - 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2, - 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28, - 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2, - 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58, - 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91, - 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91, - 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 2, 62, 62, - 62, 62, 62, 2, 2, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, - 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, - 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, - 73, 73, 73, 73, 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8, - 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19, - 19, 19, 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, - 9, 19, 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 9, 1, 1, 2, 1, 1, 1, 1, 1, 9, 9, - 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9, - 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, - 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19, - 19, 19, 19, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, + 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, + 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, + 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2, + 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, + 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, + 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, + 18, 18, 18, 2, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, + 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, + 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, + 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, + 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, + 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, + 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 45, 45, 45, 45, + 45, 45, 45, 2, 2, 2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, + 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32, + 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48, + 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52, + 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58, + 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91, + 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 2, 2, 2, 2, 62, 62, 62, 62, 62, 2, 2, 2, 76, 76, + 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70, + 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, + 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2, + 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, + 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 1, 1, + 2, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, + 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, + 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, - 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 56, 56, + 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2, @@ -4656,44 +4699,46 @@ _hb_ucd_u8[17198] = 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 2, 26, 26, 26, 2, 2, 2, 2, 2, 12, 12, - 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39, + 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, + 17, 17, 17, 17, 17, 0, 13, 13, 13, 13, 13, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, - 0, 19, 19, 19, 19, 19, 2, 2, 19, 19, 19, 19, 19, 2, 2, 2, - 2, 2, 2, 2, 2, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 65, 65, - 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, - 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12, - 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, - 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68, - 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 30, - 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 9, 19, 19, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, + 0, 19, 19, 19, 19, 19, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, + 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, + 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, + 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, + 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, - 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 6, 6, 0, 0, - 0, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, - 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, - 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49, - 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0, - 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 9, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, + 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3, + 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, + 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, + 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, + 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, @@ -4737,31 +4782,33 @@ _hb_ucd_u8[17198] = 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130, 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144, 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 2,147,147,147,147,147,147,147,147,148,148, - 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,149,149, - 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94, - 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, - 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2, - 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 2,111,111,111,111,111,111,111,111,111,111, - 111,111,111,111,111, 2,100,100,100,100,100,100,100,100,100,100, - 100,100,100,100, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108, - 2,108,108,108,108,108,108,108,108,108,108,108,108, 2,129,129, - 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129, - 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129, - 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, - 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107, - 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2, - 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2, - 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107, - 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2, - 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107, - 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137, - 137,137,137,137,137,137,137,137, 2,137, 2,137,137,137,124,124, + 3, 3, 3, 3, 3, 2,156,156,156,156,156,156,156,156,156,156, + 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2,147,147, + 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148, + 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153, + 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, + 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101, + 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, + 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108, + 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108, + 108,108,108,108,108, 2,129,129,129,129,129,129,129, 2,129, 2, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109, + 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109, + 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107, + 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107, + 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2, + 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2, + 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, + 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107, + 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137, + 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124, 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123, 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114, 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114, @@ -4771,22 +4818,26 @@ _hb_ucd_u8[17198] = 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,142,142, 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125, 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2,125,150,150,150,150,150,150,150,150, 2, 2, - 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141, - 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140, - 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2, - 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2, - 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133, - 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134, - 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134, 2,134, - 134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138,138, - 138,138,138,138,138, 2,138,138, 2,138,138,138,138,138,138,138, - 138,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138,138, - 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2, - 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, - 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2, - 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145, - 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2, 22, 22, + 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, + 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2, + 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150, + 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150, + 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140, + 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121, + 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2,133,133, + 133,133,133,133,133,133,133, 2,133,133,133,133,133,133,133,133, + 133,133,133,133,133, 2,133,133,133,133,133,133, 2, 2,133,133, + 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134, 2, 2, + 134,134,134,134,134,134, 2,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138, + 2,138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, + 138, 2,138,138, 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143, + 143,143,143,143, 2,143,143, 2,143,143,143,143,143,143,143,143, + 143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143,143, + 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, + 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145, 2, + 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, @@ -4800,19 +4851,20 @@ _hb_ucd_u8[17198] = 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146, 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, - 2, 2, 2, 2, 2, 99,136,139, 0, 0, 2, 2, 2, 2,136,136, - 136,136,136,136,136,136,136,136,136, 2, 2, 2, 2, 2, 17, 15, + 2, 2, 2, 2, 2, 99,136,139, 0, 0,155, 2, 2, 2,136,136, + 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155, + 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139, 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, 105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 0, 0, - 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, - 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131, @@ -4824,90 +4876,93 @@ _hb_ucd_u8[17198] = 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,113,113, 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132, - 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 0, 0, - 0, 0, 0, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, - 3, 2, 3, 2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 2, 2, 2, 2, 2, 2, - 3, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 2, 3, - 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 2, 3, 2, 3, 3, - 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 3, - 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 15, 0, - 0, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 0, 0, 13, 13, - 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 2, 2, 2, 13, 2, - 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 16, 50, - 84,118, 88, 89, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 91, 85, 85, - 220, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 94, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, - 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, - 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, - 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, - 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, - 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0, - 109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0, - 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129, - 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145, - 146,147,148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158, - 159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0, - 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,168,169, 0, 0, 0, 0,170,171, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172,173, - 174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189, - 190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3, + 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 13, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, + 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, + 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, + 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, + 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, + 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, + 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, + 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0, + 107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, + 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124, + 125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,128,129,130,131,132,133,134,135,136,137,138,139, + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155, + 156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, + 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171, + 172, 0, 0, 0,173,174,175,176,177,178,179,180,181,182,183,184, + 185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, + 201,202,203,204,205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, }; static const uint16_t -_hb_ucd_u16[8944] = +_hb_ucd_u16[9080] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -4917,557 +4972,566 @@ _hb_ucd_u16[8944] = 13, 13, 13, 42, 9, 43, 11, 11, 44, 45, 32, 46, 47, 48, 49, 50, 51, 52, 48, 48, 53, 32, 54, 55, 48, 48, 48, 48, 48, 56, 57, 58, 59, 60, 48, 32, 61, 48, 48, 48, 48, 48, 62, 63, 64, 48, 65, 66, - 48, 67, 68, 69, 48, 70, 71, 72, 72, 72, 48, 73, 72, 74, 75, 32, - 76, 48, 48, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 83, 84, 91, 92, 93, 94, 95, 96, 97, 84, 98, 99, 100, 88, 101, - 102, 83, 84, 103, 104, 105, 88, 106, 107, 108, 109, 110, 111, 112, 94, 113, - 114, 115, 84, 116, 117, 118, 88, 119, 120, 115, 84, 121, 122, 123, 88, 124, - 125, 115, 48, 126, 127, 128, 88, 129, 130, 131, 48, 132, 133, 134, 94, 135, - 136, 48, 48, 137, 138, 139, 72, 72, 140, 48, 141, 142, 143, 144, 72, 72, - 145, 146, 147, 148, 149, 48, 150, 151, 152, 153, 32, 154, 155, 156, 72, 72, - 48, 48, 157, 158, 159, 160, 161, 162, 163, 164, 9, 9, 165, 11, 11, 166, - 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 167, 168, 48, 48, - 167, 48, 48, 169, 170, 171, 48, 48, 48, 170, 48, 48, 48, 172, 173, 174, - 48, 175, 9, 9, 9, 9, 9, 176, 177, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 178, 48, 179, 180, 48, 48, 48, 48, 181, 182, - 183, 184, 48, 185, 48, 186, 183, 187, 48, 48, 48, 188, 189, 190, 191, 192, - 193, 191, 48, 48, 194, 48, 48, 195, 196, 48, 197, 48, 48, 48, 48, 198, - 48, 199, 200, 201, 202, 48, 203, 204, 48, 48, 205, 48, 206, 207, 208, 208, - 48, 209, 48, 48, 48, 210, 211, 212, 191, 191, 213, 214, 72, 72, 72, 72, - 215, 48, 48, 216, 217, 159, 218, 219, 220, 48, 221, 64, 48, 48, 222, 223, - 48, 48, 224, 225, 226, 64, 48, 227, 228, 9, 9, 229, 230, 231, 232, 233, - 11, 11, 234, 27, 27, 27, 235, 236, 11, 237, 27, 27, 32, 32, 32, 238, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 239, 13, 13, 13, 13, 13, 13, - 240, 241, 240, 240, 241, 242, 240, 243, 244, 244, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 260, 72, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 270, 271, 272, 273, 208, 274, 275, 208, 276, - 277, 277, 277, 277, 277, 277, 277, 277, 278, 208, 279, 208, 208, 208, 208, 280, - 208, 281, 277, 282, 208, 283, 284, 208, 208, 208, 285, 72, 286, 72, 269, 269, - 269, 287, 208, 208, 208, 208, 288, 269, 208, 208, 208, 208, 208, 208, 208, 208, - 208, 208, 208, 289, 290, 208, 208, 291, 208, 208, 208, 208, 208, 208, 292, 208, - 208, 208, 208, 208, 208, 208, 293, 294, 269, 295, 208, 208, 296, 277, 297, 277, - 298, 299, 277, 277, 277, 300, 277, 301, 208, 208, 208, 277, 302, 208, 208, 303, - 208, 304, 208, 208, 208, 208, 208, 208, 9, 9, 305, 11, 11, 306, 307, 308, - 13, 13, 13, 13, 13, 13, 309, 310, 11, 11, 311, 48, 48, 48, 312, 313, - 48, 314, 315, 315, 315, 315, 32, 32, 316, 317, 318, 319, 320, 72, 72, 72, - 208, 321, 208, 208, 208, 208, 208, 322, 208, 208, 208, 208, 208, 323, 72, 324, - 325, 326, 327, 328, 136, 48, 48, 48, 48, 329, 177, 48, 48, 48, 48, 330, - 331, 48, 48, 136, 48, 48, 48, 48, 199, 332, 48, 71, 208, 208, 322, 48, - 208, 333, 334, 208, 335, 336, 208, 208, 334, 208, 208, 336, 208, 208, 208, 208, - 48, 48, 48, 198, 208, 208, 208, 208, 48, 48, 48, 48, 48, 48, 48, 72, - 48, 337, 48, 48, 48, 48, 48, 48, 150, 208, 208, 208, 285, 48, 48, 227, - 338, 48, 339, 72, 13, 13, 340, 341, 13, 342, 48, 48, 48, 48, 343, 344, - 31, 345, 346, 347, 13, 13, 13, 348, 349, 350, 351, 352, 353, 72, 72, 354, - 355, 48, 356, 357, 48, 48, 48, 358, 359, 48, 48, 360, 361, 191, 32, 362, - 64, 48, 363, 48, 364, 365, 48, 150, 76, 48, 48, 366, 367, 368, 369, 370, - 48, 48, 371, 372, 373, 374, 48, 375, 48, 48, 48, 376, 377, 378, 379, 380, - 381, 382, 315, 11, 11, 383, 384, 11, 11, 11, 11, 11, 48, 48, 385, 191, - 48, 48, 386, 48, 387, 48, 48, 205, 388, 388, 388, 388, 388, 388, 388, 388, - 389, 389, 389, 389, 389, 389, 389, 389, 48, 48, 48, 48, 48, 48, 203, 48, - 48, 48, 48, 48, 48, 206, 72, 72, 390, 391, 392, 393, 394, 48, 48, 48, - 48, 48, 48, 395, 396, 397, 48, 48, 48, 48, 48, 398, 72, 48, 48, 48, - 48, 399, 48, 48, 400, 72, 72, 401, 32, 402, 32, 403, 404, 405, 406, 407, + 48, 67, 68, 69, 48, 70, 71, 72, 72, 72, 48, 73, 74, 75, 76, 32, + 77, 48, 48, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 84, 85, 92, 93, 94, 95, 96, 97, 98, 85, 99, 100, 101, 89, 102, + 103, 84, 85, 104, 105, 106, 89, 107, 108, 109, 110, 111, 112, 113, 95, 114, + 115, 116, 85, 117, 118, 119, 89, 120, 121, 116, 85, 122, 123, 124, 89, 125, + 126, 116, 48, 127, 128, 129, 89, 130, 131, 132, 48, 133, 134, 135, 95, 136, + 137, 48, 48, 138, 139, 140, 72, 72, 141, 48, 142, 143, 144, 145, 72, 72, + 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 72, 72, + 48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 168, 169, 48, 48, + 168, 48, 48, 170, 171, 172, 48, 48, 48, 171, 48, 48, 48, 173, 174, 175, + 48, 176, 9, 9, 9, 9, 9, 177, 178, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183, + 184, 185, 48, 186, 48, 187, 184, 188, 48, 48, 48, 189, 190, 191, 192, 193, + 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199, + 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209, + 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 72, 72, 72, + 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225, + 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235, + 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 240, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 241, 13, 13, 13, 13, 13, 13, + 242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262, 72, 263, 264, 216, + 265, 266, 267, 268, 269, 270, 271, 271, 272, 273, 274, 209, 275, 276, 209, 277, + 278, 278, 278, 278, 278, 278, 278, 278, 279, 209, 280, 209, 209, 209, 209, 281, + 209, 282, 278, 283, 209, 284, 285, 209, 209, 209, 286, 72, 287, 72, 270, 270, + 270, 288, 209, 209, 209, 209, 289, 270, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 290, 291, 209, 209, 292, 209, 209, 209, 209, 209, 209, 293, 209, + 209, 209, 209, 209, 209, 209, 294, 295, 270, 296, 209, 209, 297, 278, 298, 278, + 299, 300, 278, 278, 278, 301, 278, 302, 209, 209, 209, 278, 303, 209, 209, 304, + 209, 305, 209, 209, 209, 209, 209, 209, 9, 9, 306, 11, 11, 307, 308, 309, + 13, 13, 13, 13, 13, 13, 310, 311, 11, 11, 312, 48, 48, 48, 313, 314, + 48, 315, 316, 316, 316, 316, 32, 32, 317, 318, 319, 320, 321, 322, 72, 72, + 209, 323, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 325, 72, 326, + 327, 328, 329, 330, 137, 48, 48, 48, 48, 331, 178, 48, 48, 48, 48, 332, + 333, 48, 48, 137, 48, 48, 48, 48, 200, 334, 48, 48, 209, 209, 324, 48, + 209, 335, 336, 209, 337, 338, 209, 209, 336, 209, 209, 338, 209, 209, 209, 209, + 48, 48, 48, 48, 209, 209, 209, 209, 48, 48, 48, 48, 48, 48, 48, 151, + 48, 339, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 286, 48, 48, 229, + 340, 48, 341, 72, 13, 13, 342, 343, 13, 344, 48, 48, 48, 48, 345, 346, + 31, 347, 348, 349, 13, 13, 13, 350, 351, 352, 353, 354, 355, 72, 72, 356, + 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364, + 64, 48, 365, 48, 366, 367, 48, 151, 77, 48, 48, 368, 369, 370, 371, 372, + 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382, + 383, 384, 316, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192, + 48, 48, 388, 48, 389, 48, 48, 206, 390, 390, 390, 390, 390, 390, 390, 390, + 391, 391, 391, 391, 391, 391, 391, 391, 48, 48, 48, 48, 48, 48, 204, 48, + 48, 48, 48, 48, 48, 207, 72, 72, 392, 393, 394, 395, 396, 48, 48, 48, + 48, 48, 48, 397, 398, 399, 48, 48, 48, 48, 48, 400, 72, 48, 48, 48, + 48, 401, 48, 48, 74, 72, 72, 402, 32, 403, 32, 404, 405, 406, 407, 73, 48, 48, 48, 48, 48, 48, 48, 408, 409, 2, 3, 4, 5, 410, 411, 412, - 48, 413, 48, 199, 414, 415, 416, 417, 418, 48, 171, 419, 203, 203, 72, 72, - 48, 48, 48, 48, 48, 48, 48, 71, 420, 269, 269, 421, 270, 270, 270, 422, - 423, 324, 424, 72, 72, 208, 208, 425, 72, 72, 72, 72, 72, 72, 72, 72, - 48, 150, 48, 48, 48, 100, 426, 427, 48, 48, 428, 48, 429, 48, 48, 430, - 48, 431, 48, 48, 432, 433, 72, 72, 9, 9, 434, 11, 11, 48, 48, 48, - 48, 203, 191, 9, 9, 435, 11, 436, 48, 48, 400, 48, 48, 48, 437, 72, - 48, 48, 48, 314, 48, 198, 400, 72, 438, 48, 48, 439, 48, 440, 48, 441, - 48, 199, 442, 72, 72, 72, 48, 443, 48, 444, 48, 445, 72, 72, 72, 72, - 48, 48, 48, 446, 269, 447, 269, 269, 448, 449, 48, 450, 451, 452, 48, 453, - 48, 454, 72, 72, 455, 48, 456, 457, 48, 48, 48, 458, 48, 459, 48, 460, - 48, 461, 462, 72, 72, 72, 72, 72, 48, 48, 48, 48, 195, 72, 72, 72, - 9, 9, 9, 463, 11, 11, 11, 464, 48, 48, 465, 191, 72, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 269, 466, 48, 454, 467, 48, 62, 468, 72, 72, - 72, 72, 72, 72, 72, 72, 48, 314, 469, 48, 48, 470, 471, 447, 472, 473, - 220, 48, 48, 474, 475, 48, 195, 191, 476, 48, 477, 478, 479, 48, 48, 480, - 220, 48, 48, 481, 482, 483, 484, 485, 48, 97, 486, 487, 72, 72, 72, 72, - 488, 489, 490, 48, 48, 491, 492, 191, 493, 83, 84, 494, 495, 496, 497, 498, - 48, 48, 48, 499, 500, 501, 72, 72, 48, 48, 48, 502, 503, 191, 72, 72, - 48, 48, 504, 505, 506, 507, 72, 72, 48, 48, 48, 508, 509, 191, 510, 72, - 48, 48, 511, 512, 191, 72, 72, 72, 48, 172, 513, 514, 72, 72, 72, 72, - 48, 48, 486, 515, 72, 72, 72, 72, 72, 72, 9, 9, 11, 11, 147, 516, - 72, 72, 517, 48, 48, 518, 519, 72, 520, 48, 48, 521, 522, 523, 48, 48, - 524, 525, 526, 72, 48, 48, 48, 195, 84, 48, 504, 527, 528, 147, 174, 529, - 48, 530, 531, 532, 72, 72, 72, 72, 533, 48, 48, 534, 535, 191, 536, 48, - 537, 538, 191, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 539, - 72, 72, 72, 72, 269, 540, 541, 542, 48, 206, 72, 72, 72, 72, 72, 72, - 270, 270, 270, 270, 270, 270, 543, 544, 48, 48, 48, 48, 386, 72, 72, 72, - 48, 48, 199, 545, 72, 72, 72, 72, 48, 48, 48, 48, 314, 72, 72, 72, - 48, 48, 48, 195, 48, 199, 368, 72, 72, 72, 72, 72, 72, 48, 203, 546, - 48, 48, 48, 547, 548, 549, 550, 551, 48, 72, 72, 72, 72, 72, 72, 72, - 72, 72, 72, 72, 9, 9, 11, 11, 269, 552, 72, 72, 72, 72, 72, 72, - 48, 48, 48, 48, 553, 554, 555, 555, 556, 557, 72, 72, 72, 72, 558, 72, - 48, 48, 48, 48, 48, 48, 48, 400, 48, 48, 48, 48, 48, 48, 48, 559, - 48, 199, 72, 72, 72, 559, 560, 48, 48, 48, 48, 48, 48, 48, 48, 205, - 48, 48, 48, 48, 48, 48, 71, 150, 195, 561, 562, 72, 72, 72, 72, 72, - 208, 208, 208, 208, 208, 208, 208, 323, 208, 208, 563, 208, 208, 208, 564, 565, - 566, 208, 567, 208, 208, 208, 568, 72, 208, 208, 208, 208, 569, 72, 72, 72, - 72, 72, 72, 72, 72, 72, 269, 570, 208, 208, 208, 208, 208, 285, 269, 451, - 9, 571, 11, 572, 573, 574, 240, 9, 575, 576, 577, 578, 579, 9, 571, 11, - 580, 581, 11, 582, 583, 584, 585, 9, 586, 11, 9, 571, 11, 572, 573, 11, - 240, 9, 575, 585, 9, 586, 11, 9, 571, 11, 587, 9, 588, 589, 590, 591, - 11, 592, 9, 593, 594, 595, 596, 11, 597, 9, 598, 11, 599, 600, 600, 600, - 32, 32, 32, 601, 32, 32, 602, 603, 604, 605, 45, 72, 72, 72, 72, 72, - 606, 607, 608, 72, 72, 72, 72, 72, 48, 48, 150, 609, 610, 72, 72, 72, - 72, 72, 72, 72, 48, 48, 611, 612, 48, 48, 48, 48, 613, 614, 72, 72, - 9, 9, 575, 11, 615, 368, 72, 72, 72, 72, 72, 72, 72, 72, 72, 484, - 269, 269, 616, 617, 72, 72, 72, 72, 484, 269, 618, 619, 72, 72, 72, 72, - 620, 48, 621, 622, 623, 624, 625, 626, 627, 205, 628, 205, 72, 72, 72, 629, - 208, 208, 324, 208, 208, 208, 208, 208, 208, 322, 333, 630, 630, 630, 208, 323, - 174, 208, 208, 208, 208, 208, 631, 208, 208, 208, 631, 72, 72, 72, 632, 208, - 633, 208, 208, 324, 568, 634, 323, 72, 208, 208, 208, 208, 208, 208, 208, 635, - 208, 208, 208, 208, 208, 323, 631, 286, 208, 208, 208, 208, 208, 208, 208, 322, - 208, 208, 208, 208, 208, 568, 324, 72, 324, 208, 208, 208, 636, 175, 208, 208, - 636, 208, 637, 72, 72, 72, 72, 72, 638, 208, 208, 208, 208, 208, 208, 639, - 208, 208, 640, 208, 641, 208, 208, 208, 208, 208, 208, 208, 208, 322, 637, 642, - 633, 323, 72, 72, 72, 72, 72, 72, 48, 48, 48, 48, 48, 314, 72, 72, - 48, 48, 48, 204, 48, 48, 48, 48, 48, 203, 48, 48, 48, 48, 48, 48, - 48, 48, 643, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 72, - 48, 203, 72, 72, 72, 72, 72, 72, 644, 72, 645, 645, 645, 645, 645, 645, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 72, - 389, 389, 389, 389, 389, 389, 389, 646, 389, 389, 389, 389, 389, 389, 389, 647, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, - 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11, - 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14, - 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21, - 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26, - 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31, - 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31, - 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43, - 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 26, 26, - 26, 26, 26, 26, 31, 31, 50, 51, 26, 26, 52, 31, 53, 31, 31, 31, - 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 54, 56, 54, 54, 54, - 57, 58, 59, 60, 60, 61, 62, 63, 58, 64, 65, 66, 67, 60, 60, 68, - 69, 70, 71, 72, 72, 73, 74, 75, 70, 76, 77, 78, 79, 72, 80, 26, - 81, 82, 83, 84, 84, 85, 86, 87, 82, 88, 89, 26, 90, 84, 91, 92, - 93, 94, 95, 96, 96, 97, 98, 99, 94, 100, 101, 102, 103, 96, 96, 26, - 104, 105, 106, 107, 108, 105, 109, 110, 105, 106, 111, 26, 112, 109, 109, 113, - 114, 115, 116, 114, 114, 116, 114, 117, 115, 118, 119, 120, 121, 114, 122, 114, - 123, 124, 125, 123, 123, 125, 126, 127, 124, 128, 129, 130, 131, 123, 132, 26, - 133, 134, 135, 136, 136, 136, 136, 136, 134, 135, 137, 136, 138, 136, 136, 136, - 139, 140, 141, 142, 140, 140, 143, 144, 141, 145, 146, 140, 147, 140, 148, 26, - 149, 150, 150, 150, 150, 150, 150, 151, 150, 150, 150, 152, 26, 26, 26, 26, - 153, 154, 155, 155, 156, 155, 155, 157, 158, 157, 155, 159, 26, 26, 26, 26, - 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 160, 160, 160, 162, 161, 160, - 160, 160, 160, 161, 160, 160, 160, 163, 160, 163, 164, 165, 26, 26, 26, 26, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 167, 167, 167, 167, 168, 169, 167, 167, 167, 167, 167, 170, - 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 173, 174, 173, 172, 172, 172, 172, - 172, 173, 172, 172, 172, 172, 173, 174, 173, 172, 174, 172, 172, 172, 172, 172, - 172, 172, 173, 172, 172, 172, 172, 172, 172, 172, 172, 175, 172, 172, 172, 176, - 172, 172, 172, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, - 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, - 181, 181, 181, 182, 183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 183, 185, - 186, 187, 188, 26, 189, 189, 190, 26, 191, 191, 192, 26, 193, 194, 195, 26, - 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 197, 196, 198, 196, 198, - 199, 200, 201, 202, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 203, - 201, 201, 201, 201, 201, 204, 180, 180, 180, 180, 180, 180, 180, 180, 205, 26, - 206, 206, 206, 207, 206, 208, 206, 208, 209, 206, 210, 210, 210, 211, 212, 26, - 213, 213, 213, 213, 213, 214, 213, 213, 213, 215, 213, 216, 196, 196, 196, 196, - 217, 217, 217, 218, 219, 219, 219, 219, 219, 219, 219, 220, 219, 219, 219, 221, - 219, 222, 219, 222, 219, 223, 9, 224, 26, 26, 26, 26, 26, 26, 26, 26, - 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 225, 225, 225, 225, 225, 227, - 228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 230, 231, - 232, 232, 232, 232, 232, 232, 232, 233, 232, 234, 235, 235, 235, 235, 235, 235, - 18, 236, 167, 167, 167, 167, 167, 237, 228, 26, 238, 9, 239, 240, 241, 242, - 2, 2, 2, 2, 243, 244, 2, 2, 2, 2, 2, 245, 246, 247, 2, 248, - 2, 2, 2, 2, 2, 2, 2, 249, 9, 9, 9, 9, 9, 9, 9, 250, - 14, 14, 251, 251, 14, 14, 14, 14, 251, 251, 14, 252, 14, 14, 14, 251, - 14, 14, 14, 14, 14, 14, 253, 14, 253, 14, 254, 255, 14, 14, 256, 257, - 0, 258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 260, 261, - 0, 262, 2, 263, 0, 0, 0, 0, 26, 26, 9, 9, 9, 9, 264, 26, - 0, 0, 0, 0, 265, 266, 4, 0, 0, 267, 0, 0, 2, 2, 2, 2, - 2, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 262, 26, 26, 26, 0, 269, 26, 26, 0, 0, 0, 0, - 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271, 0, - 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 273, 273, 273, 273, 273, 274, 273, 273, 273, 273, 273, 274, 2, 2, 2, 2, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 275, 276, - 167, 167, 167, 167, 168, 169, 277, 277, 277, 277, 277, 277, 277, 278, 279, 278, - 172, 172, 174, 26, 174, 174, 174, 174, 174, 174, 174, 174, 18, 18, 18, 18, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, - 280, 280, 280, 281, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 282, 26, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 283, 26, 26, 26, 0, 284, - 285, 0, 0, 0, 286, 287, 0, 288, 289, 290, 290, 290, 290, 290, 290, 290, - 290, 290, 291, 292, 293, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 295, - 296, 297, 297, 297, 297, 297, 298, 171, 171, 171, 171, 171, 171, 171, 171, 171, - 171, 299, 0, 0, 297, 297, 297, 300, 0, 0, 0, 0, 284, 26, 294, 294, - 171, 171, 171, 299, 0, 0, 0, 0, 0, 0, 0, 0, 171, 171, 171, 301, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 294, 294, 294, 294, 294, 302, - 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 0, 0, 0, 0, 0, - 280, 280, 280, 280, 280, 280, 283, 26, 0, 0, 0, 0, 0, 0, 0, 0, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 26, 26, - 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, - 303, 304, 303, 303, 303, 303, 303, 303, 305, 26, 306, 306, 306, 306, 306, 306, - 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, - 307, 307, 307, 307, 307, 308, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 18, 18, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 26, - 0, 0, 0, 0, 310, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 311, 2, 2, 2, 2, 2, 2, 312, 26, 26, 26, 26, 26, 313, 2, - 314, 314, 314, 314, 314, 315, 0, 316, 317, 317, 317, 317, 317, 317, 317, 26, - 318, 318, 318, 318, 318, 318, 318, 318, 319, 320, 318, 321, 54, 54, 54, 54, - 322, 322, 322, 322, 322, 323, 324, 324, 324, 324, 325, 326, 171, 171, 171, 327, - 328, 328, 328, 328, 328, 328, 328, 328, 328, 329, 328, 330, 166, 166, 166, 331, - 332, 332, 332, 332, 332, 332, 333, 26, 332, 334, 332, 335, 166, 166, 166, 166, - 336, 336, 336, 336, 336, 336, 336, 336, 337, 26, 26, 338, 339, 339, 340, 26, - 341, 341, 341, 26, 174, 174, 2, 2, 2, 2, 2, 342, 343, 26, 178, 178, - 178, 178, 178, 178, 178, 178, 178, 178, 339, 339, 339, 339, 339, 344, 339, 345, - 171, 171, 171, 171, 346, 26, 171, 171, 299, 347, 171, 171, 171, 171, 171, 346, + 48, 413, 48, 200, 414, 415, 416, 417, 418, 48, 172, 419, 204, 204, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 71, 420, 270, 270, 421, 271, 271, 271, 422, + 423, 424, 425, 72, 72, 209, 209, 426, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 151, 48, 48, 48, 101, 427, 428, 48, 48, 429, 48, 430, 48, 48, 431, + 48, 432, 48, 48, 433, 434, 72, 72, 9, 9, 435, 11, 11, 48, 48, 48, + 48, 204, 192, 9, 9, 436, 11, 437, 48, 48, 74, 48, 48, 48, 438, 72, + 48, 48, 48, 315, 48, 199, 74, 72, 439, 48, 48, 440, 48, 441, 48, 442, + 48, 200, 443, 72, 72, 72, 48, 444, 48, 445, 48, 446, 72, 72, 72, 72, + 48, 48, 48, 447, 270, 448, 270, 270, 449, 450, 48, 451, 452, 453, 48, 454, + 48, 455, 72, 72, 456, 48, 457, 458, 48, 48, 48, 459, 48, 460, 48, 461, + 48, 462, 463, 72, 72, 72, 72, 72, 48, 48, 48, 48, 196, 72, 72, 72, + 9, 9, 9, 464, 11, 11, 11, 465, 48, 48, 466, 192, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 270, 467, 48, 48, 468, 469, 72, 72, 72, 72, + 48, 455, 470, 48, 62, 471, 72, 72, 72, 72, 72, 48, 472, 72, 48, 315, + 473, 48, 48, 474, 475, 448, 476, 477, 222, 48, 48, 478, 479, 48, 196, 192, + 480, 48, 481, 482, 483, 48, 48, 484, 222, 48, 48, 485, 486, 487, 488, 489, + 48, 98, 490, 491, 72, 72, 72, 72, 492, 493, 494, 48, 48, 495, 496, 192, + 497, 84, 85, 498, 499, 500, 501, 502, 48, 48, 48, 503, 504, 505, 469, 72, + 48, 48, 48, 506, 507, 192, 72, 72, 48, 48, 508, 509, 510, 511, 72, 72, + 48, 48, 48, 512, 513, 192, 514, 72, 48, 48, 515, 516, 192, 72, 72, 72, + 48, 173, 517, 518, 72, 72, 72, 72, 48, 48, 490, 519, 72, 72, 72, 72, + 72, 72, 9, 9, 11, 11, 148, 520, 521, 522, 48, 523, 524, 192, 72, 72, + 72, 72, 525, 48, 48, 526, 527, 72, 528, 48, 48, 529, 530, 531, 48, 48, + 532, 533, 534, 72, 48, 48, 48, 196, 85, 48, 508, 535, 536, 148, 175, 537, + 48, 538, 539, 540, 72, 72, 72, 72, 541, 48, 48, 542, 543, 192, 544, 48, + 545, 546, 192, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 547, + 72, 72, 72, 101, 270, 548, 549, 550, 48, 207, 72, 72, 72, 72, 72, 72, + 271, 271, 271, 271, 271, 271, 551, 552, 48, 48, 48, 48, 388, 72, 72, 72, + 48, 48, 200, 553, 72, 72, 72, 72, 48, 48, 48, 48, 315, 72, 72, 72, + 48, 48, 48, 196, 48, 200, 370, 72, 72, 72, 72, 72, 72, 48, 204, 554, + 48, 48, 48, 555, 556, 557, 558, 559, 48, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 9, 9, 11, 11, 270, 560, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 561, 562, 563, 563, 564, 565, 72, 72, 72, 72, 566, 567, + 48, 48, 48, 48, 48, 48, 48, 74, 48, 48, 48, 48, 48, 199, 72, 72, + 196, 72, 72, 72, 72, 72, 72, 72, 48, 200, 72, 72, 72, 568, 569, 48, + 48, 48, 48, 48, 48, 48, 48, 206, 48, 48, 48, 48, 48, 48, 71, 151, + 196, 570, 571, 72, 72, 72, 72, 72, 209, 209, 209, 209, 209, 209, 209, 325, + 209, 209, 572, 209, 209, 209, 573, 574, 575, 209, 576, 209, 209, 209, 577, 72, + 209, 209, 209, 209, 578, 72, 72, 72, 72, 72, 72, 72, 72, 72, 270, 579, + 209, 209, 209, 209, 209, 286, 270, 452, 9, 580, 11, 581, 582, 583, 242, 9, + 584, 585, 586, 587, 588, 9, 580, 11, 589, 590, 11, 591, 592, 593, 594, 9, + 595, 11, 9, 580, 11, 581, 582, 11, 242, 9, 584, 594, 9, 595, 11, 9, + 580, 11, 596, 9, 597, 598, 599, 600, 11, 601, 9, 602, 603, 604, 605, 11, + 606, 9, 607, 11, 608, 609, 609, 609, 32, 32, 32, 610, 32, 32, 611, 612, + 613, 614, 45, 72, 72, 72, 72, 72, 615, 616, 617, 72, 72, 72, 72, 72, + 48, 48, 151, 618, 619, 72, 72, 72, 72, 72, 72, 72, 48, 48, 620, 621, + 48, 48, 48, 48, 622, 623, 72, 72, 9, 9, 584, 11, 624, 370, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 488, 270, 270, 625, 626, 72, 72, 72, 72, + 488, 270, 627, 628, 72, 72, 72, 72, 629, 48, 630, 631, 632, 633, 634, 635, + 636, 206, 637, 206, 72, 72, 72, 638, 209, 209, 326, 209, 209, 209, 209, 209, + 209, 324, 335, 639, 639, 639, 209, 325, 640, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 641, 72, 72, 72, 642, 209, 643, 209, 209, 326, 577, 644, 325, 72, + 209, 209, 209, 209, 209, 209, 209, 645, 209, 209, 209, 209, 209, 646, 424, 424, + 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 577, 326, 72, + 326, 209, 209, 209, 646, 176, 209, 209, 646, 209, 641, 644, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 647, 209, 209, 209, 209, 648, 209, 209, 209, + 209, 209, 209, 209, 209, 324, 641, 649, 286, 209, 577, 286, 643, 286, 72, 72, + 209, 650, 209, 209, 287, 72, 72, 192, 48, 48, 48, 48, 48, 204, 72, 72, + 48, 48, 48, 205, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, + 48, 48, 469, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 101, 72, + 48, 204, 72, 72, 72, 72, 72, 72, 48, 48, 48, 48, 71, 72, 72, 72, + 651, 72, 652, 652, 652, 652, 652, 652, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 72, 391, 391, 391, 391, 391, 391, 391, 653, + 391, 391, 391, 391, 391, 391, 391, 654, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4, + 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, + 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14, + 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21, + 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25, + 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31, + 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37, + 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26, + 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46, + 47, 47, 47, 48, 37, 49, 26, 26, 26, 26, 26, 26, 31, 31, 50, 31, + 31, 26, 51, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62, + 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74, + 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86, + 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, + 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109, + 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116, + 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126, + 123, 127, 128, 129, 130, 122, 131, 26, 132, 133, 134, 132, 132, 132, 132, 132, + 133, 134, 135, 132, 136, 132, 132, 132, 137, 138, 139, 140, 138, 138, 141, 142, + 139, 143, 144, 138, 145, 138, 146, 26, 147, 148, 148, 148, 148, 148, 148, 149, + 148, 148, 148, 150, 26, 26, 26, 26, 151, 152, 153, 153, 154, 153, 153, 155, + 156, 155, 153, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, + 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, + 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172, + 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170, + 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 182, 181, 183, 184, 185, 186, 26, 187, 187, 188, 26, + 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 199, 200, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 201, 199, 199, 199, 199, 199, 202, 178, 178, + 178, 178, 178, 178, 178, 178, 203, 26, 204, 204, 204, 205, 204, 206, 204, 206, + 207, 204, 208, 208, 208, 209, 210, 26, 211, 211, 211, 211, 211, 212, 211, 211, + 211, 213, 211, 214, 194, 194, 194, 194, 215, 215, 215, 216, 217, 217, 217, 217, + 217, 217, 217, 218, 217, 217, 217, 219, 217, 220, 217, 220, 217, 221, 9, 9, + 222, 26, 26, 26, 26, 26, 26, 26, 223, 223, 223, 223, 223, 223, 223, 223, + 223, 224, 223, 223, 223, 223, 223, 225, 226, 226, 226, 226, 226, 226, 226, 226, + 227, 227, 227, 227, 227, 227, 228, 229, 230, 230, 230, 230, 230, 230, 230, 231, + 230, 232, 233, 233, 233, 233, 233, 233, 18, 234, 165, 165, 165, 165, 165, 235, + 226, 26, 236, 9, 237, 238, 239, 240, 2, 2, 2, 2, 241, 242, 2, 2, + 2, 2, 2, 243, 244, 245, 2, 246, 2, 2, 2, 2, 2, 2, 2, 247, + 9, 9, 9, 9, 9, 9, 9, 248, 14, 14, 249, 249, 14, 14, 14, 14, + 249, 249, 14, 250, 14, 14, 14, 249, 14, 14, 14, 14, 14, 14, 251, 14, + 251, 14, 252, 253, 14, 14, 254, 255, 0, 256, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 257, 0, 258, 259, 0, 260, 2, 261, 0, 0, 0, 0, + 26, 26, 9, 9, 9, 9, 222, 26, 0, 0, 0, 0, 262, 263, 4, 0, + 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 26, 26, 26, + 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 271, 270, 270, + 270, 270, 270, 271, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 272, 273, 165, 165, 165, 165, 166, 167, 274, 274, + 274, 274, 274, 274, 274, 275, 276, 275, 170, 170, 172, 26, 172, 172, 172, 172, + 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 266, 26, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285, + 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291, + 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294, + 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0, + 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291, + 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, + 0, 0, 0, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 299, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 301, 300, 300, 300, 300, 300, 300, + 302, 26, 303, 303, 303, 303, 303, 303, 304, 304, 304, 304, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 26, 26, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 306, 306, 306, 306, + 306, 306, 306, 306, 306, 306, 306, 26, 0, 0, 0, 0, 307, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 308, 2, 2, 2, 2, 2, 2, + 309, 310, 26, 26, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314, + 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316, + 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322, + 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326, + 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26, + 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334, + 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2, + 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169, + 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352, + 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 354, 26, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 355, + 26, 26, 31, 31, 31, 31, 31, 31, 31, 31, 356, 31, 31, 31, 31, 31, + 31, 26, 26, 26, 26, 26, 31, 357, 9, 9, 0, 314, 9, 358, 0, 0, + 0, 0, 359, 0, 260, 281, 50, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 360, 361, 0, 0, 0, 1, 2, 2, 3, + 1, 2, 2, 3, 362, 291, 290, 291, 291, 291, 291, 363, 169, 169, 169, 296, + 364, 364, 364, 365, 260, 260, 26, 366, 367, 368, 367, 367, 369, 367, 367, 370, + 367, 371, 367, 371, 26, 26, 26, 26, 367, 367, 367, 367, 367, 367, 367, 367, + 367, 367, 367, 367, 367, 367, 367, 372, 373, 0, 0, 0, 0, 0, 374, 0, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 255, 0, 375, 376, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 377, 378, 378, 378, 379, 380, 380, 380, 380, + 380, 380, 381, 26, 382, 0, 0, 281, 383, 383, 383, 383, 384, 385, 386, 386, + 386, 387, 388, 388, 388, 388, 388, 389, 390, 390, 390, 391, 392, 392, 392, 392, + 393, 392, 394, 26, 26, 26, 26, 26, 395, 395, 395, 395, 395, 395, 395, 395, + 395, 395, 396, 396, 396, 396, 396, 396, 397, 397, 397, 398, 397, 399, 400, 400, + 400, 400, 401, 400, 400, 400, 400, 401, 402, 402, 402, 402, 402, 26, 403, 403, + 403, 403, 403, 403, 404, 405, 26, 26, 406, 406, 406, 406, 406, 406, 406, 406, + 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 407, 26, + 406, 406, 408, 26, 406, 26, 26, 26, 409, 410, 411, 411, 411, 411, 412, 413, + 414, 414, 415, 414, 416, 416, 416, 416, 417, 417, 417, 418, 419, 417, 26, 26, + 26, 26, 26, 26, 420, 420, 421, 422, 423, 423, 423, 424, 425, 425, 425, 426, + 26, 26, 26, 26, 26, 26, 26, 26, 427, 427, 427, 427, 428, 428, 428, 429, + 428, 428, 430, 428, 428, 428, 428, 428, 431, 432, 433, 434, 435, 435, 436, 437, + 435, 438, 435, 438, 439, 439, 439, 439, 440, 440, 440, 440, 26, 26, 26, 26, + 441, 441, 441, 441, 442, 443, 442, 26, 444, 444, 444, 444, 444, 444, 445, 446, + 447, 447, 448, 447, 449, 449, 450, 449, 451, 451, 452, 453, 26, 454, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 455, 455, 455, 455, 455, 455, 455, 455, + 455, 456, 26, 26, 26, 26, 26, 26, 457, 457, 457, 457, 457, 457, 458, 26, + 457, 457, 457, 457, 457, 457, 458, 459, 460, 460, 460, 460, 460, 26, 460, 461, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 283, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 348, 26, 26, 26, 26, - 349, 26, 350, 351, 25, 25, 352, 353, 354, 25, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 355, 26, 52, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 356, 26, 26, 31, 31, 31, 31, 31, 31, - 31, 31, 357, 31, 31, 31, 31, 31, 31, 26, 26, 26, 26, 26, 31, 51, - 9, 9, 0, 316, 9, 358, 0, 0, 0, 0, 359, 0, 262, 284, 50, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 360, - 361, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 362, 294, 293, 294, - 294, 294, 294, 363, 171, 171, 171, 299, 364, 364, 364, 365, 262, 262, 26, 366, - 367, 368, 367, 367, 369, 367, 367, 370, 367, 371, 367, 371, 26, 26, 26, 26, - 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 367, 372, - 373, 0, 0, 0, 0, 0, 374, 0, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 257, 0, 284, 375, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 376, - 377, 377, 377, 378, 379, 379, 379, 379, 379, 379, 380, 26, 381, 0, 0, 284, - 382, 382, 382, 382, 383, 384, 385, 385, 385, 386, 387, 387, 387, 387, 387, 388, - 389, 389, 389, 390, 391, 391, 391, 391, 392, 391, 393, 26, 26, 26, 26, 26, - 394, 394, 394, 394, 394, 394, 394, 394, 394, 394, 395, 395, 395, 395, 395, 395, - 396, 396, 396, 397, 396, 398, 399, 399, 399, 399, 400, 399, 399, 399, 399, 400, - 401, 401, 401, 401, 401, 26, 402, 402, 402, 402, 402, 402, 403, 404, 26, 26, - 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, 405, - 405, 405, 405, 405, 405, 405, 406, 26, 405, 405, 407, 26, 405, 26, 26, 26, - 408, 409, 410, 410, 410, 410, 411, 412, 413, 413, 414, 413, 415, 415, 415, 415, - 416, 416, 416, 417, 418, 416, 26, 26, 26, 26, 26, 26, 419, 419, 420, 421, - 422, 422, 422, 423, 424, 424, 424, 425, 26, 26, 26, 26, 26, 26, 26, 26, - 426, 426, 426, 426, 427, 427, 427, 428, 427, 427, 429, 427, 427, 427, 427, 427, - 430, 431, 432, 433, 434, 434, 435, 436, 434, 437, 434, 437, 438, 438, 438, 438, - 439, 439, 439, 439, 26, 26, 26, 26, 440, 440, 440, 440, 441, 442, 441, 26, - 443, 443, 443, 443, 443, 443, 444, 445, 446, 446, 447, 446, 448, 448, 449, 448, - 450, 450, 451, 452, 26, 453, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 454, 454, 454, 454, 454, 454, 454, 454, 454, 455, 26, 26, 26, 26, 26, 26, - 456, 456, 456, 456, 456, 456, 457, 26, 456, 456, 456, 456, 456, 456, 457, 458, - 459, 459, 459, 459, 459, 26, 459, 460, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 461, - 462, 462, 462, 462, 462, 26, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 465, 465, 466, 26, - 467, 467, 467, 467, 467, 467, 467, 467, 467, 468, 469, 467, 467, 467, 26, 470, - 471, 471, 471, 471, 471, 471, 471, 471, 472, 473, 474, 474, 474, 475, 474, 476, - 477, 477, 477, 477, 477, 477, 478, 477, 479, 26, 480, 480, 480, 480, 481, 26, - 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 482, 482, 484, 140, 485, 26, - 486, 486, 487, 486, 486, 486, 486, 488, 26, 26, 26, 26, 26, 26, 26, 26, - 489, 490, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 494, 495, 494, 496, - 497, 498, 499, 500, 500, 501, 502, 503, 498, 504, 505, 506, 507, 508, 508, 26, - 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 509, 510, 26, 26, 26, 26, - 511, 511, 511, 511, 511, 511, 511, 511, 511, 26, 511, 512, 26, 26, 26, 26, - 513, 513, 513, 513, 513, 513, 514, 513, 513, 513, 513, 514, 26, 26, 26, 26, - 515, 515, 515, 515, 515, 515, 515, 515, 516, 26, 515, 517, 201, 518, 26, 26, - 519, 519, 519, 519, 519, 519, 519, 520, 519, 521, 26, 26, 26, 26, 26, 26, - 522, 522, 522, 523, 522, 524, 522, 522, 26, 26, 26, 26, 26, 26, 26, 26, - 525, 525, 525, 525, 525, 525, 525, 526, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 528, 529, - 26, 26, 26, 26, 530, 531, 530, 530, 530, 530, 530, 531, 532, 26, 26, 26, - 533, 533, 533, 533, 533, 533, 533, 533, 533, 26, 534, 534, 534, 534, 534, 534, - 534, 534, 534, 534, 535, 26, 26, 26, 536, 536, 536, 536, 536, 536, 536, 537, - 538, 539, 538, 538, 538, 538, 540, 538, 541, 26, 538, 538, 538, 542, 543, 543, - 543, 543, 544, 543, 543, 545, 546, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 547, 548, 549, 549, 549, 549, 547, 550, 549, 26, 549, 551, 552, 553, 554, 554, - 554, 555, 556, 557, 554, 558, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 559, 559, 559, 560, - 26, 26, 26, 26, 26, 26, 26, 26, 109, 109, 109, 109, 109, 109, 561, 562, - 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, - 563, 563, 563, 564, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 563, 565, 566, 26, - 563, 563, 563, 563, 563, 563, 563, 563, 567, 26, 26, 26, 26, 26, 26, 26, - 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, 568, - 568, 568, 568, 568, 568, 569, 568, 570, 26, 26, 26, 26, 26, 26, 26, 26, - 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, - 571, 571, 571, 571, 571, 571, 571, 571, 572, 26, 26, 26, 26, 26, 26, 26, - 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, - 309, 309, 309, 309, 309, 309, 309, 573, 574, 574, 574, 575, 574, 576, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 577, 577, 577, 578, 578, 26, - 579, 579, 579, 579, 579, 579, 579, 579, 580, 26, 579, 581, 581, 579, 579, 582, - 579, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 583, 583, 583, 583, 583, 583, 583, 583, - 583, 583, 583, 584, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 585, 585, 585, 585, 585, 585, 585, 585, 585, 586, 585, 585, 585, 585, 585, 585, - 585, 587, 585, 585, 26, 26, 26, 26, 26, 26, 26, 26, 588, 26, 26, 26, - 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, - 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 26, - 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 589, 590, 26, - 591, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, - 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, - 290, 290, 290, 291, 26, 26, 26, 26, 26, 26, 592, 26, 593, 26, 594, 594, - 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, - 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 595, - 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 596, 598, - 596, 599, 596, 600, 284, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 26, - 0, 0, 0, 0, 262, 361, 0, 0, 0, 0, 0, 0, 601, 602, 0, 603, - 604, 605, 0, 0, 0, 606, 0, 0, 0, 0, 0, 0, 0, 607, 26, 26, - 14, 14, 14, 14, 14, 14, 14, 14, 251, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 284, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 262, 26, 0, 0, 0, 607, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 0, - 0, 0, 0, 259, 608, 609, 0, 610, 611, 0, 0, 0, 0, 0, 0, 0, - 612, 613, 259, 259, 0, 0, 0, 614, 615, 616, 617, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, 0, - 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, - 618, 619, 26, 620, 621, 618, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 274, 273, 273, 622, 623, 624, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 625, 625, 625, 625, 625, 626, 625, 627, 625, 628, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 629, 629, 629, 629, 629, 629, 629, 630, - 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, - 631, 631, 631, 631, 631, 631, 631, 631, 632, 631, 633, 26, 26, 26, 26, 26, - 634, 634, 634, 634, 634, 634, 634, 634, 634, 635, 634, 636, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 361, 0, - 0, 0, 0, 0, 0, 0, 637, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 361, 0, 0, 0, 0, 0, 0, 272, 26, 26, 26, 26, 26, 26, 26, 26, - 638, 31, 31, 31, 639, 640, 641, 642, 643, 644, 639, 645, 639, 641, 641, 646, - 31, 647, 31, 648, 649, 647, 31, 648, 26, 26, 26, 26, 26, 26, 355, 26, - 0, 0, 0, 0, 0, 284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 284, 26, 0, 262, 361, 0, 361, 0, 361, 0, 0, 0, 272, 26, - 0, 637, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 637, 0, 0, - 0, 0, 0, 0, 0, 637, 26, 26, 26, 26, 26, 26, 650, 0, 0, 0, - 651, 26, 0, 0, 0, 0, 0, 284, 0, 607, 316, 26, 272, 26, 26, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, 26, 0, 637, 0, 269, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 26, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 607, 0, 284, 26, 26, - 0, 284, 0, 0, 0, 0, 0, 0, 0, 26, 0, 316, 0, 0, 0, 0, - 0, 26, 0, 0, 0, 272, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 0, 611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 614, 616, - 0, 0, 0, 0, 613, 652, 0, 0, 0, 613, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 284, 26, 0, 272, 284, 269, - 269, 26, 272, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 653, 26, 26, 26, 26, 26, - 280, 280, 280, 280, 280, 280, 654, 26, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 283, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 348, 26, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 655, 26, 26, 26, - 280, 280, 280, 283, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 656, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 26, 26, 26, 26, 31, 31, 31, 462, 463, 463, 463, 463, 463, 464, 465, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 26, 467, 467, + 467, 467, 467, 468, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 469, 469, + 469, 470, 26, 26, 471, 471, 472, 26, 473, 473, 473, 473, 473, 473, 473, 473, + 473, 474, 475, 473, 473, 473, 26, 476, 477, 477, 477, 477, 477, 477, 477, 477, + 478, 479, 480, 480, 480, 481, 480, 482, 483, 483, 483, 483, 483, 483, 484, 483, + 483, 26, 485, 485, 485, 485, 486, 26, 487, 487, 487, 487, 487, 487, 487, 487, + 487, 487, 487, 487, 488, 138, 489, 26, 490, 490, 491, 490, 490, 490, 490, 492, + 26, 26, 26, 26, 26, 26, 26, 26, 493, 494, 495, 496, 495, 497, 498, 498, + 498, 498, 498, 498, 498, 499, 498, 500, 501, 502, 503, 504, 504, 505, 506, 507, + 502, 508, 509, 510, 511, 512, 512, 26, 513, 513, 513, 513, 513, 513, 513, 513, + 513, 513, 513, 514, 515, 26, 26, 26, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 26, 516, 517, 26, 26, 26, 26, 518, 518, 518, 518, 518, 518, 519, 518, + 518, 518, 518, 519, 26, 26, 26, 26, 520, 520, 520, 520, 520, 520, 520, 520, + 521, 26, 520, 522, 199, 523, 26, 26, 524, 524, 524, 524, 524, 524, 524, 525, + 524, 526, 26, 26, 26, 26, 26, 26, 527, 527, 527, 528, 527, 529, 527, 527, + 26, 26, 26, 26, 26, 26, 26, 26, 530, 530, 530, 530, 530, 530, 530, 531, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 532, 532, 532, 532, + 532, 532, 532, 532, 532, 532, 533, 534, 535, 536, 537, 538, 538, 538, 539, 540, + 535, 26, 538, 541, 26, 26, 26, 26, 26, 26, 26, 26, 542, 543, 542, 542, + 542, 542, 542, 543, 544, 26, 26, 26, 545, 545, 545, 545, 545, 545, 545, 545, + 545, 26, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 547, 26, 26, 26, + 548, 548, 548, 548, 548, 548, 548, 549, 550, 551, 550, 550, 550, 550, 552, 550, + 553, 26, 550, 550, 550, 554, 555, 555, 555, 555, 556, 555, 555, 557, 558, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 559, 560, 561, 561, 561, 561, 559, 562, + 561, 26, 561, 563, 564, 565, 566, 566, 566, 567, 568, 569, 566, 570, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 571, 571, 571, 572, 26, 26, 26, 26, 26, 26, 573, 26, + 108, 108, 108, 108, 108, 108, 574, 575, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 577, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 576, 578, 579, 26, 576, 576, 576, 576, 576, 576, 576, 576, + 580, 26, 26, 26, 26, 26, 26, 26, 581, 581, 581, 581, 581, 581, 581, 581, + 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 582, 581, 583, + 26, 26, 26, 26, 26, 26, 26, 26, 584, 584, 584, 584, 584, 584, 584, 584, + 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, + 585, 26, 26, 26, 26, 26, 26, 26, 306, 306, 306, 306, 306, 306, 306, 306, + 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 586, + 587, 587, 587, 588, 587, 589, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 590, 590, 590, 591, 591, 26, 592, 592, 592, 592, 592, 592, 592, 592, + 593, 26, 592, 594, 594, 592, 592, 595, 592, 592, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 598, 598, 598, 598, 598, 598, 598, 598, + 598, 599, 598, 598, 598, 598, 598, 598, 598, 600, 598, 598, 26, 26, 26, 26, + 26, 26, 26, 26, 601, 26, 347, 26, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 26, 603, 603, 603, 603, 603, 603, 603, 603, + 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, + 603, 603, 604, 26, 26, 26, 26, 26, 602, 605, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 606, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 26, 26, 26, 26, + 26, 26, 607, 26, 608, 26, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, + 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, + 609, 609, 609, 609, 609, 609, 609, 610, 611, 611, 611, 611, 611, 611, 611, 611, + 611, 611, 611, 611, 611, 612, 611, 613, 611, 614, 611, 615, 281, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 616, 26, 0, 0, 0, 0, 260, 361, 0, 0, + 0, 0, 0, 0, 617, 618, 0, 619, 620, 621, 0, 0, 0, 622, 0, 0, + 0, 0, 0, 0, 0, 623, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14, + 249, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 260, 26, 0, 0, 0, 623, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 257, 624, 625, 0, 626, + 627, 0, 0, 0, 0, 0, 0, 0, 269, 628, 257, 257, 0, 0, 0, 629, + 630, 631, 632, 0, 0, 0, 0, 0, 0, 0, 0, 0, 616, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 268, 0, 0, 0, 0, 0, 0, 633, 633, 633, 633, 633, 633, 633, 633, + 633, 633, 633, 633, 633, 633, 633, 633, 633, 634, 26, 635, 636, 633, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 271, 270, 270, 637, 638, 639, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 640, 640, 640, 640, 640, 641, 640, 642, + 640, 643, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 644, 644, 644, 644, 644, 644, 644, 645, 646, 646, 646, 646, 646, 646, 646, 646, + 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, + 647, 646, 648, 26, 26, 26, 26, 26, 649, 649, 649, 649, 649, 649, 649, 649, + 649, 650, 649, 651, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 361, 0, 0, 0, 0, 0, 0, 0, 375, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 361, 0, 0, 0, 0, 0, 0, 616, + 26, 26, 26, 26, 26, 26, 26, 26, 652, 31, 31, 31, 653, 654, 655, 656, + 657, 658, 653, 659, 653, 655, 655, 660, 31, 661, 31, 662, 663, 661, 31, 662, + 26, 26, 26, 26, 26, 26, 354, 26, 0, 0, 0, 0, 0, 281, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 260, 361, 0, + 361, 0, 361, 0, 0, 0, 616, 26, 0, 0, 0, 0, 0, 616, 26, 26, + 26, 26, 26, 26, 664, 0, 0, 0, 665, 26, 0, 0, 0, 0, 0, 281, + 0, 623, 314, 26, 616, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 0, 375, 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 623, 0, 281, 26, 26, 0, 281, 0, 0, 0, 0, 0, 0, + 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 616, 314, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 632, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 281, 26, 0, 616, 375, 266, 260, 26, 0, 0, 0, 623, 260, 26, + 266, 26, 260, 26, 26, 26, 26, 26, 0, 0, 359, 0, 0, 0, 0, 0, + 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 280, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 299, 26, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 666, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 667, 26, 26, 26, 26, 26, 26, 668, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, + 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, + 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147, + 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, + 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, + 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, + 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0, + 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, + 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035, + 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250, + 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0, + 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299, + 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, - 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, - 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, - 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, - 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, - 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, - 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, - 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, - 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, - 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, - 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, - 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, - 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, - 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010, - 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, - 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, - 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, - 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, - 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, - 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, - 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, - 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486, - 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, - 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, - 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, - 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, - 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, - 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, - 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, - 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, - 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, - 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, - 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, - 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, - 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, - 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, - 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, - 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, - 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, - 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, - 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, - 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, - 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, - 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, - 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, - 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, - 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, - 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, - 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, - 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, - 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, - 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, - 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, - 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, - 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, - 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, - 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, - 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, - 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, - 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, - 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, - 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, - 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, - 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, - 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, - 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, - 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, - 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, - 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, - 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, - 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, - 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, - 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, - 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, - 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, - 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, - 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, - 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, - 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, - 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, - 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, - 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, - 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, - 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, - 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, - 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, - 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, - 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, - 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, - 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, - 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, - 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, - 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, - 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, - 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, - 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, - 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, - 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, - 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, - 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, - 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, - 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, - 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, - 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, - 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, - 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, - 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, - 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, - 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, - 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, - 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, - 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, - 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, - 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, - 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, - 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, - 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1948,1949, - 1950,1951,1952,1953,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956,1957,1959,1958, - 1960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, - 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, - 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, - 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, - 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, - 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, - 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, - 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, - 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, - 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, - 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, - 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, - 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, - 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, - 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, - 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, - 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, - 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, - 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, - 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, - 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, - 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, - 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, - 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, - 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, - 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, - 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, - 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, - 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, - 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, - 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, - 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, - 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, - 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340, + 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177, + 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0, + 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165, + 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279, + 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, + 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5, + 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, + 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, + 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, + 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, + 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0, + 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648, + 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, + 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0, + 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, + 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0, + 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142, + 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, + 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, + 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210, + 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222, + 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243, + 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389, + 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284, + 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291, + 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260, + 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343, + 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, + 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698, + 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359, + 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274, + 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304, + 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707, + 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0, + 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743, + 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770, + 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0, + 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, + 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800, + 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24, + 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714, + 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750, + 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807, + 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825, + 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829, + 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515, + 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518, + 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830, + 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, + 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, + 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, + 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0, + 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0, + 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, + 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0, + 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, + 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, + 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0, + 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, + 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, + 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929, + 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, + 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, + 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, + 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, + 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, + 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, + 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, + 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, + 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, + 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, + 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, + 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, + 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, + 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, + 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, + 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, + 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, + 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, + 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, + 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, + 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, + 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, + 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, + 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, + 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, + 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, + 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, + 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, + 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, + 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, + 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0, + 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599, + 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, + 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, + 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, + 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, + 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, + 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, + 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, + 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, + 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, + 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, + 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, + 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, + 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, + 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, + 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, + 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, + 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, + 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, + 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, + 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, + 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, + 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, + 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, + 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, + 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, + 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, + 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, + 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, + 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, + 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, + 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, + 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, + 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, + 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, + 817, 818, 819, 820, 821, 935, 0, 0, }; static const int16_t _hb_ucd_i16[196] = @@ -5490,12 +5554,12 @@ _hb_ucd_i16[196] = static inline uint_fast8_t _hb_ucd_gc (unsigned u) { - return u<1114110u?_hb_ucd_u8[6432+(((_hb_ucd_u8[1248+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114110u?_hb_ucd_u8[6504+(((_hb_ucd_u8[1264+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; } static inline uint_fast8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[8640+(((_hb_ucd_u8[7704+(((_hb_ucd_u8[7048+(((_hb_ucd_u8[6802+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0; + return u<125259u?_hb_ucd_u8[8768+(((_hb_ucd_u8[7792+(((_hb_ucd_u8[7120+(((_hb_ucd_u8[6874+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0; } static inline unsigned _hb_ucd_b4 (const uint8_t* a, unsigned i) @@ -5505,28 +5569,29 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i) static inline int_fast16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9372+(((_hb_ucd_u8[9252+(((_hb_ucd_b4(9124+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9508+(((_hb_ucd_u8[9388+(((_hb_ucd_b4(9260+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; } static inline uint_fast8_t _hb_ucd_sc (unsigned u) { - return u<918000u?_hb_ucd_u8[10822+(((_hb_ucd_u16[1920+(((_hb_ucd_u8[10150+(((_hb_ucd_u8[9700+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; + return u<918000u?_hb_ucd_u8[10974+(((_hb_ucd_u16[1960+(((_hb_ucd_u8[10286+(((_hb_ucd_u8[9836+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; } static inline uint_fast16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[5648+(((_hb_ucd_u8[16174+(((_hb_ucd_b4(16078+_hb_ucd_u8,u>>4>>6))<<6)+((u>>4)&63u))])<<4)+((u)&15u))]:0; + return u<195102u?_hb_ucd_u16[5768+(((_hb_ucd_u8[16708+(((_hb_ucd_u8[16326+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; } #else static const uint8_t -_hb_ucd_u8[13072] = +_hb_ucd_u8[13344] = { 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 6, 5, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 5, 17, 15, 15, 18, 15, 19, 20, 21, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 23, + 5, 24, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, @@ -5537,8 +5602,7 @@ _hb_ucd_u8[13072] = 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 24, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 25, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -5562,34 +5626,36 @@ _hb_ucd_u8[13072] = 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, 100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108, 34, 34,109,110,111,112,113,114,115,116,117,111, 34, 34, 34,111, - 118,119,120,121,122,123,124,125, 34,126,127,111,128,111,129, 34, - 130,131,132,133,134,135,136,111,137,138,111,139,140,141,142,111, - 143,144,111,145,146,147,111,111,148,149,150,151,111,152,111,153, - 34, 34, 34, 34, 34, 34, 34, 34,154, 34, 34,111,111,111,111,111, + 118,119,120,121,122,123,124,125, 34,126,127,111,128,129,130,131, + 132,133,134,135,136,137,138,111,139,140,111,141,142,143,144,111, + 145,146,147,148,149,150,111,111,151,152,153,154,111,155,111,156, + 34, 34, 34, 34, 34, 34, 34, 34,157, 34, 34,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34, 34, 34, 34, 34,155,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34, 34, 34, 34,158,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34,156,157,158, 34,111,111,111,111,159,160,161,162, + 34, 34, 34, 34,159,160,161, 34,111,111,111,111,162,163,164,165, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111, - 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111, - 111,111,111,111,111,111,111,111, 34,163,111,111,111,111,111,111, - 67, 67,164,165,166,128, 65,111,167,168,169,170,171,172,173,174, - 67, 67, 67, 67,175,176,111,111,111,111,111,111,111,111,111,111, - 177,111,178,111,111,179,111,111,111,111,111,111,111,111,111,111, - 34,180,181,111,111,111,111,111,128,182,183,111, 34,184,111,111, - 67, 67,185, 67, 67,111, 67,186, 67, 67, 67, 67, 67, 67, 67, 67, - 67, 67, 67, 67, 67, 67,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 34,166,111,111,111,111,111,111, + 67, 67,167,168,169,128, 65,111,170,171,172,173,174,175,176,177, + 67, 67, 67, 67,178,179,111,111,111,111,111,111,111,111,111,111, + 180,111,181,111,111,182,111,111,111,111,111,111,111,111,111,111, + 34,183,184,111,111,111,111,111,128,185,186,111, 34,187,111,111, + 67, 67,188, 67, 67,111, 67,189, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67,190,111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111, - 187,111,177,177,111,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 191,111,180,180,111,111,111,111,111,111,111,111,111,111,111,111, 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, @@ -5646,9 +5712,9 @@ _hb_ucd_u8[13072] = 43, 43, 43, 43, 36, 36, 36, 36, 7, 7, 7, 82, 27, 27, 27, 81, 63, 75, 65, 36, 36, 36, 36, 36, 75, 75, 75, 74, 75, 75, 43, 43, 43, 43, 74, 75, 75, 75, 75, 36, 83, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 63, 64, 75, 76, 43, 43, 75, 75, 75, 76, 70, - 61, 61, 36, 79, 27, 27, 27, 84, 27, 27, 27, 27, 81, 36, 36, 36, - 75, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 74, + 43, 75, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 75, + 76, 43, 43, 75, 75, 75, 76, 70, 61, 61, 36, 79, 27, 27, 27, 84, + 27, 27, 27, 27, 81, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 74, 75, 43, 43, 43, 75, 75, 75, 75, 7, 75, 2, 2, 2, 2, 2, 2, 63, 36, 43, 43, 43, 43, 43, 85, 36, 36, 36, 68, 43, 43, 43, 57, 7, 7, 7, 7, 7, 2, 2, 2, 63, 36, 43, 43, 43, 43, 64, 36, @@ -5676,51 +5742,51 @@ _hb_ucd_u8[13072] = 61, 61, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 27, 27, 61, 36, 36, 36, 63, 74, 76, 43, 2, 36, 36, 79, 74, 43, 43, 43, 43, 74, 74, 76, 43, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 43, 43, - 2, 2, 2, 77, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 48, - 48, 48, 48, 48, 48, 48, 48, 48, 43, 43, 78, 36, 36, 36, 36, 36, - 36, 36, 74, 43, 43, 74, 74, 75, 75, 74, 78, 36, 36, 36, 36, 36, - 86, 61, 61, 61, 61, 47, 43, 43, 43, 43, 61, 61, 61, 61, 61, 61, - 43, 78, 36, 36, 36, 36, 36, 36, 79, 43, 43, 75, 43, 76, 43, 36, - 36, 36, 36, 74, 43, 75, 76, 76, 43, 75, 75, 75, 75, 75, 2, 2, - 36, 36, 75, 75, 75, 75, 43, 43, 43, 43, 75, 43, 43, 57, 2, 2, - 7, 7, 7, 7, 7, 7, 83, 36, 36, 36, 36, 36, 40, 40, 40, 2, - 43, 57, 43, 43, 43, 43, 43, 43, 74, 43, 43, 43, 64, 36, 63, 36, - 36, 36, 64, 79, 43, 36, 36, 36, 16, 16, 16, 16, 16, 16, 40, 40, - 40, 40, 40, 40, 40, 44, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, - 16, 16, 16, 16, 16, 96, 40, 40, 32, 32, 32, 16, 16, 16, 16, 32, - 16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 16, 34, 11, 11, 11, - 16, 16, 16, 16, 97, 97, 97, 97, 16, 16, 16, 16, 11, 11, 98, 99, - 41, 16, 16, 16, 11, 11, 98, 41, 16, 16, 16, 16, 11, 11,100, 41, - 101,101,101,101,101,102, 59, 59, 51, 51, 51, 2,103,104,103,104, - 2, 2, 2, 2,105, 59, 59,106, 2, 2, 2, 2,107,108, 2,109, - 110, 2,111,112, 2, 2, 2, 2, 2, 9,110, 2, 2, 2, 2,113, - 59, 59, 59, 59, 59, 59, 59, 59,114, 40, 27, 27, 27, 8,111,115, - 27, 27, 27, 27, 27, 8,111, 91, 20, 20, 20, 20, 20, 20, 20, 20, - 43, 43, 43, 43, 43, 43,116, 48,117, 48,117, 43, 43, 43, 43, 43, - 61,118, 61,119, 61, 34, 11, 16, 11, 32,119, 61, 46, 11, 11, 61, - 61, 61,118,118,118, 11, 11,120, 11, 11, 35, 36, 39, 61, 16, 11, - 8, 8, 46, 16, 16, 26, 61,121, 92, 92, 92, 92, 92, 92, 92, 92, - 92,122,123, 92,124, 61, 61, 61, 8, 8,125, 61, 61, 8, 61, 61, - 125, 26, 61,125, 61, 61, 61,125, 61, 61, 61, 61, 61, 61, 61, 8, - 61,125,125, 61, 61, 61, 61, 61, 61, 61, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 61, 61, 61, 61, 4, 4, 61, 61, - 8, 61, 61, 61,126,127, 61, 61, 61, 61, 61, 61, 61, 61,125, 61, - 61, 61, 61, 61, 61, 26, 8, 8, 8, 8, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 8, 8, 8, 61, 61, 61, 61, 61, 61, 61, - 27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, - 61, 61, 61, 26, 61, 61, 61, 61, 26, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 8, 8, 8, 8, 61, 61, 61, 61, 61, 61, 61, 26, - 61, 61, 61, 61, 4, 4, 4, 4, 4, 4, 4, 27, 27, 27, 27, 27, - 27, 27, 61, 61, 61, 61, 61, 61, 8, 8,111,128, 8, 8, 8, 8, - 8, 8, 8, 4, 4, 4, 4, 4, 8,111,129,129,129,129,129,129, - 129,129,129,129,128, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8, - 8, 8, 8, 8, 8, 8, 4, 8, 8, 8,125, 26, 8, 8,125, 61, - 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11, - 32, 32,121, 61, 61,119, 34,130, 43, 32, 16, 16, 50, 2, 87, 2, - 36, 36, 36, 36, 36, 36, 36, 95, 2, 2, 2, 2, 2, 2, 2, 56, - 2,103,103, 2,107,108,103, 2, 2, 2, 2, 6, 2, 94,103, 2, - 103, 4, 4, 4, 4, 2, 2, 77, 2, 2, 2, 2, 2, 51, 2, 2, - 94,131, 2, 2, 2, 2, 2, 2, 1, 2,132,133, 4, 4, 4, 4, + 2, 2, 2, 77, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 96, + 43, 43, 78, 36, 36, 36, 36, 36, 36, 36, 74, 43, 43, 74, 74, 75, + 75, 74, 78, 36, 36, 36, 36, 36, 86, 61, 61, 61, 61, 47, 43, 43, + 43, 43, 61, 61, 61, 61, 61, 61, 43, 78, 36, 36, 36, 36, 36, 36, + 79, 43, 43, 75, 43, 76, 43, 36, 36, 36, 36, 74, 43, 75, 76, 76, + 43, 75, 75, 75, 75, 75, 2, 2, 36, 36, 75, 75, 75, 75, 43, 43, + 43, 43, 75, 43, 43, 57, 2, 2, 7, 7, 7, 7, 7, 7, 83, 36, + 36, 36, 36, 36, 40, 40, 40, 2, 43, 57, 43, 43, 43, 43, 43, 43, + 74, 43, 43, 43, 64, 36, 63, 36, 36, 36, 64, 79, 43, 36, 36, 36, + 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 44, 16, 16, + 16, 16, 16, 16, 44, 16, 16, 16, 16, 16, 16, 16, 16, 97, 40, 40, + 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11, + 16, 16, 16, 16, 34, 11, 11, 11, 16, 16, 16, 16, 98, 98, 98, 98, + 16, 16, 16, 16, 11, 11, 99,100, 41, 16, 16, 16, 11, 11, 99, 41, + 16, 16, 16, 16, 11, 11,101, 41,102,102,102,102,102,103, 59, 59, + 51, 51, 51, 2,104,105,104,105, 2, 2, 2, 2,106, 59, 59,107, + 2, 2, 2, 2,108,109, 2,110,111, 2,112,113, 2, 2, 2, 2, + 2, 9,111, 2, 2, 2, 2,114, 59, 59, 59, 59, 59, 59, 59, 59, + 115, 40, 27, 27, 27, 8,112,116, 27, 27, 27, 27, 27, 8,112, 91, + 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,117, 48, + 96, 48, 96, 43, 43, 43, 43, 43, 61,118, 61,119, 61, 34, 11, 16, + 11, 32,119, 61, 46, 11, 11, 61, 61, 61,118,118,118, 11, 11,120, + 11, 11, 35, 36, 39, 61, 16, 11, 8, 8, 46, 16, 16, 26, 61,121, + 92, 92, 92, 92, 92, 92, 92, 92, 92,122,123, 92,124, 61, 61, 61, + 8, 8,125, 61, 61, 8, 61, 61,125, 26, 61,125, 61, 61, 61,125, + 61, 61, 61, 61, 61, 61, 61, 8, 61,125,125, 61, 61, 61, 61, 61, + 61, 61, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 61, 61, 61, 61, 4, 4, 61, 61, 8, 61, 61, 61,126,127, 61, 61, + 61, 61, 61, 61, 61, 61,125, 61, 61, 61, 61, 61, 61, 26, 8, 8, + 8, 8, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 8, 8, + 8, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 27, 61, 61, + 61, 61, 61, 61, 61, 27, 27, 27, 61, 61, 61, 26, 61, 61, 61, 61, + 26, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 8, 8, 8, 8, + 61, 61, 61, 61, 61, 61, 61, 26, 61, 61, 61, 61, 4, 4, 4, 4, + 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, + 8, 8,112,128, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, + 8,112,129,129,129,129,129,129,129,129,129,129,128, 8, 8, 8, + 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, + 8, 8,125, 26, 8, 8,125, 61, 32, 11, 32, 34, 34, 34, 34, 11, + 32, 32, 34, 16, 16, 16, 40, 11, 32, 32,121, 61, 61,119, 34,130, + 43, 32, 16, 16, 50, 2, 87, 2, 36, 36, 36, 36, 36, 36, 36, 95, + 2, 2, 2, 2, 2, 2, 2, 56, 2,104,104, 2,108,109,104, 2, + 2, 2, 2, 6, 2, 94,104, 2,104, 4, 4, 4, 4, 2, 2, 77, + 2, 2, 2, 2, 2, 51, 2, 2, 94,131, 2, 2, 2, 2, 2, 2, + 61, 2, 2, 2, 2, 2, 2, 2, 1, 2,132,133, 4, 4, 4, 4, 4, 61, 4, 4, 4, 4,134, 91,135, 92, 92, 92, 92, 43, 43, 75, 136, 40, 40, 61, 92,137, 58, 61, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63,138,139, 62, 36, 36, 36, 36, 36, 58, 40, 62, @@ -5733,99 +5799,102 @@ _hb_ucd_u8[13072] = 41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 44, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,143, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32, - 11, 11, 32, 32, 32, 32, 32, 32, 16, 32, 11, 11, 11, 11, 11, 11, - 11, 11, 11,144, 40, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36, - 36, 79, 76, 74, 61, 61, 61, 61, 27, 27, 27, 61,145, 61, 61, 61, + 11, 11, 32, 32, 32, 32, 32, 32, 16, 32, 11, 11, 34, 16, 16, 16, + 16, 16, 34, 35, 40, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36, + 36, 79, 76, 74, 61, 61, 43, 43, 27, 27, 27, 61,144, 61, 61, 61, 36, 36, 2, 2, 2, 2, 2, 2, 75, 36, 36, 36, 36, 36, 36, 36, 36, 36, 75, 75, 75, 75, 75, 75, 75, 75, 43, 43, 43, 43, 43, 2, 43, 36, 36, 36, 2, 65, 65, 63, 36, 36, 36, 43, 43, 43, 43, 2, - 36, 36, 36, 63, 43, 43, 43, 43, 43, 75, 75, 75, 75, 75, 75,146, - 36, 63, 75, 43, 43, 75, 43, 75,146, 2, 2, 2, 2, 2, 2, 77, + 36, 36, 36, 63, 43, 43, 43, 43, 43, 75, 75, 75, 75, 75, 75,145, + 36, 63, 75, 43, 43, 75, 43, 75,145, 2, 2, 2, 2, 2, 2, 77, 7, 7, 7, 7, 7, 7, 7, 2, 36, 36, 63, 62, 36, 36, 36, 36, 36, 36, 36, 36, 63, 43, 43, 74, 76, 74, 76, 43, 43, 43, 43, 43, 36, 63, 36, 36, 36, 36, 74, 75, 7, 7, 7, 7, 7, 7, 2, 2, 62, 36, 36, 70, 61, 79, 74, 36, 64, 43, 64, 63, 64, 36, 36, 43, 36, 36, 36, 36, 36, 36, 95, 2, 36, 36, 36, 36, 36, 79, 43, 75, - 2, 95,147, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16, 99, 40, 40, - 36, 79, 76, 75, 74,146, 76, 43,148,148,148,148,148,148,148,148, - 149,149,149,149,149,149,149,149, 16, 16, 16, 16, 16, 16, 35, 64, - 36, 36, 36, 36,150, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41, - 41,151, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,129, - 152,152,152,152,152,152,152,152, 36, 36, 36, 36, 36, 36,145, 61, - 2, 2, 2,153,112, 2, 2, 2, 6,154,155,129,129,129,129,129, - 129,129,112,153,112, 2,109,156, 2, 2, 2, 2,134,129,129,112, - 2,157, 8, 8, 60, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36,158, - 2, 2, 3, 2, 4, 5, 6, 2, 16, 16, 16, 16, 16, 17, 18,111, - 112, 4, 2, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 40, 20,159, 53, 20, 26, 8,125, 61, - 61, 61, 61, 61,160, 59, 61, 61, 2, 2, 2, 87, 27, 27, 27, 27, - 27, 27, 27, 81, 61, 61, 61, 61, 92, 92,124, 27, 81, 61, 61, 61, - 61, 61, 61, 61, 61, 27, 61, 61, 61, 61, 61, 61, 61, 61, 47, 43, - 161,161,161,161,161,161,161,161,162, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 84, 36,133, 36, 36, 36, 36, 92, 92, 92, - 36, 36, 36, 36, 36, 36, 36, 58,163, 92, 92, 92, 92, 92, 92, 92, - 36, 36, 36, 58, 27, 27, 27, 27, 36, 36, 36, 70,140, 27, 27, 27, - 36, 36, 36,164, 27, 27, 27, 27, 36, 36, 36, 36, 36,164, 27, 27, - 36, 36, 36, 27, 27, 27, 27, 30, 36, 36, 36, 36, 36, 36, 27, 36, - 63, 43, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 43, 43, 43, 43, - 36, 36, 36, 36, 36, 36,164, 30, 36, 36, 36, 36, 36, 36,164, 27, - 36, 36, 36, 36, 71, 36, 36, 36, 36, 36, 63, 43, 43,162, 27, 27, - 36, 36, 36, 36, 58, 2, 2, 2, 36, 36, 36, 36, 27, 27, 27, 27, - 16, 16, 16, 16, 16, 27, 27, 27, 36, 36, 43, 43, 43, 43, 43, 43, - 27, 27, 27, 84, 36, 36, 36, 36,162, 27, 30, 2, 2, 2, 2, 2, - 76, 78, 36, 36, 36, 36, 36, 36, 43, 43, 43, 57, 2, 2, 2, 2, - 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7,165, 75, 76, 43, 74, 76, 57, 72, 2, - 2, 2, 2, 2, 2, 2, 72, 59, 36, 36, 36, 63, 43, 43, 76, 43, - 43, 43, 43, 7, 7, 7, 7, 7, 2, 2, 79, 75, 75, 75, 75, 75, - 36, 63, 2, 36, 36, 36, 36, 36, 36, 79, 75, 43, 43, 43, 43, 74, - 78, 36, 58, 2, 56, 43, 57, 2, 7, 7, 7, 7, 7, 58, 58, 2, - 87, 27, 27, 27, 27, 27, 27, 27, 36, 36, 36, 36, 36, 36, 75, 76, - 43, 75, 74, 43, 2, 2, 2, 43, 36, 36, 36, 36, 36, 36, 36, 63, - 74, 75, 75, 75, 75, 75, 75, 75, 36, 36, 36, 79, 75, 75, 78, 36, - 36, 75, 75, 43, 43, 43, 43, 43, 36, 36, 79, 75, 43, 43, 43, 43, - 75, 43, 74, 64, 36, 58, 2, 2, 7, 7, 7, 7, 7, 82, 2, 64, - 75, 76, 43, 43, 74, 74, 75, 76, 74, 43, 36, 65, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 79, 75, 43, 43, 43, 75, 75, 43, 76, - 57, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 43, 43, - 75, 76, 43, 43, 43, 74, 76, 76, 57, 2, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 63, 76, 75, 43, 43, 43, 76, 36, 36, 36, 36, - 75, 43, 43, 76, 43, 43, 43, 43, 7, 7, 7, 7, 7, 27, 2, 86, - 43, 43, 43, 43, 76, 57, 2, 2, 27, 27, 27, 27, 27, 27, 27, 84, - 79, 75, 43, 43, 43, 43, 75, 75, 64, 65, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 63, 43, 43, 43, 43, 64, 36, 36, - 36, 63, 43, 43, 74, 63, 43, 57, 2, 2, 2, 56, 43, 43, 43, 43, - 63, 43, 43, 74, 76, 43, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, - 43, 43, 43, 74, 43, 2, 65, 2, 43, 43, 43, 43, 43, 43, 43, 76, - 58, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, - 43, 43, 43, 43, 74, 43, 43, 43, 74, 43, 76, 43, 43, 43, 43, 43, - 43, 43, 43, 63, 43, 43, 43, 43, 36, 36, 36, 36, 36, 75, 75, 75, - 43, 74, 76, 76, 36, 36, 36, 36, 36, 63, 74,146, 2, 2, 2, 2, - 27, 27, 81, 61, 61, 61, 53, 20,145, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 21, 43, 43, 57, 2, 2, 2, 2, 2, - 43, 43, 43, 57, 2, 2, 61, 61, 40, 40, 86, 61, 61, 61, 61, 61, - 7, 7, 7, 7, 7,166, 27, 27, 27, 84, 36, 36, 36, 36, 36, 36, - 27, 27, 27, 30, 2, 2, 2, 2, 79, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 76, 43, 67, 40, 40, 40, 40, 40, 40, - 40, 77, 40, 40, 40, 40, 40, 40, 36, 36, 36, 36, 36, 36, 47, 57, - 61, 61,167, 76, 43, 61,167, 75, 75,168, 59, 59, 59, 73, 43, 43, - 43, 69, 47, 43, 43, 43, 61, 61, 61, 61, 61, 61, 61, 43, 43, 61, - 61, 43, 69, 61, 61, 61, 61, 61, 11, 11, 11, 11, 11, 16, 16, 16, - 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16, - 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11, - 11, 11, 11, 16, 16, 16, 16, 16, 31, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, - 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, - 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, - 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, - 16, 33, 16, 16, 16, 32, 16, 7, 43, 43, 43, 69, 61, 47, 43, 43, - 43, 43, 43, 43, 43, 43, 69, 61, 61, 61, 47, 61, 61, 61, 61, 61, - 61, 61, 69, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 56, 43, 43, - 43, 43, 43, 67, 40, 40, 40, 40, 7, 7, 7, 7, 7, 7, 7, 70, - 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 7, 7,169, - 16, 16, 43, 43, 43, 67, 40, 40, 27, 27, 27, 27, 27, 27,140, 27, - 170, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,140, + 2, 95,146, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16,100, 40, 40, + 16, 16, 16, 16, 97, 41, 41, 41, 36, 79, 76, 75, 74,145, 76, 43, + 147,147,147,147,147,147,147,147,148,148,148,148,148,148,148,148, + 16, 16, 16, 16, 16, 16, 35, 64, 36, 36, 36, 36,149, 36, 36, 36, + 36, 41, 41, 41, 41, 41, 41, 41, 41,150, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36,129,151,151,151,151,151,151,151,151, + 36, 36, 36, 36, 36, 36,144, 61, 2, 2, 2,152,113, 2, 2, 2, + 6,153,154,129,129,129,129,129,129,129,113,152,113, 2,110,155, + 2, 2, 2, 2,134,129,129,113, 2,156, 8, 8, 60, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36,157, 2, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18,112,113, 4, 2, 36, 36, 36, 36, 36, + 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, + 20,158, 53, 20, 26, 8,125, 61, 61, 61, 61, 61,159, 59, 61, 61, + 2, 2, 2, 87, 27, 27, 27, 27, 27, 27, 27, 81, 61, 61, 61, 61, + 92, 92,124, 27, 81, 61, 61, 61, 61, 61, 61, 61, 61, 27, 61, 61, + 61, 61, 61, 61, 61, 61, 47, 43,160,160,160,160,160,160,160,160, + 161, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 84, 36, + 133, 36, 36, 36, 36, 92, 92, 92, 36, 36, 36, 36, 36, 36, 36, 58, + 162, 92, 92, 92, 92, 92, 92, 92, 36, 36, 36, 58, 27, 27, 27, 27, + 36, 36, 36, 70,140, 27, 27, 27, 36, 36, 36,163, 27, 27, 27, 27, + 36, 36, 36, 36, 36,163, 27, 27, 36, 36, 36, 27, 27, 27, 27, 30, + 36, 36, 36, 36, 36, 36, 27, 36, 63, 43, 43, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 30, + 36, 36, 36, 36, 36, 36,163, 27, 36, 36, 36, 36, 71, 36, 36, 36, + 36, 36, 63, 43, 43,161, 27, 27, 36, 36, 36, 36, 58, 2, 2, 2, + 36, 36, 36, 36, 27, 27, 27, 27, 16, 16, 16, 16, 16, 27, 27, 27, + 36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 63,164, 51, + 27, 27, 27, 84, 36, 36, 36, 36,161, 27, 30, 2, 2, 2, 2, 2, + 36, 36,163, 27, 27, 27, 27, 27, 76, 78, 36, 36, 36, 36, 36, 36, + 43, 43, 43, 57, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,165, + 75, 76, 43, 74, 76, 57, 72, 2, 2, 2, 2, 2, 2, 2, 72, 59, + 36, 36, 36, 63, 43, 43, 76, 43, 43, 43, 43, 7, 7, 7, 7, 7, + 2, 2, 79, 78, 36, 36, 36, 36, 36, 63, 2, 36, 36, 36, 36, 36, + 36, 79, 75, 43, 43, 43, 43, 74, 78, 36, 58, 2, 56, 43, 57, 76, + 7, 7, 7, 7, 7, 58, 58, 2, 87, 27, 27, 27, 27, 27, 27, 27, + 36, 36, 36, 36, 36, 36, 75, 76, 43, 75, 74, 43, 2, 2, 2, 43, + 36, 36, 36, 36, 36, 36, 36, 63, 74, 75, 75, 75, 75, 75, 75, 75, + 36, 36, 36, 79, 75, 75, 78, 36, 36, 75, 75, 43, 43, 43, 43, 43, + 36, 36, 79, 75, 43, 43, 43, 43, 75, 43, 74, 64, 36, 58, 2, 2, + 7, 7, 7, 7, 7, 2, 2, 64, 75, 76, 43, 43, 74, 74, 75, 76, + 74, 43, 36, 65, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 79, + 75, 43, 43, 43, 75, 75, 43, 76, 57, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 36, 36, 43, 43, 75, 76, 43, 43, 43, 74, 76, 76, + 57, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 76, 75, + 43, 43, 43, 76, 36, 36, 36, 36, 75, 43, 43, 76, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 27, 2, 86, 43, 43, 43, 43, 76, 57, 2, 2, + 27, 27, 27, 27, 27, 27, 27, 84, 75, 75, 75, 75, 75, 76, 74, 64, + 78, 76, 2, 2, 2, 2, 2, 2, 79, 75, 43, 43, 43, 43, 75, 75, + 64, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 63, 43, 43, 43, 43, 64, 36, 36, 36, 63, 43, 43, 74, 63, 43, 57, + 2, 2, 2, 56, 43, 43, 43, 43, 63, 43, 43, 74, 76, 43, 36, 36, + 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 74, 43, 2, 65, 2, + 43, 43, 43, 43, 43, 43, 43, 76, 58, 2, 2, 2, 2, 2, 2, 2, + 2, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 74, 43, 43, 43, + 74, 43, 76, 43, 43, 43, 43, 43, 43, 43, 43, 63, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 75, 75, 75, 43, 74, 76, 76, 36, 36, 36, 36, + 36, 63, 74,145, 2, 2, 2, 2, 27, 27, 81, 61, 61, 61, 53, 20, + 144, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21, + 43, 43, 57, 2, 2, 2, 2, 2, 43, 43, 43, 57, 2, 2, 61, 61, + 40, 40, 86, 61, 61, 61, 61, 61, 7, 7, 7, 7, 7,166, 27, 27, + 27, 84, 36, 36, 36, 36, 36, 36, 27, 27, 27, 30, 2, 2, 2, 2, + 79, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 76, + 43, 67, 40, 40, 40, 40, 40, 40, 40, 77, 43, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 47, 57, 61, 61,167, 76, 43, 61,167, 75, + 75,168, 59, 59, 59, 73, 43, 43, 43, 69, 47, 43, 43, 43, 61, 61, + 61, 61, 61, 61, 61, 43, 43, 61, 61, 43, 69, 61, 61, 61, 61, 61, + 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 16, 11, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, + 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, + 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, + 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, + 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 16, 7, + 43, 43, 43, 69, 61, 47, 43, 43, 43, 43, 43, 43, 43, 43, 69, 61, + 61, 61, 47, 61, 61, 61, 61, 61, 61, 61, 69, 21, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 56, 43, 43, 43, 43, 43, 67, 40, 40, 40, 40, + 7, 7, 7, 7, 7, 7, 7, 70, 36, 36, 36, 36, 36, 36, 43, 43, + 7, 7, 7, 7, 7, 7, 7,169, 16, 16, 43, 43, 43, 67, 40, 40, + 27, 27, 27, 27, 27, 27,140, 27,170, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 81, 61, 61, 61, 61, 61, 61, 25, 41, 41, 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, @@ -5838,185 +5907,188 @@ _hb_ucd_u8[13072] = 6, 12, 12, 26, 7, 26, 26, 7, 21, 1, 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 10, 7, 7, 10, 23, 7, 15, 26, 13, 21, 13, 7, 15, 7, 12, 23, 21, 26, 21, 15, 17, 7, 29, 7, 7, 22, 18, 18, - 14, 14, 14, 7, 17, 21, 7, 6, 5, 6, 8, 8, 8, 24, 5, 24, - 9, 24, 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, - 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6, - 12, 11, 11, 12, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, + 14, 14, 14, 7, 17, 21, 7, 6, 11, 12, 5, 6, 8, 8, 8, 24, + 5, 24, 9, 24, 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, + 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, + 18, 6, 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, - 26, 15, 6, 21, 11, 21, 24, 9, 9, 7, 23, 26, 10, 21, 6, 10, - 4, 4, 3, 3, 7, 25, 24, 7, 22, 22, 21, 22, 17, 16, 16, 22, - 16, 16, 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, - 7, 15, 13, 12, 13, 15, 26, 10, 10, 1, 13, 23, 23, 15, 0, 1, - 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 11, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 12, 13, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 14, 15, 16, 9, - 17, 18, 19, 20, 21, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 23, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 24, 9, 9, - 9, 9, 25, 9, 9, 9, 26, 9, 27, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, - 4, 5, 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 0, 14, 15, 16, - 15, 17, 15, 18, 15, 18, 15, 18, 0, 18, 0, 19, 15, 18, 20, 18, - 0, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, 31, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 0, 0, 35, 0, 36, 0, - 0, 0, 37, 38, 39, 0, 40, 41, 42, 43, 44, 0, 0, 45, 0, 0, - 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, - 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 52, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 53, 54, 55, 0, 0, 0, 0, 56, 0, 0, 57, 58, 59, - 60, 61, 0, 0, 62, 63, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 67, 0, 0, 0, 68, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 70, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, - 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, 74, 75, 0, 76, 60, - 0, 77, 78, 0, 0, 79, 80, 81, 0, 0, 0, 82, 0, 83, 0, 0, - 49, 84, 49, 0, 85, 0, 86, 0, 0, 0, 75, 0, 0, 0, 0, 0, - 0, 87, 88, 89, 90, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 91, - 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 93, 94, 0, 0, 0, 0, 0, 95, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, - 97, 0, 0, 98, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 94, 0, - 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0, 0, 0,101, 0,102, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, - 3, 4, 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, - 0, 0, 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, - 0, 20, 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, - 0, 0, 0, 27, 28, 29, 0, 0, 0, 30, 31, 32, 0, 0, 31, 0, - 0, 33, 31, 0, 0, 0, 31, 34, 0, 0, 0, 0, 0, 35, 36, 0, - 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, - 0, 0, 0, 41, 0, 42, 0, 0, 0, 43, 44, 0, 0, 0, 45, 0, - 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 48, 0, 0, 0, 49, - 0, 49, 0, 50, 0, 0, 0, 0, 51, 0, 0, 0, 0, 52, 0, 53, - 0, 0, 0, 0, 54, 55, 0, 0, 0, 56, 0, 0, 0, 57, 49, 0, - 58, 59, 0, 0, 60, 0, 0, 0, 61, 62, 0, 0, 0, 63, 0, 64, - 65, 66, 67, 68, 1, 69, 0, 70, 71, 72, 0, 0, 73, 74, 0, 0, - 0, 75, 0, 0, 1, 1, 0, 0, 76, 0, 0, 77, 0, 0, 0, 0, - 73, 78, 0, 79, 0, 0, 0, 0, 0, 74, 80, 0, 0, 0, 49, 0, - 1, 74, 0, 0, 81, 0, 0, 82, 0, 0, 0, 0, 0, 83, 54, 0, - 0, 0, 0, 0, 0, 84, 85, 0, 0, 80, 0, 0, 31, 0, 0, 86, - 0, 0, 0, 0, 87, 0, 0, 0, 0, 47, 0, 0, 88, 0, 0, 0, - 0, 89, 90, 0, 0, 91, 0, 0, 92, 0, 0, 0, 93, 0, 94, 88, - 0, 0, 80, 0, 0, 75, 0, 0, 0, 95, 96, 0, 0, 97, 98, 0, - 0, 0, 0, 0, 0, 99, 0, 0,100, 0, 0, 0, 0,101, 31, 0, - 102,103,104, 33, 0, 0,105, 0, 0, 0,106, 0, 0, 0, 0, 0, - 0,107, 0, 0,108, 0, 0, 0, 54, 0, 0, 0, 0, 49,109, 0, - 0, 0, 0,110, 0, 0,111, 0, 0, 0, 0,109, 0, 0, 0, 0, - 0,112, 0, 0, 0,113, 0,114, 0, 0, 0, 0,115,116,117, 0, - 118, 0,119, 0, 0, 0,120,121,122, 0, 0, 0,123, 0, 0,124, - 0, 0,125, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, - 3, 4, 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, - 16, 17, 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, - 21, 24, 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, - 32, 33, 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, - 40, 41, 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, - 19, 1, 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, - 51, 0, 52, 1, 1, 1, 53, 21, 43, 54, 55, 21, 35, 1, 0, 0, - 0, 56, 0, 0, 0, 57, 58, 59, 0, 0, 0, 0, 0, 60, 0, 61, - 0, 0, 0, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, - 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 69, 0, 0, 70, - 71, 0, 72, 73, 74, 75, 76, 77, 0, 0, 0, 78, 0, 0, 0, 79, - 80, 0, 0, 0, 0, 47, 0, 0, 0, 49, 0, 63, 0, 0, 64, 0, - 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, 63, 0, - 0, 0, 0, 49, 1, 85, 1, 54, 15, 41, 0, 56, 0, 0, 0, 0, - 19, 10, 1, 0, 0, 0, 0, 0, 86, 0, 0, 87, 0, 0, 86, 0, - 0, 0, 0, 79, 0, 0, 88, 9, 12, 4, 89, 8, 90, 47, 0, 59, - 50, 0, 21, 1, 21, 91, 92, 1, 1, 1, 1, 93, 94, 95, 96, 1, - 97, 59, 81, 98, 99, 4, 59, 0, 0, 0, 0, 0, 0, 19, 50, 0, - 0, 0, 0, 0, 0, 62, 0, 0,100,101, 0, 0,102, 0, 0, 1, - 1, 50, 0, 0, 0, 38, 0, 64, 0, 0, 0, 0, 52, 69, 62, 0, - 0, 0, 79, 0, 0, 0,103,104, 59, 38, 81, 0, 0, 0, 0, 0, - 0,105, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 88, 0, 0, 0, - 0,106, 0, 0,107, 62, 0,108, 0, 0, 0, 1, 0, 0, 0,109, - 14, 54, 0, 0,110, 0, 88, 0, 0, 0, 62, 63, 0, 0, 63, 0, - 87, 0, 0,110, 0, 0, 0, 0,111, 0, 0, 0, 79, 56, 0, 38, - 1, 59, 1, 59, 0, 0, 64, 87, 0, 0,112, 0, 0, 0, 56, 0, - 0, 0, 0,112, 0, 0, 0, 0, 62, 0, 0, 62, 0, 0, 0, 0, - 57, 0, 87,113, 0, 0, 8, 90, 0, 0, 1, 88, 0, 0, 0, 0, - 0,114, 0,115,116,117,118, 0, 52, 4,119, 49, 23, 0, 0, 0, - 38, 50, 38, 59, 0, 0, 1, 88, 1, 1, 1, 1, 39, 1, 48,103, - 88, 0, 0, 0, 0, 1, 4,119, 0, 0, 0, 1,120, 0, 0, 0, - 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,220,220, - 220,220,220,202,202,220,220,220,220,202,202,220,220,220, 1, 1, - 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,220,220, - 230,230,230,220,220, 0,230,230,230,220,220,220,220,230,232,220, - 220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220, - 230,230,230,230,220,230,230,230,222,220,230,230,220,220,230,222, - 228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, - 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, - 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230, - 230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0, - 220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220, - 230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230, - 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220, 0, 0, - 0,220,230,230, 0,220,230,220,220,220, 27, 28, 29,230, 7, 0, - 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0, - 230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, - 9, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122, - 122,122,220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129, - 130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0, - 230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, - 9, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, - 0, 0,230, 0, 0,220, 0, 0, 9, 9, 0, 0, 7, 0,230,230, - 230, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230, - 230,230,230,230,232,228,228,220, 0,230,233,220,230,220,230,230, - 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0, - 218,228,232,222,224,224, 0, 8, 8, 0,230, 0,230,230,220, 0, - 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230, - 220, 0, 0, 0,220,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, - 9, 7, 9, 9, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, - 0, 0, 0,226,216,216,216,216,216, 0,220,220,220, 0,230,230, - 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145, 26, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 26, 15, 6, 21, 11, 21, 24, 9, 23, 26, 10, 21, 6, 10, 4, 4, + 3, 3, 7, 25, 24, 7, 22, 22, 21, 22, 17, 16, 16, 22, 16, 16, + 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, + 12, 17, 13, 12, 13, 15, 26, 10, 10, 1, 13, 23, 23, 15, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, + 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, + 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, + 9, 10, 0, 11, 12, 13, 0, 14, 15, 16, 15, 17, 15, 18, 15, 18, + 15, 18, 0, 18, 0, 19, 15, 18, 20, 18, 0, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 0, 0, 35, 0, + 36, 0, 0, 0, 37, 38, 39, 40, 41, 42, 43, 44, 45, 0, 0, 46, + 0, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 49, + 0, 50, 0, 51, 52, 0, 53, 0, 0, 0, 0, 0, 0, 54, 55, 56, + 0, 0, 0, 0, 57, 0, 0, 58, 59, 60, 61, 62, 0, 0, 63, 64, + 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 69, + 0, 70, 0, 0, 71, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 0, 0, 74, 0, 0, 75, 0, 0, 0, 76, 77, 0, + 78, 61, 0, 79, 80, 0, 0, 81, 82, 83, 0, 0, 0, 84, 0, 85, + 0, 0, 50, 86, 50, 0, 87, 0, 88, 0, 0, 0, 77, 0, 0, 0, + 89, 90, 0, 91, 92, 93, 94, 0, 0, 0, 0, 0, 50, 0, 0, 0, + 0, 95, 96, 0, 0, 0, 0, 97, 98, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 99, 0, 0,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,101,102, 0, 0,103, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, + 98, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0,106, + 0,107, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, + 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, + 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, + 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 28, 29, + 0, 0, 0, 30, 31, 32, 0, 0, 31, 0, 0, 33, 31, 0, 0, 0, + 31, 34, 0, 0, 0, 0, 0, 35, 36, 0, 0, 0, 0, 0, 0, 37, + 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 41, 0, 42, + 0, 0, 0, 43, 44, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 0, 0, 0, 48, 0, 0, 0, 49, 0, 49, 0, 50, 0, 0, + 0, 0, 51, 0, 0, 0, 0, 52, 0, 53, 0, 0, 0, 0, 54, 55, + 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 0, 58, 49, 0, 59, 60, + 0, 0, 61, 0, 0, 0, 62, 63, 0, 0, 0, 64, 0, 65, 66, 67, + 68, 69, 1, 70, 0, 71, 72, 73, 0, 0, 74, 75, 0, 0, 0, 76, + 0, 0, 1, 1, 0, 0, 77, 0, 0, 78, 0, 0, 0, 0, 74, 79, + 0, 80, 0, 0, 0, 0, 0, 75, 81, 0, 82, 0, 49, 0, 1, 75, + 0, 0, 83, 0, 0, 84, 0, 0, 0, 0, 0, 85, 54, 0, 0, 0, + 0, 0, 0, 86, 87, 0, 0, 81, 0, 0, 31, 0, 0, 88, 0, 0, + 0, 0, 89, 0, 0, 0, 0, 47, 0, 0, 57, 0, 0, 0, 0, 90, + 91, 0, 0, 92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 0, 95, 0, + 96, 57, 0, 0, 81, 0, 0, 76, 0, 0, 0, 97, 98, 0, 0, 99, + 100, 0, 0, 0, 0, 0, 0,101, 0, 0,102, 0, 0, 0, 0,103, + 31, 0,104,105,106, 33, 0, 0,107, 0, 0, 0,108, 0, 0, 0, + 0, 0, 0,109, 0, 0,110, 0, 0, 0, 0,111, 85, 0, 0, 0, + 0, 0, 54, 0, 0, 0, 0, 49,112, 0, 0, 0, 0,113, 0, 0, + 114, 0, 0, 0, 0,112, 0, 0, 0, 0, 0,115, 0, 0, 0,116, + 0, 0, 0,117, 0,118, 0, 0, 0, 0,119,120,121, 0,122, 0, + 123, 0, 0, 0,124,125,126, 0, 0, 0,127, 0, 0,128, 0, 0, + 129, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, + 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, + 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, + 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, + 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, + 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, + 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, + 52, 1, 1, 1, 53, 21, 43, 54, 55, 21, 35, 1, 0, 0, 0, 56, + 0, 0, 0, 57, 58, 59, 0, 0, 0, 0, 0, 60, 0, 61, 0, 0, + 0, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, + 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 69, 0, 0, 70, 71, 0, + 72, 73, 74, 75, 76, 77, 0, 0, 0, 78, 0, 0, 0, 79, 80, 0, + 0, 0, 0, 47, 0, 0, 0, 49, 0, 63, 0, 0, 64, 0, 0, 81, + 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, 63, 0, 0, 0, + 0, 49, 1, 85, 1, 54, 15, 86, 84, 0, 0, 0, 0, 56, 0, 0, + 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 87, 0, 0, 88, 0, 0, + 87, 0, 0, 0, 0, 79, 0, 0, 89, 9, 12, 4, 90, 8, 91, 47, + 0, 59, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, + 97, 1, 98, 59, 81, 99,100, 4, 59, 0, 0, 0, 0, 0, 0, 19, + 50, 0, 0, 0, 0, 0, 0, 62, 0, 0,101,102, 0, 0,103, 0, + 0, 1, 1, 50, 0, 0, 0, 38, 0, 64, 0, 0, 0, 0, 0, 63, + 0, 0, 52, 69, 62, 0, 0, 0, 79, 0, 0, 0,104,105, 59, 38, + 81, 0, 0, 0, 0, 0, 0,106, 1, 14, 4, 12, 0, 38, 89, 0, + 0, 0, 0,107, 0, 0,108, 62, 0,109, 0, 0, 0, 1, 0, 0, + 0, 0, 19, 59, 0,110, 14, 54, 0, 0,111, 0, 89, 0, 0, 0, + 62, 63, 0, 0, 63, 0, 88, 0, 0,111, 0, 0, 0, 0,112, 0, + 0, 0, 79, 56, 0, 38, 1, 59, 1, 59, 0, 0, 64, 88, 0, 0, + 113, 0, 0, 0, 56, 0, 0, 0, 0,113, 0, 0, 0, 0, 62, 0, + 0, 0, 0, 80, 0, 62, 0, 0, 0, 0, 57, 0, 88,114, 0, 0, + 8, 91, 0, 0, 1, 89, 0, 0,115, 0, 0, 0, 0, 0, 0,116, + 0,117,118,119,120, 0, 52, 4,121, 49, 23, 0, 0, 0, 38, 50, + 38, 59, 0, 0, 1, 89, 1, 1, 1, 1, 39, 1, 48,104, 89, 0, + 0, 0, 0, 1, 4,121, 0, 0, 0, 1,122, 0, 0, 0, 0, 0, + 230,230,230,230,230,232,220,220,220,220,232,216,220,220,220,220, + 220,202,202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, + 1,220,220,220,220,230,230,230,230,240,230,220,220,220,230,230, + 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230, + 233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230, + 230,230,220,230,230,230,222,220,230,230,220,220,230,222,228,230, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, + 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, + 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, + 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230, + 230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220, + 220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, + 0,230,230,230,230,230, 0, 0, 0,220,220,220, 0, 0, 0,220, + 230,230, 0,220,230,220,220,220, 27, 28, 29,230, 7, 0, 0, 0, + 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, + 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0, + 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122, + 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0, + 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, + 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, + 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0, + 230, 0, 0,220,230,220, 0,220, 0, 0, 9, 9, 0, 0, 7, 0, + 230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220, + 202,230,230,230,230,230,232,228,228,220, 0,230,233,220,230,220, + 230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, + 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,230, 0,230,230, + 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, + 0,230,220, 0, 0, 0,220,220, 0, 9, 7, 0, 0, 7, 9, 0, + 0, 0, 9, 7, 9, 9, 0, 0, 6, 6, 0, 0, 0, 0, 1, 0, + 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0, + 220,220,220, 0,230,230, 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, + 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, - 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, - 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, - 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 3, 3, 3, 3, 3, - 3, 3, 24, 3, 3, 3, 3, 3, 3, 3, 3, 25, 3, 3, 26, 27, - 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, - 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, - 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, - 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, - 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, - 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, - 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, - 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, - 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, - 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, - 0, 0, 0, 19, 56, 31, 0, 0, 0, 0, 0, 0, 0, 57, 14, 0, - 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 58, 59, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3, 0, 4, - 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0, 0, 8, - 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 0, 0, - 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0, 0, 18, - 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0, 0, 1, - 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0, 1, 0, - 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20, 1, 1, - 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9, 0, 1, - 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21, 9, 36, - 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0, 0, 0, - 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21, 21, 21, - 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9, 0, 0, - 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45, 8, 9, - 1, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, - 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 11, 12, 12, 12, - 12, 13, 14, 15, 16, 17, 18, 12, 19, 12, 20, 12, 12, 12, 12, 21, - 22, 22, 22, 23, 12, 12, 12, 12, 24, 25, 12, 12, 26, 27, 28, 29, - 30, 31, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 32, - 12, 33, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, + 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, + 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, + 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, + 23, 3, 3, 3, 3, 3, 3, 3, 24, 3, 3, 3, 3, 3, 3, 3, + 3, 25, 3, 3, 26, 27, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, + 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, + 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, + 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, + 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, + 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, + 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, + 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, + 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, + 6, 55, 0, 14, 19, 1, 0, 0, 0, 19, 56, 31, 0, 0, 0, 0, + 0, 0, 0, 57, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, + 0, 0, 0, 58, 59, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, + 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, + 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, + 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, + 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, + 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, + 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, + 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, + 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, + 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, + 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, + 0, 0, 0, 45, 8, 9, 1, 0, 1, 0, 1, 1, 8, 21, 21, 9, + 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, + 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 13, 14, 15, 16, 17, 18, 12, 19, 12, + 20, 12, 12, 12, 12, 21, 22, 22, 22, 23, 12, 12, 12, 12, 24, 25, + 12, 12, 26, 27, 28, 29, 30, 31, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 32, 12, 33, 7, 7, 34, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, @@ -6038,245 +6110,268 @@ _hb_ucd_u8[13072] = 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 34, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 33, 34, 35, 35, 35, 35, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 2, 2, 51, 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 57, 57, 56, 56, 56, 56, 56, 56, 58, 59, 60, 61, - 56, 62, 62, 63, 64, 65, 66, 67, 68, 69, 70, 56, 62, 62, 62, 62, + 12, 12, 12, 12, 12, 12, 12, 12, 35, 0, 0, 1, 2, 2, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, + 33, 34, 35, 35, 35, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 2, 2, 51, 51, 52, 53, 54, 55, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 56, 56, 56, 56, + 56, 56, 58, 59, 60, 61, 56, 62, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 56, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 71, - 62, 62, 62, 62, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 74, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 88, 89, 89, 89, 90, 89, - 91, 92, 93, 94, 95, 95, 96, 97, 87, 98, 99,100,101,102,103, 87, - 104,104,104, 87,105,106,107,108,109,110,111,112,113,114,115, 87, - 89, 87,116,117,118,119,120,121,122,123,124, 87,125,126, 87,127, - 128,129,130, 87,131,132, 87,133,134,135, 87, 87,136,137,138,139, - 87,140, 87, 21,141,141,141,141,141,141,141,141,141,141,141, 87, - 87, 87, 87, 87,142,142,142,142,142,142,142,142,142, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,143,143,143,143, - 143, 87, 87, 87,144,144,144,144,145,146,147,147, 87, 87, 87, 87, - 148,148,149,150,151,151,151,151,151,151,151,151,151,151,151,151, - 151,151,151,151,151,151,151,151,151,151, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87,152,153,154,155,155,155, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,156,157, 87, 87, - 87, 87, 87, 87, 56, 56,158,159, 51, 56, 56, 87, 56, 56, 56, 56, - 56, 56, 56, 56,160,160,160,160,160,160, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87,161, 87,162, 87, 87,163, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87,164,164,165, 87, 87, 87, 87, 87, 56, 56, 56, 87, - 89, 89, 87, 87, 56, 56, 56, 56,166, 87, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87, - 87, 87, 87, 87, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 56, 87,167,167, 0, 1, 2, 2, 0, 1, 2, 2, - 2, 3, 4, 5, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, - 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, - 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11, - 11, 11, 12, 11, 13, 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16, 17, 18, 19, 19, - 19, 19, 19, 19, 20, 21, 22, 22, 23, 24, 22, 25, 22, 22, 22, 22, - 22, 26, 22, 22, 27, 27, 27, 27, 27, 22, 22, 22, 28, 28, 28, 28, - 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 27, 27, 22, 22, 22, 22, - 22, 22, 32, 22, 33, 33, 33, 33, 33, 34, 35, 33, 36, 36, 36, 36, - 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, - 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, - 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, - 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, - 44, 44, 44, 44, 45, 45, 45, 46, 45, 45, 45, 45, 47, 47, 47, 47, - 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, - 48, 49, 48, 48, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, - 51, 51, 51, 52, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, - 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, - 56, 56, 56, 56, 57, 57, 58, 58, 58, 58, 59, 58, 60, 60, 61, 62, - 63, 63, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 66, 67, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 56, 56, 56, 56, 56, 68, 68, 68, 68, - 68, 69, 69, 69, 70, 70, 70, 70, 70, 70, 65, 65, 71, 71, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 8, 8, 8, 8, 8, 73, 73, 73, 73, - 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, - 76, 77, 77, 77, 13, 51, 51, 51, 74, 78, 79, 80, 4, 4, 81, 4, - 4, 82, 83, 84, 4, 4, 4, 85, 8, 8, 8, 8, 11, 11, 11, 11, - 11, 11, 11, 11, 86, 0, 0, 0, 0, 0, 0, 87, 0, 4, 0, 0, - 0, 8, 8, 8, 0, 0, 88, 89, 90, 0, 4, 4, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 91, 91, 91, - 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 4, 4, 93, 93, 93, 93, - 93, 93, 93, 93, 51, 51, 51, 94, 94, 94, 94, 94, 54, 54, 54, 54, - 54, 54, 13, 13, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 0, 96, 0, 97, 98, 99,100,100,100,100,101,102,103, - 103,103,103,104,105,105,105,106, 53, 53, 53, 53, 53, 0,105,105, - 0, 0, 0,103, 53, 53, 0, 0, 0, 0, 53,107, 0, 0, 0, 0, - 0,103,103,108,103,103,103,103,103,109, 0, 0, 95, 95, 95, 95, - 0, 0, 0, 0,110,110,110,110,110,110,110,110,110,110,110,110, - 110,111,111,111,112,112,112,112,112,112,112,112,112,112,112,112, - 13, 13, 13, 13, 13, 13,113,113,113,113,113,113, 0, 0,114, 4, - 4, 4, 4, 4,115, 4, 4, 4, 4, 4, 4, 4,116,116,116, 0, - 117,117,117,117,118,118,118,118,118,118, 33, 33,119,119,120,121, - 121,121, 53, 53,122,122,122,122,123,122, 50, 50,124,124,124,124, - 124,124, 50, 50,125,125,125,125,125,125,126,126, 54, 54, 54, 4, - 4,127,128, 55, 55, 55, 55, 55,126,126,126,126,129,129,129,129, - 129,129,129,129, 4,130, 19, 19, 19, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22,131, 0, 22, 22, 22, 8, 0,132, 0, - 0, 0, 0, 22, 22, 22, 22, 22, 22, 22, 22,133, 0, 0, 1, 2, - 1, 2,134,102,103,135, 53, 53, 53, 53, 0, 0,136,136,136,136, - 136,136,136,136, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 11, 11, - 11, 0, 0,137,138,138,139,139,139,139,140, 0,141,141,141,142, - 142,143,143,143,144,144,145,145,145,145,145,145,146,146,146,146, - 146,147,147,147,148,148,148,149,149,149,149,149,150,150,150,151, - 151,151,151,151,152,152,152,152,152,152,152,152,153,153,153,153, - 154,154,155,155,156,156,156,156,156,156,157,157,158,158,159,159, - 159,159,159,159,160,160,161,161,161,161,161,161,162,162,162,162, - 162,162,163,163,164,164,164,164,165,165,165,165,166,166,166,166, - 167,167,168,168,169,169,169,169,169,169,169,169,170,170,170,170, - 170,170,170,170,171,171,171,171,171,171,171,171,172,172,172,172, - 172,172,172,172,173,173,173,174,174,174,174,174,175,175,175,175, - 175,175,175,175,176,176,176,176,176,176,176,176,177,177,177,177, - 177,178,178,178,179,179,179,179,179,180,180,180,181,181,181,181, - 181,181,182, 44,183,183,183,183,183,183,183,183,184,184,184,185, - 185,185,185,185,186,186,186,187,186,186,186,186,188,188,188,188, - 188,188,188,188,189,189,189,189,189,189,189,189,190,190,190,190, - 190,190,190,190,191,191,191,191,191,191, 67, 67,192,192,192,192, - 192,192,192,192,193,193,193,193,193,193,193,193,194,194,194,194, - 194,194,194,194,195,195,195,195,195,195,195,195,196,196,196,196, - 196,196,196,196,197,197,197,197,197,198,198,198,198,198,198,198, - 199,199,199,199,200,200,200,200,200,200,200,201,201,201,201,201, - 201,201,201,201,202,202,202,202,202,202,203,203,203,203,203,203, - 203,203,203,203,204,204,204,204,204,204,204,204,205,205,205,205, - 205,205,205,205,206,206,206,206,206,206,206,206,207,207,207,207, - 207,207,207,207,113,113,113,113,113,113,113,113,113,113,113,113, - 208,208,208,208,209,209,209,209,209,209,209,209,210,210,210,210, - 210,210,210,210,211,211,211,211,211,211,211,211,212,212,212,212, - 212,212,212,212,212,212,212,212,212,212,213, 0,214,214,214,214, - 214,214,214,214,215,100,100,100,100,100,100,100,100,100,100,100, - 100,100,100,100,100,100,100,100,100,100,216,217,217,217,217,217, - 217,217,217,217,218,218,218,218,218,218,218,218,218,218, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,219,220,221, 0,222, 0, - 0, 0, 0, 0,223,223,223,223,223,223,223,223, 92, 92, 92, 92, - 92, 92, 92, 92,224,224,224,224,224,224,224,224,225,225,225,225, - 225,225,225,225,226,226,226,226,226,226,226,226,227,227,227,227, - 227,227,227,227,228, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, - 8, 8, 8, 8, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 0, - 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 0, - 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10, 8, 11, 8, 8, - 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14, - 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 17, 19, 20, 20, 20, - 20, 20, 20, 20, 21, 22, 21, 23, 21, 21, 24, 24, 21, 21, 21, 21, - 23, 21, 25, 7, 7, 26, 21, 21, 27, 21, 21, 21, 21, 21, 21, 22, - 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, - 32, 32, 32, 32, 33, 21, 21, 21, 34, 34, 34, 34, 35, 36, 34, 34, - 34, 37, 34, 34, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, - 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, - 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 48, - 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, 50, 53, 53, 53, 53, - 54, 54, 54, 54, 54, 54, 55, 54, 56, 56, 56, 56, 57, 57, 57, 57, - 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 61, 61, 61, 61, - 61, 61, 62, 63, 64, 64, 64, 64, 65, 65, 65, 65, 65, 66, 0, 0, - 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69, 70, 71, 72, 72, - 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, - 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, - 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83, 7, 7, 7, - 84, 7, 85, 86, 0, 85, 87, 0, 2, 88, 89, 2, 2, 2, 2, 90, - 91, 88, 92, 2, 2, 2, 93, 2, 2, 2, 2, 94, 0, 0, 0, 87, - 1, 0, 0, 95, 0, 96, 97, 0, 4, 0, 0, 0, 0, 0, 0, 4, - 98, 98, 98, 98, 99, 99, 99, 99, 13, 13, 13, 13,100,100,100,100, - 101,101,101,101, 0,102, 0, 0,103,101,104,105, 0, 0,101, 0, - 106,107,107,107,107,107,107,107,107,107,108,106,109,110,110,110, - 110,110,110,110,110,110,111,109,112,112,112,112,113, 56, 56, 56, - 56, 56, 56,114,110,110,110,111,110,110, 0, 0,115,115,115,115, - 116,116,116,116,117,117,117,117,118,118,118,118, 97, 2, 2, 2, - 2, 2, 95, 2,119,119,119,119,120,120,120,120,121,121,121,121, - 122,122,122,122,122,122,122,123,124,124,124,124,125,125,125,125, - 125,125,125,126,127,127,127,127,128,128,128,128,129,129,129,129, - 2, 2, 3, 2, 2,130, 2, 2,131,131,131,131,132, 17, 17, 19, - 21, 21, 21,133, 7, 7, 7,134, 21, 21, 21, 24, 0,135,110,110, - 110,110,110,136,137,137,137,137, 0, 0, 0,138,139,139,139,139, - 140,140,140,140, 85, 0, 0, 0,141,141,141,141,142,142,142,142, - 143,143,143,143,144,144,144,144,145,145,145,145,146,146,146,146, - 147,147,147,147,148,148,148,148,149,149,149,149,150,150,150,150, - 151,151,151,151,152,152,152,152,153,153,153,153,154,154,154,154, - 155,155,155,155,156,156,156,156,157,157,157,157,158,158,158,158, - 159,159,159,159,160,160,160,160,161,161,161,161,162,162,162,162, - 163,163,163,163,164,164,164,164,165,165,165,165,166,166,166,166, - 167,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170, - 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,174, - 175,175,175,175,176,176,176,176,177,177,177,177,178,178,178,178, - 179,179,179,179,180,180,180,180,181,181,181,181,182, 46, 46, 46, - 183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186, - 186,186,187,186,188,188,188,188,189,189,189,189,190,190,190,190, - 191,191,191,191,192,192,192,192,193,193,193,193,194,194,194,194, - 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198, - 199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202, - 203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206, - 207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210, - 211,211,211,211,212,212,212,212,213, 0, 0, 0,214,214,214,214, - 215,107,107,107,107,110,110,110,216,216,216,216,217,217,217,217, - 0,218, 87, 0, 0, 0,218, 7, 83,138, 7, 0, 0, 0,219, 87, - 220,220,220,220,221,221,221,221,222,222,222,222,223,223,223,223, - 224,224,224,224,225, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, - 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, - 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55, - 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4, - 4, 0, 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, - 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, - 1, 1, 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, - 64, 64, 64, 64, 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, - 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, - 5, 5, 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, - 22, 22, 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, - 36, 36, 36, 36, 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, - 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, - 8, 8, 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, - 29, 29, 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, - 35, 35, 35, 0, 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, - 44, 0, 0, 0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, - 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, - 52, 52, 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, - 62, 62, 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, - 73, 73, 73, 73, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, - 0, 1, 0, 0, 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, - 19, 9, 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, - 19, 19, 19, 9, 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, - 27, 27, 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, - 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, - 0, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, - 12, 12, 12, 0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, - 79, 79, 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, - 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, - 84, 84, 84, 0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, - 19, 9, 19, 19, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0, - 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49, - 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42, - 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59, - 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135, - 106,106,106,106,104,104,104,104,110,110,110,110, 47, 47, 47, 47, - 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128,128,128, - 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, 97, 97, - 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112,112,112, - 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122,122,122, - 89, 89, 89, 89,130,130,130,130,144,144,144,144,147,147,147,147, - 148,148,148,148,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85, - 101,101,101,101, 96, 96, 96, 96,111,111,111,111,100,100,100,100, - 100, 36, 36, 36,108,108,108,108,129,129,129,129,109,109,109,109, - 107,107,107,107,107,107,107, 1,137,137,137,137,124,124,124,124, - 123,123,123,123,114,114,114,114,102,102,102,102,126,126,126,126, - 142,142,142,142,125,125,125,125,150,150,150,150,141,141,141,141, - 140,140,140,140,121,121,121,121,133,133,133,133,134,134,134,134, - 138,138,138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63, - 80, 80, 80, 80,127,127,127,127,115,115,115,115,103,103,103,103, - 119,119,119,119,146,146,146,146, 99, 99, 99, 99,136,139, 0, 0, - 136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105,105,105, - 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151,151,151,151, - 152,152,152,152,113,113,113,113,132,132,132,132, 15, 0, 0, 0, - 16, 50, 84,118, 88, 89, 90, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 91, - 85, 85,220, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 94, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 15, + 62, 62, 62, 62, 62, 71, 62, 62, 62, 62, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 73, 74, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, + 88, 89, 89, 89, 90, 89, 91, 92, 93, 94, 95, 95, 96, 97, 87, 98, + 99,100,101,102,103, 87,104,104,104, 87,105,106,107,108,109,110, + 111,112,113,114,115, 87, 89,116,117,118,119,120,121,122,123,124, + 125, 87,126,127, 87,128,129,130,131, 87,132,133,134,135,136,137, + 87, 87,138,139,140,141, 87,142, 87,143,144,144,144,144,144,144, + 144,144,144,144,144, 87, 87, 87, 87, 87,145,145,145,145,145,145, + 145,145,145, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87,146,146,146,146,146, 87, 87, 87,147,147,147,147,148,149, + 150,150, 87, 87, 87, 87,151,151,152,153,154,154,154,154,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, + 155,155,155,155,154, 87, 87, 87, 87, 87,156,157,158,159,159,159, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87,160,161, 87, 87, 87, 87, 87, 87, 56, 56,162,163, 51, 56, + 56, 87, 56, 56, 56, 56, 56, 56, 56, 56,164,164,164,164,164,164, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,165, 87,166, 87, 87,167, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,168,168,169, 87, 87, 87, + 87, 87, 56, 56, 56, 87, 89, 89, 87, 87, 56, 56, 56, 56,170, 87, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, + 62, 62, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, + 62, 87, 87, 87, 87, 87, 87, 87, 87, 87, 56, 87,171,171, 0, 1, + 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 1, 2, + 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, + 8, 9, 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 16, 16, + 16, 16, 16, 17, 18, 18, 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, + 21, 24, 21, 21, 21, 21, 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, + 21, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, + 26, 26, 21, 21, 21, 21, 21, 21, 31, 21, 32, 32, 32, 32, 32, 33, + 34, 32, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, + 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, + 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, + 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, + 44, 44, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 52, 52, + 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, + 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 57, 57, 57, 57, + 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64, 64, 64, + 64, 64, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 55, 55, + 55, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, + 64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71, 8, 8, 8, + 8, 8, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, + 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50, 73, 77, + 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, 4, 4, 84, 8, 8, + 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, 85, 0, 0, 0, 0, 0, + 0, 86, 0, 4, 0, 0, 0, 8, 8, 8, 0, 0, 87, 88, 89, 0, + 4, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, + 4, 4, 92, 92, 92, 92, 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, + 93, 93, 53, 53, 53, 53, 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 0, 95, 0, 96, 97, 98, 99, + 99, 99, 99,100,101,102,102,102,102,103,104,104,104,105, 52, 52, + 52, 52, 52, 0,104,104, 0, 0, 0,102, 52, 52, 0, 0, 0, 0, + 52,106, 0, 0, 0, 0, 0,102,102,107,102,102,102,102,102,108, + 0, 0, 94, 94, 94, 94, 0, 0, 0, 0,109,109,109,109,109,109, + 109,109,109,109,109,109,109,110,110,110,111,111,111,111,111,111, + 111,111,111,111,111,111, 13, 13, 13, 13, 13, 13,112,112,112,112, + 112,112, 0, 0,113, 4, 4, 4, 4, 4,114, 4, 4, 4, 4, 4, + 4, 4,115,115,115, 0,116,116,116,116,117,117,117,117,117,117, + 32, 32,118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, + 49, 49,123,123,123,123,123,123, 49, 49,124,124,124,124,124,124, + 125,125, 53, 53, 53, 4, 4,126,127, 54, 54, 54, 54, 54,125,125, + 125,125,128,128,128,128,128,128,128,128, 4,129, 18, 18, 18, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,130, 0, 21, + 21, 21, 8, 0,131, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, + 21,132, 0, 0, 1, 2, 1, 2,133,101,102,134, 52, 52, 52, 52, + 0, 0,135,135,135,135,135,135,135,135, 0, 0, 0, 0, 11, 11, + 11, 11, 11, 0, 11, 11, 11, 0, 0,136,137,137,138,138,138,138, + 139, 0,140,140,140,141,141,142,142,142,143,143,144,144,144,144, + 144,144,145,145,145,145,145,146,146,146,147,147,147,148,148,148, + 148,148,149,149,149,150,150,150,150,150,151,151,151,151,151,151, + 151,151,152,152,152,152,153,153,154,154,155,155,155,155,155,155, + 156,156,157,157,158,158,158,158,158,158,159,159,160,160,160,160, + 160,160,161,161,161,161,161,161,162,162,163,163,163,163,164,164, + 164,164,165,165,165,165,166,166,167,167,168,168,168,168,168,168, + 168,168,169,169,169,169,169,169,169,169,170,170,170,170,170,170, + 170,170,171,171,171,171,171,171,171,171,172,172,172,172,172,172, + 172,172,173,173,173,174,174,174,174,174,175,175,175,175,175,175, + 176,176,177,177,177,177,177,177,177,177,178,178,178,178,178,179, + 179,179,180,180,180,180,180,181,181,181,182,182,182,182,182,182, + 183, 43,184,184,184,184,184,184,184,184,185,185,185,186,186,186, + 186,186,187,187,187,188,187,187,187,187,189,189,189,189,189,189, + 189,189,190,190,190,190,190,190,190,190,191,191,191,191,191,191, + 191,191,192,192,192,192,192,192, 66, 66,193,193,193,193,193,193, + 193,193,194,194,194,194,194,194,194,194,195,195,195,195,195,195, + 195,195,196,196,196,196,196,196,196,196,197,197,197,197,197,197, + 197,197,198,198,198,198,198,198,198,198,199,199,199,199,199,200, + 200,200,200,200,200,200,201,201,201,201,202,202,202,202,202,202, + 202,203,203,203,203,203,203,203,203,203,204,204,204,204,204,204, + 205,205,205,205,205,205,205,205,205,205,206,206,206,206,206,206, + 206,206,110,110,110,110, 39, 39, 39, 39,207,207,207,207,207,207, + 207,207,208,208,208,208,208,208,208,208,209,209,209,209,209,209, + 209,209,112,112,112,112,112,112,112,112,112,112,112,112,210,210, + 210,210,211,211,211,211,211,211,211,211,212,212,212,212,212,212, + 212,212,213,213,213,213,213,213,213,213,214,214,214,214,214,214, + 214,214,214,214,214,214,214,214,215, 94,216,216,216,216,216,216, + 216,216,217,217,217,217,217,217,217,217,218, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 219,220,220,220,220,220,220,220,220,220,221,221,221,221,221,221, + 221,221,221,221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 222,223,224, 0,225, 0, 0, 0, 0, 0,226,226,226,226,226,226, + 226,226, 91, 91, 91, 91, 91, 91, 91, 91,227,227,227,227,227,227, + 227,227,228,228,228,228,228,228,228,228,229,229,229,229,229,229, + 229,229,230,230,230,230,230,230,230,230,231, 0, 0, 0, 0, 0, + 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 1, 2, + 2, 2, 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, + 8, 10, 8, 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, + 14, 14, 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, + 19, 19, 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, + 20, 20, 22, 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, + 20, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, + 30, 30, 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, + 33, 33, 33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, + 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, + 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, + 46, 47, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, + 52, 52, 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, + 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, + 60, 60, 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, + 0, 0, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, + 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, + 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, + 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, + 7, 7, 83, 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, + 2, 89, 90, 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, + 0, 86, 1, 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, + 0, 4, 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, + 99, 99,100,100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0, + 100, 0,105,106,106,106,106,106,106,106,106,106,107,105,108,109, + 109,109,109,109,109,109,109,109,110,108,111,111,111,111,112, 55, + 55, 55, 55, 55, 55,113,109,109,109,110,109,109, 0, 0,114,114, + 114,114,115,115,115,115,116,116,116,116,117,117,117,117, 96, 2, + 2, 2, 2, 2, 94, 2,118,118,118,118,119,119,119,119,120,120, + 120,120,121,121,121,121,121,121,121,122,123,123,123,123,124,124, + 124,124,124,124,124,125,126,126,126,126,127,127,127,127,128,128, + 128,128, 2, 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, + 17, 18, 20, 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135, + 109,109,109,109,109,136,137,137,137,137, 0, 0, 0,138,139,139, + 139,139,140,140,140,140, 84, 0, 0, 0,141,141,141,141,142,142, + 142,142,143,143,143,143,144,144,144,144,145,145,145,145,146,146, + 146,146,147,147,147,147,148,148,148,148,149,149,149,149,150,150, + 150,150,151,151,151,151,152,152,152,152,153,153,153,153,154,154, + 154,154,155,155,155,155,156,156,156,156,157,157,157,157,158,158, + 158,158,159,159,159,159,160,160,160,160,161,161,161,161,162,162, + 162,162,163,163,163,163,164,164,164,164,165,165,165,165,166,166, + 166,166,167,167,167,167,168,168,168,168,169,169,169,169,170,170, + 170,170,171,171,171,171,172,172,172,172,173,173,173,173,174,174, + 174,174,175,175,175,175,176,176,176,176,177,177,177,177,178,178, + 178,178,179,179,179,179,180,180,180,180,181,181,181,181,182,182, + 182,182,183,183,183,183,184, 45, 45, 45,185,185,185,185,186,186, + 186,186,187,187,187,187,188,188,188,188,188,188,189,188,190,190, + 190,190,191,191,191,191,192,192,192,192,193,193,193,193,194,194, + 194,194,195,195,195,195,196,196,196,196,197,197,197,197,198,198, + 198,198,199,199,199,199,200,200,200,200,201,201,201,201,202,202, + 202,202,203,203,203,203,204,204,204,204,205,205,205,205,206,206, + 206,206,207,207,207,207,208,208,208,208,209,209,209,209,210,210, + 210,210,211,211,211,211,212,212,212,212,213,213,213,213,214,214, + 214,214,215,215,215,215,216,217,217,217,218,218,218,218,217,217, + 217,217,219,106,106,106,106,109,109,109,220,220,220,220,221,221, + 221,221, 0,222, 86, 0, 0, 0,222, 7, 82,138, 7, 0, 0, 0, + 223, 86,224,224,224,224,225,225,225,225,226,226,226,226,227,227, + 227,227,228,228,228,228,229, 0, 0, 0, 0, 0, 0, 0, 0, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, + 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, + 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, + 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, + 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, + 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, + 64, 64, 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, + 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, + 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, + 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, + 36, 36, 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, + 25, 25, 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, + 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, + 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, + 35, 0, 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, + 0, 0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, + 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, + 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, + 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, + 73, 73, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 0, 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, + 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, + 19, 9, 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, + 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, + 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, + 15, 15, 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, + 12, 0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, + 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, + 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, + 84, 0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, + 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, + 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, + 49, 49, 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, + 42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, + 59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135, + 135,135,106,106,106,106,104,104,104,104,110,110,110,110, 47, 47, + 47, 47, 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128, + 128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, + 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112, + 112,112, 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122, + 122,122, 89, 89, 89, 89,130,130,130,130,144,144,144,144,156,156, + 156,156,147,147,147,147,148,148,148,148,153,153,153,153,149,149, + 149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96, + 96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108, + 108,108,129,129,129,129,109,109,109,109,107,107,107,107,107,107, + 107, 1,137,137,137,137,124,124,124,124,123,123,123,123,114,114, + 114,114,102,102,102,102,126,126,126,126,142,142,142,142,125,125, + 125,125,154,154,154,154,150,150,150,150,141,141,141,141,140,140, + 140,140,121,121,121,121,133,133,133,133,134,134,134,134,138,138, + 138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63, 80, 80, + 80, 80,127,127,127,127,115,115,115,115,103,103,103,103,119,119, + 119,119,146,146,146,146, 99, 99, 99, 99,136,139, 0, 0,155,155, + 155,155,136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105, + 105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151,151, + 151,151,152,152,152,152,113,113,113,113,132,132,132,132, 15, 0, + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, + 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6298,30 +6393,18 @@ _hb_ucd_u8[13072] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0, 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, 144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -6332,18 +6415,16 @@ _hb_ucd_u8[13072] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,168,169, 0, 0, 0, 0,170,171, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187, - 188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203, - 204,205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0, + 173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188, + 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204, + 205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, }; static const uint16_t -_hb_ucd_u16[4800] = +_hb_ucd_u16[4848] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, @@ -6358,7 +6439,7 @@ _hb_ucd_u16[4800] = 82, 47, 47, 83, 84, 85, 86, 87, 82, 47, 47, 77, 88, 47, 80, 89, 90, 47, 47, 91, 92, 93, 80, 94, 95, 47, 47, 96, 97, 98, 99, 100, 101, 47, 47, 102, 103, 104, 80, 105, 106, 47, 47, 91, 107, 108, 80, 109, - 90, 47, 47, 110, 111, 112, 80, 113, 114, 47, 47, 47, 115, 116, 99, 117, + 110, 47, 47, 111, 112, 113, 80, 114, 90, 47, 47, 47, 115, 116, 99, 117, 47, 47, 47, 118, 119, 120, 66, 66, 47, 47, 47, 121, 122, 123, 47, 47, 124, 125, 126, 127, 47, 47, 47, 128, 129, 32, 32, 130, 131, 132, 66, 66, 47, 47, 133, 134, 120, 135, 136, 137, 138, 139, 9, 9, 9, 11, 11, 140, @@ -6368,77 +6449,79 @@ _hb_ucd_u16[4800] = 47, 152, 47, 153, 47, 152, 47, 152, 47, 47, 47, 154, 155, 156, 157, 143, 158, 157, 47, 47, 159, 47, 47, 47, 160, 47, 161, 47, 47, 47, 47, 47, 47, 47, 162, 163, 164, 47, 47, 47, 47, 47, 47, 47, 47, 165, 144, 144, - 47, 166, 47, 47, 47, 167, 168, 169, 157, 157, 170, 171, 172, 172, 172, 172, - 173, 47, 47, 174, 175, 120, 176, 177, 178, 47, 179, 61, 47, 47, 180, 181, - 47, 47, 182, 183, 184, 61, 47, 185, 11, 9, 9, 9, 66, 186, 187, 188, - 11, 11, 189, 27, 27, 27, 190, 191, 11, 192, 27, 27, 32, 32, 32, 32, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 193, 13, 13, 13, 13, 13, 13, - 194, 194, 194, 194, 194, 195, 194, 11, 196, 196, 196, 197, 198, 199, 199, 198, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 27, 209, 209, 209, 210, 211, 32, - 212, 213, 214, 215, 216, 143, 217, 217, 218, 219, 220, 144, 221, 222, 144, 223, - 224, 224, 224, 224, 224, 224, 224, 224, 225, 144, 226, 144, 144, 144, 144, 227, - 144, 228, 224, 229, 144, 230, 231, 144, 144, 144, 144, 144, 144, 144, 143, 143, - 143, 232, 144, 144, 144, 144, 233, 143, 144, 144, 144, 144, 144, 144, 144, 144, - 144, 144, 144, 234, 235, 144, 144, 236, 144, 144, 144, 144, 144, 144, 237, 144, - 144, 144, 144, 144, 144, 144, 238, 239, 143, 240, 144, 144, 241, 224, 242, 224, - 243, 244, 224, 224, 224, 245, 224, 246, 144, 144, 144, 224, 247, 144, 144, 144, - 9, 9, 9, 11, 11, 11, 248, 249, 13, 13, 13, 13, 13, 13, 250, 251, - 11, 11, 11, 47, 47, 47, 252, 253, 47, 47, 47, 47, 47, 47, 32, 32, - 254, 255, 256, 257, 258, 66, 66, 66, 259, 260, 261, 262, 263, 47, 47, 47, + 47, 166, 47, 47, 47, 167, 168, 169, 157, 157, 170, 171, 32, 32, 32, 32, + 172, 47, 47, 173, 174, 120, 175, 176, 177, 47, 178, 61, 47, 47, 179, 180, + 47, 47, 181, 182, 183, 61, 47, 184, 11, 9, 9, 9, 66, 185, 186, 187, + 11, 11, 188, 27, 27, 27, 189, 190, 11, 191, 27, 27, 32, 32, 32, 32, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 192, 13, 13, 13, 13, 13, 13, + 193, 193, 193, 193, 193, 194, 193, 11, 195, 195, 195, 196, 197, 198, 198, 197, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 27, 208, 208, 208, 209, 210, 32, + 211, 212, 213, 214, 215, 143, 216, 216, 217, 218, 219, 144, 220, 221, 144, 222, + 223, 223, 223, 223, 223, 223, 223, 223, 224, 144, 225, 144, 144, 144, 144, 226, + 144, 227, 223, 228, 144, 229, 230, 144, 144, 144, 144, 144, 144, 144, 143, 143, + 143, 231, 144, 144, 144, 144, 232, 143, 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 233, 234, 144, 144, 235, 144, 144, 144, 144, 144, 144, 236, 144, + 144, 144, 144, 144, 144, 144, 237, 238, 143, 239, 144, 144, 240, 223, 241, 223, + 242, 243, 223, 223, 223, 244, 223, 245, 144, 144, 144, 223, 246, 144, 144, 144, + 9, 9, 9, 11, 11, 11, 247, 248, 13, 13, 13, 13, 13, 13, 249, 250, + 11, 11, 11, 47, 47, 47, 251, 252, 47, 47, 47, 47, 47, 47, 32, 32, + 253, 254, 255, 256, 257, 258, 66, 66, 259, 260, 261, 262, 263, 47, 47, 47, 47, 264, 146, 47, 47, 47, 47, 265, 47, 266, 47, 47, 144, 144, 144, 47, 144, 144, 267, 144, 268, 269, 144, 144, 267, 144, 144, 269, 144, 144, 144, 144, 47, 47, 47, 47, 144, 144, 144, 144, 47, 270, 47, 47, 47, 47, 47, 47, - 47, 144, 144, 144, 144, 47, 47, 185, 271, 47, 61, 47, 13, 13, 272, 273, + 47, 144, 144, 144, 144, 47, 47, 184, 271, 47, 61, 47, 13, 13, 272, 273, 13, 274, 47, 47, 47, 47, 275, 276, 31, 277, 278, 279, 13, 13, 13, 280, - 281, 282, 283, 284, 285, 9, 9, 286, 287, 47, 288, 289, 47, 47, 47, 290, + 281, 282, 283, 284, 285, 11, 11, 286, 287, 47, 288, 289, 47, 47, 47, 290, 291, 47, 47, 292, 293, 157, 32, 294, 61, 47, 295, 47, 296, 297, 47, 47, 70, 47, 47, 298, 299, 300, 301, 61, 47, 47, 302, 303, 304, 305, 47, 306, - 47, 47, 47, 307, 58, 308, 309, 310, 47, 47, 47, 11, 11, 311, 11, 11, - 11, 11, 11, 11, 47, 47, 312, 157, 313, 313, 313, 313, 313, 313, 313, 313, - 314, 314, 314, 314, 314, 314, 314, 314, 11, 315, 316, 47, 47, 47, 47, 47, - 47, 47, 47, 317, 31, 318, 47, 47, 47, 47, 47, 319, 320, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 321, 32, 322, 32, 323, 324, 325, 326, 47, - 47, 47, 47, 47, 47, 47, 47, 327, 328, 2, 3, 4, 5, 329, 330, 331, - 47, 332, 47, 47, 47, 47, 333, 334, 335, 143, 143, 336, 217, 217, 217, 337, - 338, 144, 144, 144, 144, 144, 144, 339, 340, 340, 340, 340, 340, 340, 340, 340, - 47, 47, 47, 47, 47, 47, 341, 143, 47, 47, 342, 47, 343, 47, 47, 60, - 47, 344, 47, 47, 47, 345, 217, 217, 9, 9, 145, 11, 11, 47, 47, 47, - 47, 47, 157, 9, 9, 145, 11, 11, 47, 47, 47, 47, 47, 47, 344, 66, - 47, 47, 47, 47, 47, 346, 47, 347, 47, 47, 348, 143, 143, 143, 47, 349, - 47, 350, 47, 344, 66, 66, 66, 66, 47, 47, 47, 351, 143, 143, 143, 143, - 352, 47, 47, 353, 143, 66, 47, 354, 47, 355, 143, 143, 356, 47, 357, 66, - 47, 47, 47, 358, 47, 359, 47, 359, 47, 358, 142, 143, 143, 143, 143, 143, - 9, 9, 9, 9, 11, 11, 11, 360, 47, 47, 361, 157, 157, 157, 157, 157, - 143, 143, 143, 143, 143, 143, 143, 143, 47, 355, 362, 47, 60, 363, 66, 66, - 364, 47, 47, 353, 365, 366, 367, 368, 178, 47, 47, 369, 370, 47, 47, 157, - 95, 47, 371, 372, 373, 47, 47, 374, 178, 47, 47, 375, 376, 377, 378, 143, - 47, 47, 379, 380, 32, 32, 32, 32, 47, 47, 358, 47, 47, 381, 169, 157, - 90, 47, 47, 110, 382, 383, 384, 32, 47, 47, 47, 385, 386, 387, 47, 47, - 47, 47, 47, 388, 389, 157, 157, 157, 47, 47, 390, 391, 392, 393, 32, 32, - 47, 47, 47, 394, 395, 157, 66, 66, 47, 47, 396, 397, 157, 157, 157, 157, - 47, 141, 398, 399, 144, 144, 144, 144, 47, 47, 379, 400, 66, 66, 66, 66, - 9, 9, 9, 9, 11, 11, 126, 401, 47, 47, 47, 47, 47, 402, 403, 404, - 405, 47, 47, 406, 407, 408, 47, 47, 409, 410, 66, 66, 47, 47, 47, 47, - 47, 47, 390, 411, 412, 126, 143, 413, 47, 152, 414, 415, 32, 32, 32, 32, - 47, 47, 47, 352, 416, 157, 47, 47, 417, 418, 157, 157, 157, 157, 157, 157, - 47, 47, 47, 47, 47, 47, 47, 419, 143, 143, 143, 143, 143, 420, 421, 422, - 217, 217, 217, 217, 217, 217, 217, 66, 47, 47, 47, 206, 206, 206, 206, 206, - 47, 47, 47, 47, 47, 47, 300, 66, 47, 47, 47, 47, 47, 47, 47, 423, - 47, 47, 47, 424, 425, 426, 427, 47, 9, 9, 9, 9, 9, 9, 11, 11, - 143, 428, 66, 66, 66, 66, 66, 66, 47, 47, 47, 47, 381, 429, 404, 404, - 430, 431, 27, 27, 27, 27, 432, 27, 47, 433, 206, 206, 206, 206, 206, 206, - 144, 144, 144, 144, 144, 144, 434, 435, 436, 144, 437, 144, 144, 144, 144, 144, - 144, 144, 144, 144, 438, 144, 144, 144, 9, 439, 11, 440, 441, 11, 194, 9, - 442, 443, 9, 444, 11, 9, 439, 11, 440, 441, 11, 194, 9, 442, 443, 9, - 444, 11, 9, 439, 11, 440, 441, 11, 194, 9, 442, 443, 9, 444, 11, 9, - 439, 11, 194, 9, 445, 446, 447, 448, 11, 449, 9, 450, 451, 452, 453, 11, - 454, 9, 455, 11, 456, 157, 157, 157, 32, 32, 32, 457, 32, 32, 458, 459, - 460, 461, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 47, 47, 47, 462, 463, 144, 144, 144, 47, 47, 47, 47, 47, 47, 464, 465, - 47, 47, 47, 47, 348, 32, 32, 32, 9, 9, 442, 11, 466, 300, 66, 66, - 143, 143, 467, 468, 143, 143, 143, 143, 143, 143, 469, 143, 143, 143, 143, 143, - 47, 47, 47, 47, 47, 47, 47, 224, 143, 144, 144, 144, 144, 144, 144, 144, - 144, 144, 144, 144, 144, 144, 144, 470, 206, 206, 206, 206, 206, 206, 206, 206, + 47, 47, 47, 307, 58, 308, 309, 310, 47, 47, 47, 11, 11, 311, 312, 11, + 11, 11, 11, 11, 47, 47, 313, 157, 314, 314, 314, 314, 314, 314, 314, 314, + 315, 315, 315, 315, 315, 315, 315, 315, 11, 316, 317, 47, 47, 47, 47, 47, + 47, 47, 47, 318, 31, 319, 47, 47, 47, 47, 47, 320, 321, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 322, 32, 323, 32, 324, 325, 326, 327, 47, + 47, 47, 47, 47, 47, 47, 47, 328, 329, 2, 3, 4, 5, 330, 331, 332, + 47, 333, 47, 47, 47, 47, 334, 335, 336, 143, 143, 337, 216, 216, 216, 338, + 339, 144, 144, 144, 144, 144, 144, 340, 341, 341, 341, 341, 341, 341, 341, 341, + 47, 47, 47, 47, 47, 47, 342, 143, 47, 47, 343, 47, 344, 47, 47, 60, + 47, 345, 47, 47, 47, 346, 216, 216, 9, 9, 145, 11, 11, 47, 47, 47, + 47, 47, 157, 9, 9, 145, 11, 11, 47, 47, 47, 47, 47, 47, 345, 66, + 47, 47, 47, 47, 47, 347, 47, 348, 47, 47, 349, 143, 143, 143, 47, 350, + 47, 351, 47, 345, 66, 66, 66, 66, 47, 47, 47, 352, 143, 143, 143, 143, + 353, 47, 47, 354, 143, 66, 47, 355, 47, 356, 143, 143, 357, 47, 358, 66, + 47, 47, 47, 359, 47, 360, 47, 360, 47, 359, 142, 143, 143, 143, 143, 143, + 9, 9, 9, 9, 11, 11, 11, 361, 47, 47, 362, 157, 157, 157, 157, 157, + 143, 143, 143, 143, 143, 143, 143, 143, 47, 47, 363, 47, 47, 47, 47, 47, + 47, 356, 364, 47, 60, 365, 66, 66, 47, 47, 47, 47, 366, 143, 47, 47, + 367, 47, 47, 354, 368, 369, 370, 371, 177, 47, 47, 372, 373, 47, 47, 157, + 95, 47, 374, 375, 376, 47, 47, 377, 177, 47, 47, 378, 379, 380, 381, 143, + 47, 47, 382, 383, 32, 32, 32, 32, 47, 47, 359, 47, 47, 384, 169, 157, + 90, 47, 47, 111, 385, 386, 387, 32, 47, 47, 47, 388, 389, 390, 47, 47, + 47, 47, 47, 391, 392, 157, 157, 157, 47, 47, 393, 394, 395, 396, 32, 32, + 47, 47, 47, 397, 398, 157, 66, 66, 47, 47, 399, 400, 157, 157, 157, 157, + 47, 141, 401, 402, 144, 144, 144, 144, 47, 47, 382, 403, 66, 66, 66, 66, + 9, 9, 9, 9, 11, 11, 126, 404, 47, 47, 47, 405, 406, 157, 157, 157, + 47, 47, 47, 47, 47, 407, 408, 409, 410, 47, 47, 411, 412, 413, 47, 47, + 414, 415, 66, 66, 47, 47, 47, 47, 47, 47, 393, 416, 417, 126, 143, 418, + 47, 152, 419, 420, 32, 32, 32, 32, 47, 47, 47, 353, 421, 157, 47, 47, + 422, 423, 157, 157, 157, 157, 157, 157, 47, 47, 47, 47, 47, 47, 47, 424, + 47, 47, 47, 47, 143, 425, 426, 427, 216, 216, 216, 216, 216, 216, 216, 66, + 47, 47, 47, 205, 205, 205, 205, 205, 47, 47, 47, 47, 47, 47, 300, 66, + 47, 47, 47, 47, 47, 47, 47, 428, 47, 47, 47, 429, 430, 431, 432, 47, + 9, 9, 9, 9, 9, 9, 11, 11, 143, 433, 66, 66, 66, 66, 66, 66, + 47, 47, 47, 47, 384, 434, 409, 409, 435, 436, 27, 27, 27, 27, 437, 409, + 47, 438, 205, 205, 205, 205, 205, 205, 144, 144, 144, 144, 144, 144, 439, 440, + 441, 144, 442, 144, 144, 144, 144, 144, 144, 144, 144, 144, 443, 144, 144, 144, + 9, 444, 11, 445, 446, 11, 193, 9, 447, 448, 9, 449, 11, 9, 444, 11, + 445, 446, 11, 193, 9, 447, 448, 9, 449, 11, 9, 444, 11, 445, 446, 11, + 193, 9, 447, 448, 9, 449, 11, 9, 444, 11, 193, 9, 450, 451, 452, 453, + 11, 454, 9, 455, 456, 457, 458, 11, 459, 9, 460, 11, 461, 157, 157, 157, + 32, 32, 32, 462, 32, 32, 463, 464, 465, 466, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 47, 467, 468, 144, 144, 144, + 47, 47, 47, 47, 47, 47, 469, 470, 47, 47, 47, 47, 349, 32, 32, 32, + 9, 9, 447, 11, 471, 300, 66, 66, 143, 143, 472, 473, 143, 143, 143, 143, + 143, 143, 474, 143, 143, 143, 143, 143, 47, 47, 47, 47, 47, 47, 47, 223, + 475, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 476, + 144, 144, 144, 144, 144, 144, 144, 157, 205, 205, 205, 205, 205, 205, 205, 205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, @@ -6607,10 +6690,11 @@ _hb_ucd_u16[4800] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1948,1949, - 1950,1951,1952,1953,1954, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1955,1956,1957,1959,1958, - 1960, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950, + 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959, + 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, @@ -6660,12 +6744,12 @@ _hb_ucd_i16[92] = static inline uint_fast8_t _hb_ucd_gc (unsigned u) { - return u<1114112u?_hb_ucd_u8[4840+(((_hb_ucd_u8[1072+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>3>>5])<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; + return u<1114112u?_hb_ucd_u8[4920+(((_hb_ucd_u8[1104+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>3>>5])<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; } static inline uint_fast8_t _hb_ucd_ccc (unsigned u) { - return u<125259u?_hb_ucd_u8[6670+(((_hb_ucd_u8[6166+(((_hb_ucd_u8[5754+(((_hb_ucd_u8[5306+(((_hb_ucd_u8[5182+(u>>2>>2>>2>>4)])<<4)+((u>>2>>2>>2)&15u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; + return u<125259u?_hb_ucd_u8[6796+(((_hb_ucd_u8[6276+(((_hb_ucd_u8[5844+(((_hb_ucd_u8[5508+(((_hb_ucd_u8[5262+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; } static inline unsigned _hb_ucd_b4 (const uint8_t* a, unsigned i) @@ -6675,17 +6759,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i) static inline int_fast16_t _hb_ucd_bmg (unsigned u) { - return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7538+(((_hb_ucd_u8[7314+(((_hb_ucd_u8[7218+(((_hb_ucd_b4(7154+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7672+(((_hb_ucd_u8[7448+(((_hb_ucd_u8[7352+(((_hb_ucd_b4(7288+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; } static inline uint_fast8_t _hb_ucd_sc (unsigned u) { - return u<918016u?_hb_ucd_u8[11048+(((_hb_ucd_u8[10132+(((_hb_ucd_u8[8788+(((_hb_ucd_u8[8228+(((_hb_ucd_u8[7778+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2; + return u<918016u?_hb_ucd_u8[11242+(((_hb_ucd_u8[10314+(((_hb_ucd_u8[8938+(((_hb_ucd_u8[8362+(((_hb_ucd_u8[7912+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2; } static inline uint_fast16_t _hb_ucd_dm (unsigned u) { - return u<195102u?_hb_ucd_u16[1504+(((_hb_ucd_u8[12048+(((_hb_ucd_b4(11952+_hb_ucd_u8,u>>4>>6))<<6)+((u>>4)&63u))])<<4)+((u)&15u))]:0; + return u<195102u?_hb_ucd_u16[1536+(((_hb_ucd_u8[12544+(((_hb_ucd_u8[12162+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; } #endif diff --git a/src/hb-ucd.cc b/src/hb-ucd.cc index b29f2a9c7d1240a64a4f20189bb50361edf607fb..ad72a26c04cbf70ef1759e6863275163ad7a2952 100644 --- a/src/hb-ucd.cc +++ b/src/hb-ucd.cc @@ -136,20 +136,22 @@ hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u) { uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0); - uint32_t *v = (uint32_t*) hb_bsearch (&k, _hb_ucd_dm2_u32_map, - ARRAY_LENGTH (_hb_ucd_dm2_u32_map), - sizeof (*_hb_ucd_dm2_u32_map), - _cmp_pair_11_7_14); + const uint32_t *v = hb_bsearch (k, + _hb_ucd_dm2_u32_map, + ARRAY_LENGTH (_hb_ucd_dm2_u32_map), + sizeof (*_hb_ucd_dm2_u32_map), + _cmp_pair_11_7_14); if (likely (!v)) return false; u = HB_CODEPOINT_DECODE3_11_7_14_3 (*v); } else { uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0); - uint64_t *v = (uint64_t*) hb_bsearch (&k, _hb_ucd_dm2_u64_map, - ARRAY_LENGTH (_hb_ucd_dm2_u64_map), - sizeof (*_hb_ucd_dm2_u64_map), - _cmp_pair); + const uint64_t *v = hb_bsearch (k, + _hb_ucd_dm2_u64_map, + ARRAY_LENGTH (_hb_ucd_dm2_u64_map), + sizeof (*_hb_ucd_dm2_u64_map), + _cmp_pair); if (likely (!v)) return false; u = HB_CODEPOINT_DECODE3_3 (*v); } diff --git a/src/hb-unicode-emoji-table.hh b/src/hb-unicode-emoji-table.hh index 1ff79c977854b2dc34bb8724894b237f9c5e848c..eb7776eecbe3a0979d477ac55b4fe3c7ae1afde1 100644 --- a/src/hb-unicode-emoji-table.hh +++ b/src/hb-unicode-emoji-table.hh @@ -7,13 +7,13 @@ * on file with this header: * * # emoji-data.txt - * # Date: 2019-01-15, 12:10:05 GMT - * # © 2019 Unicode®, Inc. + * # Date: 2020-01-28, 20:52:38 GMT + * # © 2020 Unicode®, Inc. * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. * # For terms of use, see http://www.unicode.org/terms_of_use.html * # * # Emoji Data for UTS #51 - * # Version: 12.0 + * # Version: 13.0 * # * # For documentation and usage, see http://www.unicode.org/reports/tr51 */ @@ -36,7 +36,7 @@ _hb_emoji_u8[448] = 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 7, 7, 7, 14, 15, 16, 17, 18, 19, 20, 7, 7, 7, 7, 7, 21, 7, 7, 7, 7, 22, 23, 7, 7, 7, 24, 7, 14, 0, 25, 0, 26, - 27, 28, 29, 14, 30, 31, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 27, 28, 29, 14, 30, 31, 7, 7, 7, 7, 7, 14, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 1, 0, 2, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,254, 7, 3, diff --git a/src/hb-unicode.cc b/src/hb-unicode.cc index 9a8184063df89310827ac7ce87fc06a8d0f4c675..7470bb1b6ef7426370b3fbe8f70b518eca4b4615 100644 --- a/src/hb-unicode.cc +++ b/src/hb-unicode.cc @@ -40,11 +40,16 @@ * @include: hb.h * * Unicode functions are used to access Unicode character properties. - * Client can pass its own Unicode functions to HarfBuzz, or access - * the built-in Unicode functions that come with HarfBuzz. + * With these functions, client programs can query various properties from + * the Unicode Character Database for any code point, such as General + * Category (gc), Script (sc), Canonical Combining Class (ccc), etc. * - * With the Unicode functions, one can query variour Unicode character - * properties, such as General Category, Script, Combining Class, etc. + * Client programs can optionally pass in their own Unicode functions + * that implement the same queries. The set of functions available is + * defined by the virtual methods in #hb_unicode_funcs_t. + * + * HarfBuzz provides built-in default functions for each method in + * #hb_unicode_funcs_t. **/ @@ -133,6 +138,16 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED #include "hb-icu.h" #endif +/** + * hb_unicode_funcs_get_default: + * + * Fetches a pointer to the default Unicode-functions structure that is used + * when no functions are explicitly set on #hb_buffer_t. + * + * Return value: (transfer none): a pointer to the #hb_unicode_funcs_t Unicode-functions structure + * + * Since: 0.9.2 + **/ hb_unicode_funcs_t * hb_unicode_funcs_get_default () { @@ -155,11 +170,11 @@ hb_unicode_funcs_get_default () /** * hb_unicode_funcs_create: (Xconstructor) - * @parent: (nullable): + * @parent: (nullable): Parent Unicode-functions structure * + * Creates a new #hb_unicode_funcs_t structure of Unicode functions. * - * - * Return value: (transfer full): + * Return value: (transfer full): The Unicode-functions structure * * Since: 0.9.2 **/ @@ -203,25 +218,25 @@ DEFINE_NULL_INSTANCE (hb_unicode_funcs_t) = /** * hb_unicode_funcs_get_empty: * + * Fetches the singleton empty Unicode-functions structure. * - * - * Return value: (transfer full): + * Return value: (transfer full): The empty Unicode-functions structure * * Since: 0.9.2 **/ hb_unicode_funcs_t * hb_unicode_funcs_get_empty () { - return const_cast (&Null(hb_unicode_funcs_t)); + return const_cast (&Null (hb_unicode_funcs_t)); } /** * hb_unicode_funcs_reference: (skip) - * @ufuncs: Unicode functions. + * @ufuncs: The Unicode-functions structure * + * Increases the reference count on a Unicode-functions structure. * - * - * Return value: (transfer full): + * Return value: (transfer full): The Unicode-functions structure * * Since: 0.9.2 **/ @@ -233,9 +248,11 @@ hb_unicode_funcs_reference (hb_unicode_funcs_t *ufuncs) /** * hb_unicode_funcs_destroy: (skip) - * @ufuncs: Unicode functions. - * + * @ufuncs: The Unicode-functions structure * + * Decreases the reference count on a Unicode-functions structure. When + * the reference count reaches zero, the Unicode-functions structure is + * destroyed, freeing all memory. * * Since: 0.9.2 **/ @@ -256,23 +273,23 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs) /** * hb_unicode_funcs_set_user_data: (skip) - * @ufuncs: Unicode functions. - * @key: - * @data: - * @destroy: - * @replace: + * @ufuncs: The Unicode-functions structure + * @key: The user-data key + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key * + * Attaches a user-data key/data pair to the specified Unicode-functions structure. * - * - * Return value: + * Return value: %true if success, %false otherwise * * Since: 0.9.2 **/ hb_bool_t hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, - hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, hb_bool_t replace) { return hb_object_set_user_data (ufuncs, key, data, destroy, replace); @@ -280,18 +297,19 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_get_user_data: (skip) - * @ufuncs: Unicode functions. - * @key: - * + * @ufuncs: The Unicode-functions structure + * @key: The user-data key to query * + * Fetches the user-data associated with the specified key, + * attached to the specified Unicode-functions structure. * - * Return value: (transfer none): + * Return value: (transfer none): A pointer to the user data * * Since: 0.9.2 **/ void * hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, - hb_user_data_key_t *key) + hb_user_data_key_t *key) { return hb_object_get_user_data (ufuncs, key); } @@ -299,9 +317,10 @@ hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_make_immutable: - * @ufuncs: Unicode functions. - * + * @ufuncs: The Unicode-functions structure * + * Makes the specified Unicode-functions structure + * immutable. * * Since: 0.9.2 **/ @@ -316,11 +335,12 @@ hb_unicode_funcs_make_immutable (hb_unicode_funcs_t *ufuncs) /** * hb_unicode_funcs_is_immutable: - * @ufuncs: Unicode functions. - * + * @ufuncs: The Unicode-functions structure * + * Tests whether the specified Unicode-functions structure + * is immutable. * - * Return value: + * Return value: %true if @ufuncs is immutable, %false otherwise * * Since: 0.9.2 **/ @@ -332,11 +352,12 @@ hb_unicode_funcs_is_immutable (hb_unicode_funcs_t *ufuncs) /** * hb_unicode_funcs_get_parent: - * @ufuncs: Unicode functions. + * @ufuncs: The Unicode-functions structure * + * Fetches the parent of the Unicode-functions structure + * @ufuncs. * - * - * Return value: + * Return value: The parent Unicode-functions structure * * Since: 0.9.2 **/ @@ -389,14 +410,18 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE /** * hb_unicode_compose: - * @ufuncs: Unicode functions. - * @a: - * @b: - * @ab: (out): + * @ufuncs: The Unicode-functions structure + * @a: The first Unicode code point to compose + * @b: The second Unicode code point to compose + * @ab: (out): The composition of @a, @b * + * Fetches the composition of a sequence of two Unicode + * code points. * + * Calls the composition function of the specified + * Unicode-functions structure @ufuncs. * - * Return value: + * Return value: %true if @a and @b composed, %false otherwise * * Since: 0.9.2 **/ @@ -411,14 +436,17 @@ hb_unicode_compose (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_decompose: - * @ufuncs: Unicode functions. - * @ab: - * @a: (out): - * @b: (out): + * @ufuncs: The Unicode-functions structure + * @ab: Unicode code point to decompose + * @a: (out): The first code point of the decomposition of @ab + * @b: (out): The second code point of the decomposition of @ab * + * Fetches the decomposition of a Unicode code point. * + * Calls the decomposition function of the specified + * Unicode-functions structure @ufuncs. * - * Return value: + * Return value: %true if @ab was decomposed, %false otherwise * * Since: 0.9.2 **/ @@ -434,13 +462,14 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, #ifndef HB_DISABLE_DEPRECATED /** * hb_unicode_decompose_compatibility: - * @ufuncs: Unicode functions. - * @u: - * @decomposed: (out): - * + * @ufuncs: The Unicode-functions structure + * @u: Code point to decompose + * @decomposed: (out): Compatibility decomposition of @u * + * Fetches the compatibility decomposition of a Unicode + * code point. Deprecated. * - * Return value: + * Return value: length of @decomposed. * * Since: 0.9.2 * Deprecated: 2.0.0 diff --git a/src/hb-unicode.h b/src/hb-unicode.h index df0b91f01902975884e5cc85f62dd7a50d368bb3..c04ee15a09b1d7143b65aeb84ed03f9674014980 100644 --- a/src/hb-unicode.h +++ b/src/hb-unicode.h @@ -28,7 +28,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -41,14 +41,51 @@ HB_BEGIN_DECLS /** - * HB_UNICODE_MAX + * HB_UNICODE_MAX: + * + * Maximum valid Unicode code point. * * Since: 1.9.0 **/ #define HB_UNICODE_MAX 0x10FFFFu -/* hb_unicode_general_category_t */ +/** + * hb_unicode_general_category_t: + * @HB_UNICODE_GENERAL_CATEGORY_CONTROL: [Cc] + * @HB_UNICODE_GENERAL_CATEGORY_FORMAT: [Cf] + * @HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED: [Cn] + * @HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE: [Co] + * @HB_UNICODE_GENERAL_CATEGORY_SURROGATE: [Cs] + * @HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER: [Ll] + * @HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER: [Lm] + * @HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER: [Lo] + * @HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER: [Lt] + * @HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER: [Lu] + * @HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK: [Mc] + * @HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK: [Me] + * @HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK: [Mn] + * @HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER: [Nd] + * @HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER: [Nl] + * @HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER: [No] + * @HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION: [Pc] + * @HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION: [Pd] + * @HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION: [Pe] + * @HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION: [Pf] + * @HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION: [Pi] + * @HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION: [Po] + * @HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION: [Ps] + * @HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL: [Sc] + * @HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL: [Sk] + * @HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL: [Sm] + * @HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL: [So] + * @HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR: [Zl] + * @HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR: [Zp] + * @HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR: [Zs] + * + * Data type for the "General_Category" (gc) property from + * the Unicode Character Database. + **/ /* Unicode Character Database property: General_Category (gc) */ typedef enum @@ -85,13 +122,74 @@ typedef enum HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR /* Zs */ } hb_unicode_general_category_t; -/* hb_unicode_combining_class_t */ - -/* Note: newer versions of Unicode may add new values. Clients should be ready to handle - * any value in the 0..254 range being returned from hb_unicode_combining_class(). - */ - -/* Unicode Character Database property: Canonical_Combining_Class (ccc) */ +/** + * hb_unicode_combining_class_t: + * @HB_UNICODE_COMBINING_CLASS_NOT_REORDERED: Spacing and enclosing marks; also many vowel and consonant signs, even if nonspacing + * @HB_UNICODE_COMBINING_CLASS_OVERLAY: Marks which overlay a base letter or symbol + * @HB_UNICODE_COMBINING_CLASS_NUKTA: Diacritic nukta marks in Brahmi-derived scripts + * @HB_UNICODE_COMBINING_CLASS_KANA_VOICING: Hiragana/Katakana voicing marks + * @HB_UNICODE_COMBINING_CLASS_VIRAMA: Viramas + * @HB_UNICODE_COMBINING_CLASS_CCC10: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC11: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC12: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC13: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC14: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC15: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC16: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC17: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC18: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC19: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC20: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC21: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC22: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC23: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC24: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC25: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC26: [Hebrew] + * @HB_UNICODE_COMBINING_CLASS_CCC27: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC28: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC29: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC30: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC31: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC32: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC33: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC34: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC35: [Arabic] + * @HB_UNICODE_COMBINING_CLASS_CCC36: [Syriac] + * @HB_UNICODE_COMBINING_CLASS_CCC84: [Telugu] + * @HB_UNICODE_COMBINING_CLASS_CCC91: [Telugu] + * @HB_UNICODE_COMBINING_CLASS_CCC103: [Thai] + * @HB_UNICODE_COMBINING_CLASS_CCC107: [Thai] + * @HB_UNICODE_COMBINING_CLASS_CCC118: [Lao] + * @HB_UNICODE_COMBINING_CLASS_CCC122: [Lao] + * @HB_UNICODE_COMBINING_CLASS_CCC129: [Tibetan] + * @HB_UNICODE_COMBINING_CLASS_CCC130: [Tibetan] + * @HB_UNICODE_COMBINING_CLASS_CCC133: [Tibetan] + * @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: Marks attached at the bottom left + * @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: Marks attached directly below + * @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: Marks attached directly above + * @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE_RIGHT: Marks attached at the top right + * @HB_UNICODE_COMBINING_CLASS_BELOW_LEFT: Distinct marks at the bottom left + * @HB_UNICODE_COMBINING_CLASS_BELOW: Distinct marks directly below + * @HB_UNICODE_COMBINING_CLASS_BELOW_RIGHT: Distinct marks at the bottom right + * @HB_UNICODE_COMBINING_CLASS_LEFT: Distinct marks to the left + * @HB_UNICODE_COMBINING_CLASS_RIGHT: Distinct marks to the right + * @HB_UNICODE_COMBINING_CLASS_ABOVE_LEFT: Distinct marks at the top left + * @HB_UNICODE_COMBINING_CLASS_ABOVE: Distinct marks directly above + * @HB_UNICODE_COMBINING_CLASS_ABOVE_RIGHT: Distinct marks at the top right + * @HB_UNICODE_COMBINING_CLASS_DOUBLE_BELOW: Distinct marks subtending two bases + * @HB_UNICODE_COMBINING_CLASS_DOUBLE_ABOVE: Distinct marks extending above two bases + * @HB_UNICODE_COMBINING_CLASS_IOTA_SUBSCRIPT: Greek iota subscript only + * @HB_UNICODE_COMBINING_CLASS_INVALID: Invalid combining class + * + * Data type for the Canonical_Combining_Class (ccc) property + * from the Unicode Character Database. + * + * Note: newer versions of Unicode may add new values. + * Client programs should be ready to handle any value in the 0..254 range + * being returned from hb_unicode_combining_class(). + * + **/ typedef enum { HB_UNICODE_COMBINING_CLASS_NOT_REORDERED = 0, @@ -176,6 +274,18 @@ typedef enum * hb_unicode_funcs_t */ +/** + * hb_unicode_funcs_t: + * + * Data type containing a set of virtual methods used for + * accessing various Unicode character properties. + * + * HarfBuzz provides a default function for each of the + * methods in #hb_unicode_funcs_t. Client programs can implement + * their own replacements for the individual Unicode functions, as + * needed, and replace the default by calling the setter for a + * method. + **/ typedef struct hb_unicode_funcs_t hb_unicode_funcs_t; @@ -200,15 +310,15 @@ hb_unicode_funcs_destroy (hb_unicode_funcs_t *ufuncs); HB_EXTERN hb_bool_t hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs, - hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, hb_bool_t replace); HB_EXTERN void * hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs, - hb_user_data_key_t *key); + hb_user_data_key_t *key); HB_EXTERN void @@ -227,40 +337,141 @@ hb_unicode_funcs_get_parent (hb_unicode_funcs_t *ufuncs); /* typedefs */ +/** + * hb_unicode_combining_class_func_t: + * @ufuncs: A Unicode-functions structure + * @unicode: The code point to query + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. + * + * This method should retrieve the Canonical Combining Class (ccc) + * property for a specified Unicode code point. + * + * Return value: The #hb_unicode_combining_class_t of @unicode + * + **/ typedef hb_unicode_combining_class_t (*hb_unicode_combining_class_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); + +/** + * hb_unicode_general_category_func_t: + * @ufuncs: A Unicode-functions structure + * @unicode: The code point to query + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. + * + * This method should retrieve the General Category property for + * a specified Unicode code point. + * + * Return value: The #hb_unicode_general_category_t of @unicode + * + **/ typedef hb_unicode_general_category_t (*hb_unicode_general_category_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); + +/** + * hb_unicode_mirroring_func_t: + * @ufuncs: A Unicode-functions structure + * @unicode: The code point to query + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. + * + * This method should retrieve the Bi-Directional Mirroring Glyph + * code point for a specified Unicode code point. + * + * Note: If a code point does not have a specified + * Bi-Directional Mirroring Glyph defined, the method should + * return the original code point. + * + * Return value: The #hb_codepoint_t of the Mirroring Glyph for @unicode + * + **/ typedef hb_codepoint_t (*hb_unicode_mirroring_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); + +/** + * hb_unicode_script_func_t: + * @ufuncs: A Unicode-functions structure + * @unicode: The code point to query + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. + * + * This method should retrieve the Script property for a + * specified Unicode code point. + * + * Return value: The #hb_script_t of @unicode + * + **/ typedef hb_script_t (*hb_unicode_script_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t unicode, void *user_data); +/** + * hb_unicode_compose_func_t: + * @ufuncs: A Unicode-functions structure + * @a: The first code point to compose + * @b: The second code point to compose + * @ab: (out): The composed code point + * @user_data: user data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. + * + * This method should compose a sequence of two input Unicode code + * points by canonical equivalence, returning the composed code + * point in a #hb_codepoint_t output parameter (if successful). + * The method must return an #hb_bool_t indicating the success + * of the composition. + * + * Return value: %true is @a,@b composed, %false otherwise + * + **/ typedef hb_bool_t (*hb_unicode_compose_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab, void *user_data); + +/** + * hb_unicode_decompose_func_t: + * @ufuncs: A Unicode-functions structure + * @ab: The code point to decompose + * @a: (out): The first decomposed code point + * @b: (out): The second decomposed code point + * @user_data: user data pointer passed by the caller + * + * A virtual method for the #hb_unicode_funcs_t structure. + * + * This method should decompose an input Unicode code point, + * returning the two decomposed code points in #hb_codepoint_t + * output parameters (if successful). The method must return an + * #hb_bool_t indicating the success of the composition. + * + * Return value: %true if @ab decomposed, %false otherwise + * + **/ typedef hb_bool_t (*hb_unicode_decompose_func_t) (hb_unicode_funcs_t *ufuncs, hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b, void *user_data); -/* setters */ +/* func setters */ /** * hb_unicode_funcs_set_combining_class_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_combining_class_func_t. * * Since: 0.9.2 **/ @@ -271,12 +482,12 @@ hb_unicode_funcs_set_combining_class_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_set_general_category_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_general_category_func_t. * * Since: 0.9.2 **/ @@ -287,12 +498,12 @@ hb_unicode_funcs_set_general_category_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_set_mirroring_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_mirroring_func_t. * * Since: 0.9.2 **/ @@ -303,12 +514,12 @@ hb_unicode_funcs_set_mirroring_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_set_script_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_script_func_t. * * Since: 0.9.2 **/ @@ -319,12 +530,12 @@ hb_unicode_funcs_set_script_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_set_compose_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_compose_func_t. * * Since: 0.9.2 **/ @@ -335,12 +546,12 @@ hb_unicode_funcs_set_compose_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_funcs_set_decompose_func: - * @ufuncs: a Unicode function structure - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: + * @ufuncs: A Unicode-functions structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * + * Sets the implementation function for #hb_unicode_decompose_func_t. * * Since: 0.9.2 **/ @@ -353,6 +564,13 @@ hb_unicode_funcs_set_decompose_func (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_combining_class: + * @ufuncs: The Unicode-functions structure + * @unicode: The code point to query + * + * Retrieves the Canonical Combining Class (ccc) property + * of code point @unicode. + * + * Return value: The #hb_unicode_combining_class_t of @unicode * * Since: 0.9.2 **/ @@ -362,6 +580,13 @@ hb_unicode_combining_class (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_general_category: + * @ufuncs: The Unicode-functions structure + * @unicode: The code point to query + * + * Retrieves the General Category (gc) property + * of code point @unicode. + * + * Return value: The #hb_unicode_general_category_t of @unicode * * Since: 0.9.2 **/ @@ -371,6 +596,13 @@ hb_unicode_general_category (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_mirroring: + * @ufuncs: The Unicode-functions structure + * @unicode: The code point to query + * + * Retrieves the Bi-directional Mirroring Glyph code + * point defined for code point @unicode. + * + * Return value: The #hb_codepoint_t of the Mirroring Glyph for @unicode * * Since: 0.9.2 **/ @@ -380,6 +612,13 @@ hb_unicode_mirroring (hb_unicode_funcs_t *ufuncs, /** * hb_unicode_script: + * @ufuncs: The Unicode-functions structure + * @unicode: The code point to query + * + * Retrieves the #hb_script_t script to which code + * point @unicode belongs. + * + * Return value: The #hb_script_t of @unicode * * Since: 0.9.2 **/ diff --git a/src/hb-unicode.hh b/src/hb-unicode.hh index 0c355f1113b4be8cad3ec6879a23bba041dfb098..5c0cb859deff4abc8bffafcf524d43ef03ef3d7b 100644 --- a/src/hb-unicode.hh +++ b/src/hb-unicode.hh @@ -289,8 +289,8 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); #define HB_MODIFIED_COMBINING_CLASS_CCC15 18 /* tsere */ #define HB_MODIFIED_COMBINING_CLASS_CCC16 19 /* segol */ #define HB_MODIFIED_COMBINING_CLASS_CCC17 20 /* patah */ -#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats */ -#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam */ +#define HB_MODIFIED_COMBINING_CLASS_CCC18 21 /* qamats & qamats qatan */ +#define HB_MODIFIED_COMBINING_CLASS_CCC19 14 /* holam & holam haser for vav*/ #define HB_MODIFIED_COMBINING_CLASS_CCC20 24 /* qubuts */ #define HB_MODIFIED_COMBINING_CLASS_CCC21 12 /* dagesh */ #define HB_MODIFIED_COMBINING_CLASS_CCC22 25 /* meteg */ @@ -324,10 +324,10 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); * Modify Telugu length marks (ccc=84, ccc=91). * These are the only matras in the main Indic scripts range that have * a non-zero ccc. That makes them reorder with the Halant (ccc=9). - * Assign 5 and 6, which are otherwise unassigned. + * Assign 4 and 5, which are otherwise unassigned. */ -#define HB_MODIFIED_COMBINING_CLASS_CCC84 5 /* length mark */ -#define HB_MODIFIED_COMBINING_CLASS_CCC91 6 /* ai length mark */ +#define HB_MODIFIED_COMBINING_CLASS_CCC84 4 /* length mark */ +#define HB_MODIFIED_COMBINING_CLASS_CCC91 5 /* ai length mark */ /* Thai * diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 289a3477fe5d487fbfa154f9a6faf8764c05cef7..48a5dc50adfe7fc9a548891c0c7bde11b17a086f 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -55,7 +55,7 @@ * @short_description: Windows integration * @include: hb-uniscribe.h * - * Functions for using HarfBuzz with the Windows fonts. + * Functions for using HarfBuzz with Windows fonts. **/ typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/( @@ -385,8 +385,8 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 }; unsigned int name_table_length = OT::name::min_size + - ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size + - name_str_len * 2; /* for name data in UTF16BE form */ + ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size + + name_str_len * 2; /* for name data in UTF16BE form */ unsigned int padded_name_table_length = ((name_table_length + 3) & ~3); unsigned int name_table_offset = (length + 3) & ~3; @@ -453,7 +453,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) hb_blob_destroy (blob); return hb_blob_create ((const char *) new_sfnt_data, new_length, - HB_MEMORY_MODE_WRITABLE, nullptr, free); + HB_MEMORY_MODE_WRITABLE, new_sfnt_data, free); } hb_uniscribe_face_data_t * @@ -583,6 +583,16 @@ _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t *data) free (data); } +/** + * hb_uniscribe_font_get_logfontw: + * @font: The #hb_font_t to work upon + * + * Fetches the LOGFONTW structure that corresponds to the + * specified #hb_font_t font. + * + * Return value: a pointer to the LOGFONTW retrieved + * + **/ LOGFONTW * hb_uniscribe_font_get_logfontw (hb_font_t *font) { @@ -590,6 +600,16 @@ hb_uniscribe_font_get_logfontw (hb_font_t *font) return data ? &data->log_font : nullptr; } +/** + * hb_uniscribe_font_get_hfont: + * @font: The #hb_font_t to work upon + * + * Fetches the HFONT handle that corresponds to the + * specified #hb_font_t font. + * + * Return value: the HFONT retreieved + * + **/ HFONT hb_uniscribe_font_get_hfont (hb_font_t *font) { @@ -666,7 +686,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, if (event->index != last_index) { - /* Save a snapshot of active features and the range. */ + /* Save a snapshot of active features and the range. */ range_record_t *range = range_records.push (); unsigned int offset = feature_records.length; @@ -701,7 +721,7 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan, } else { - active_feature_t *feature = active_features.find (&event->feature); + active_feature_t *feature = active_features.find (&event->feature); if (feature) active_features.remove (feature - active_features.arrayZ); } diff --git a/src/hb-utf.hh b/src/hb-utf.hh index 59ec75ebc1e78e361ec51c50f308656a606aeb84..ff5712d16ddb08e7482f6693dc8afc135179689a 100644 --- a/src/hb-utf.hh +++ b/src/hb-utf.hh @@ -235,10 +235,10 @@ struct hb_utf16_xe_t hb_codepoint_t h = text[-1]; if (likely (hb_in_range (h, 0xD800u, 0xDBFFu))) { - /* High-surrogate in h */ - *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u); - text--; - return text; + /* High-surrogate in h */ + *unicode = (h << 10) + c - ((0xD800u << 10) - 0x10000u + 0xDC00u); + text--; + return text; } } diff --git a/src/hb-vector.hh b/src/hb-vector.hh index 035c6d0a86206f29c9c7e4c7fb139220e671260a..17f7d486fa9c189bba9960a689c043bc06de6719 100644 --- a/src/hb-vector.hh +++ b/src/hb-vector.hh @@ -80,7 +80,12 @@ struct hb_vector_t fini (); } - void reset () { resize (0); } + void reset () + { + if (unlikely (in_error ())) + allocated = length; // Big hack! + resize (0); + } hb_vector_t& operator = (const hb_vector_t &o) { @@ -117,7 +122,7 @@ struct hb_vector_t { unsigned int i = (unsigned int) i_; if (unlikely (i >= length)) - return Null(Type); + return Null (Type); return arrayZ[i]; } @@ -165,13 +170,18 @@ struct hb_vector_t Type *push () { if (unlikely (!resize (length + 1))) - return &Crap(Type); + return &Crap (Type); return &arrayZ[length - 1]; } template Type *push (T&& v) { Type *p = push (); + if (p == &Crap (Type)) + // If push failed to allocate then don't copy v, since this may cause + // the created copy to leak memory since we won't have stored a + // reference to it. + return p; *p = hb_forward (v); return p; } @@ -181,7 +191,7 @@ struct hb_vector_t /* Allocate for size but don't adjust length. */ bool alloc (unsigned int size) { - if (unlikely (allocated < 0)) + if (unlikely (in_error ())) return false; if (likely (size <= (unsigned) allocated)) @@ -195,7 +205,7 @@ struct hb_vector_t Type *new_array = nullptr; bool overflows = - (int) new_allocated < 0 || + (int) in_error () || (new_allocated < (unsigned) allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); if (likely (!overflows)) @@ -228,7 +238,7 @@ struct hb_vector_t Type pop () { - if (!length) return Null(Type); + if (!length) return Null (Type); return hb_move (arrayZ[--length]); /* Does this move actually work? */ } @@ -277,6 +287,9 @@ struct hb_vector_t template const Type *lsearch (const T &x, const Type *not_found = nullptr) const { return as_array ().lsearch (x, not_found); } + template + bool lfind (const T &x, unsigned *pos = nullptr) const + { return as_array ().lfind (x, pos); } }; template @@ -290,7 +303,7 @@ struct hb_sorted_vector_t : hb_vector_t typedef hb_sorted_array_t< Type> iter_t; const_iter_t iter () const { return as_array (); } const_iter_t citer () const { return as_array (); } - iter_t iter () { return as_array (); } + iter_t iter () { return as_array (); } operator iter_t () { return iter (); } operator const_iter_t () const { return iter (); } @@ -302,8 +315,8 @@ struct hb_sorted_vector_t : hb_vector_t { return as_array ().bsearch (x, not_found); } template bool bfind (const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { return as_array ().bfind (x, i, not_found, to_store); } }; diff --git a/src/hb-version.h b/src/hb-version.h index 18b3c2c4ee70079174c8d3df201048c5ebef95ae..3c33bd4fe68623b912c75823c40af737ba7f2fa4 100644 --- a/src/hb-version.h +++ b/src/hb-version.h @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -36,12 +36,41 @@ HB_BEGIN_DECLS +/** + * HB_VERSION_MAJOR: + * + * The major component of the library version available at compile-time. + */ #define HB_VERSION_MAJOR 2 -#define HB_VERSION_MINOR 6 +/** + * HB_VERSION_MINOR: + * + * The minor component of the library version available at compile-time. + */ +#define HB_VERSION_MINOR 8 +/** + * HB_VERSION_MICRO: + * + * The micro component of the library version available at compile-time. + */ #define HB_VERSION_MICRO 1 -#define HB_VERSION_STRING "2.6.1" +/** + * HB_VERSION_STRING: + * + * A string literal containing the library version available at compile-time. + */ +#define HB_VERSION_STRING "2.8.1" +/** + * HB_VERSION_ATLEAST: + * @major: the major component of the version number + * @minor: the minor component of the version number + * @micro: the micro component of the version number + * + * Tests the library version at compile-time against a minimum value, + * as three integer components. + */ #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) diff --git a/src/hb-version.h.in b/src/hb-version.h.in index 0ffd889b278962a33f2b8882e1dba4b41af6b672..abcb73f417df5e4cf3e7c81a98b656e402298068 100644 --- a/src/hb-version.h.in +++ b/src/hb-version.h.in @@ -24,7 +24,7 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_H_IN +#if !defined(HB_H_IN) && !defined(HB_NO_SINGLE_HEADER_ERROR) #error "Include instead." #endif @@ -36,12 +36,41 @@ HB_BEGIN_DECLS +/** + * HB_VERSION_MAJOR: + * + * The major component of the library version available at compile-time. + */ #define HB_VERSION_MAJOR @HB_VERSION_MAJOR@ +/** + * HB_VERSION_MINOR: + * + * The minor component of the library version available at compile-time. + */ #define HB_VERSION_MINOR @HB_VERSION_MINOR@ +/** + * HB_VERSION_MICRO: + * + * The micro component of the library version available at compile-time. + */ #define HB_VERSION_MICRO @HB_VERSION_MICRO@ +/** + * HB_VERSION_STRING: + * + * A string literal containing the library version available at compile-time. + */ #define HB_VERSION_STRING "@HB_VERSION@" +/** + * HB_VERSION_ATLEAST: + * @major: the major component of the version number + * @minor: the minor component of the version number + * @micro: the micro component of the version number + * + * Tests the library version at compile-time against a minimum value, + * as three integer components. + */ #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ HB_VERSION_MAJOR*10000+HB_VERSION_MINOR*100+HB_VERSION_MICRO) diff --git a/src/hb.h b/src/hb.h index c5e7072fbacff67809d2194e507637f608fef7c2..360686ca687e2c1a4fc60f7c6637ab30d00a0bf4 100644 --- a/src/hb.h +++ b/src/hb.h @@ -32,12 +32,14 @@ #include "hb-buffer.h" #include "hb-common.h" #include "hb-deprecated.h" +#include "hb-draw.h" #include "hb-face.h" #include "hb-font.h" #include "hb-map.h" #include "hb-set.h" #include "hb-shape.h" #include "hb-shape-plan.h" +#include "hb-style.h" #include "hb-unicode.h" #include "hb-version.h" diff --git a/src/hb.hh b/src/hb.hh index 8dcd5aa88f36c2a7f01ac5b68d37be64a33c61be..4d90e4d576d1300ba52cb5386ad61e7841ecf88b 100644 --- a/src/hb.hh +++ b/src/hb.hh @@ -62,7 +62,6 @@ /* Error. Should never happen. */ #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_ERROR -#pragma GCC diagnostic error "-Wc++11-narrowing" #pragma GCC diagnostic error "-Wcast-align" #pragma GCC diagnostic error "-Wcast-function-type" #pragma GCC diagnostic error "-Wdelete-non-virtual-dtor" @@ -75,6 +74,7 @@ #pragma GCC diagnostic error "-Wmissing-braces" #pragma GCC diagnostic error "-Wmissing-declarations" #pragma GCC diagnostic error "-Wmissing-prototypes" +#pragma GCC diagnostic error "-Wnarrowing" #pragma GCC diagnostic error "-Wnested-externs" #pragma GCC diagnostic error "-Wold-style-definition" #pragma GCC diagnostic error "-Wpointer-arith" @@ -107,6 +107,7 @@ #pragma GCC diagnostic warning "-Wmaybe-uninitialized" #pragma GCC diagnostic warning "-Wmissing-format-attribute" #pragma GCC diagnostic warning "-Wundef" +#pragma GCC diagnostic warning "-Wunused-but-set-variable" #endif /* Ignored currently, but should be fixed at some point. */ @@ -116,6 +117,9 @@ #pragma GCC diagnostic ignored "-Wshadow" // TODO fix #pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" // TODO fix #pragma GCC diagnostic ignored "-Wunused-parameter" // TODO fix +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic ignored "-Wunused-result" // TODO fix +#endif #endif /* Ignored intentionally. */ @@ -125,6 +129,7 @@ #pragma GCC diagnostic ignored "-Wformat-zero-length" #pragma GCC diagnostic ignored "-Wmissing-field-initializers" #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang +#pragma GCC diagnostic ignored "-Wrange-loop-analysis" // https://github.com/harfbuzz/harfbuzz/issues/2834 #pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wtype-limits" #pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it @@ -174,37 +179,46 @@ #include "hb-aat.h" #define HB_AAT_H_IN -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) #ifdef __MINGW32_VERSION #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN 1 #endif -#include #else #include #endif #endif +#ifdef _WIN32 +#include +#include +#endif + #define HB_PASTE1(a,b) a##b #define HB_PASTE(a,b) HB_PASTE1(a,b) /* Compile-time custom allocator support. */ -#if defined(hb_malloc_impl) \ - && defined(hb_calloc_impl) \ - && defined(hb_realloc_impl) \ - && defined(hb_free_impl) +#if !defined(HB_CUSTOM_MALLOC) \ + && defined(hb_malloc_impl) \ + && defined(hb_calloc_impl) \ + && defined(hb_realloc_impl) \ + && defined(hb_free_impl) +#define HB_CUSTOM_MALLOC +#endif + +#ifdef HB_CUSTOM_MALLOC extern "C" void* hb_malloc_impl(size_t size); extern "C" void* hb_calloc_impl(size_t nmemb, size_t size); extern "C" void* hb_realloc_impl(void *ptr, size_t size); @@ -234,15 +248,11 @@ extern "C" void hb_free_impl(void *ptr); #endif #if defined(__GNUC__) && (__GNUC__ >= 3) -#define HB_PURE_FUNC __attribute__((pure)) -#define HB_CONST_FUNC __attribute__((const)) #define HB_PRINTF_FUNC(format_idx, arg_idx) __attribute__((__format__ (__printf__, format_idx, arg_idx))) #else -#define HB_PURE_FUNC -#define HB_CONST_FUNC #define HB_PRINTF_FUNC(format_idx, arg_idx) #endif -#if defined(__GNUC__) && (__GNUC__ >= 4) +#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__) #define HB_UNUSED __attribute__((unused)) #elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */ #define HB_UNUSED __pragma(warning(suppress: 4100 4101)) @@ -318,6 +328,17 @@ extern "C" void hb_free_impl(void *ptr); # define HB_FALLTHROUGH /* FALLTHROUGH */ #endif +/* A tag to enforce use of return value for a function */ +#if __cplusplus >= 201703L +# define HB_NODISCARD [[nodiscard]] +#elif defined(__GNUC__) || defined(__clang__) +# define HB_NODISCARD __attribute__((warn_unused_result)) +#elif defined(_MSC_VER) +# define HB_NODISCARD _Check_return_ +#else +# define HB_NODISCARD +#endif + /* https://github.com/harfbuzz/harfbuzz/issues/1852 */ #if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))) /* Disable certain sanitizer errors. */ @@ -336,7 +357,7 @@ extern "C" void hb_free_impl(void *ptr); # undef _WIN32_WINNT # endif # ifndef _WIN32_WINNT -# if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define _WIN32_WINNT 0x0600 # endif # endif @@ -355,9 +376,9 @@ extern "C" void hb_free_impl(void *ptr); # endif # if _WIN32_WCE < 0x800 # define HB_NO_SETLOCALE -static int errno = 0; /* Use something better? */ +# define HB_NO_ERRNO # endif -# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # ifndef HB_NO_GETENV # define HB_NO_GETENV # endif @@ -371,6 +392,14 @@ static int errno = 0; /* Use something better? */ #define getenv(Name) nullptr #endif +#ifndef HB_NO_ERRNO +# include +#else +static int HB_UNUSED _hb_errno = 0; +# undef errno +# define errno _hb_errno +#endif + #if defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT) /* atexit() is only safe to be called from shared libraries on certain * platforms. Whitelist. @@ -410,184 +439,22 @@ static int errno = 0; /* Use something better? */ #define HB_STMT_START do #define HB_STMT_END while (0) -/* Static-assert as expression. */ -template class hb_assert_constant_t; -template <> class hb_assert_constant_t<1> {}; -#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>)) - /* Lets assert int types. Saves trouble down the road. */ -static_assert ((sizeof (int8_t) == 1), ""); -static_assert ((sizeof (uint8_t) == 1), ""); -static_assert ((sizeof (int16_t) == 2), ""); -static_assert ((sizeof (uint16_t) == 2), ""); -static_assert ((sizeof (int32_t) == 4), ""); -static_assert ((sizeof (uint32_t) == 4), ""); -static_assert ((sizeof (int64_t) == 8), ""); -static_assert ((sizeof (uint64_t) == 8), ""); static_assert ((sizeof (hb_codepoint_t) == 4), ""); static_assert ((sizeof (hb_position_t) == 4), ""); static_assert ((sizeof (hb_mask_t) == 4), ""); static_assert ((sizeof (hb_var_int_t) == 4), ""); -#define HB_DELETE_COPY_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - void operator=(const TypeName&) = delete -#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \ - TypeName() = delete; \ - TypeName(const TypeName&) = delete; \ - void operator=(const TypeName&) = delete - - -/* Flags */ - -/* Enable bitwise ops on enums marked as flags_t */ -/* To my surprise, looks like the function resolver is happy to silently cast - * one enum to another... So this doesn't provide the type-checking that I - * originally had in mind... :(. - * - * For MSVC warnings, see: https://github.com/harfbuzz/harfbuzz/pull/163 - */ -#ifdef _MSC_VER -# pragma warning(disable:4200) -# pragma warning(disable:4800) -#endif -#define HB_MARK_AS_FLAG_T(T) \ - extern "C++" { \ - static inline T operator | (T l, T r) { return T ((unsigned) l | (unsigned) r); } \ - static inline T operator & (T l, T r) { return T ((unsigned) l & (unsigned) r); } \ - static inline T operator ^ (T l, T r) { return T ((unsigned) l ^ (unsigned) r); } \ - static inline T operator ~ (T r) { return T (~(unsigned int) r); } \ - static inline T& operator |= (T &l, T r) { l = l | r; return l; } \ - static inline T& operator &= (T& l, T r) { l = l & r; return l; } \ - static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \ - } \ - static_assert (true, "") - -/* Useful for set-operations on small enums. - * For example, for testing "x ∈ {x1, x2, x3}" use: - * (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3))) - */ -#define FLAG(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 32) + (((uint32_t) 1U) << (unsigned)(x))) -#define FLAG_UNSAFE(x) ((unsigned)(x) < 32 ? (((uint32_t) 1U) << (unsigned)(x)) : 0) -#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x)) -#define FLAG64(x) (ASSERT_STATIC_EXPR_ZERO ((unsigned)(x) < 64) + (((uint64_t) 1ULL) << (unsigned)(x))) -#define FLAG64_UNSAFE(x) ((unsigned)(x) < 64 ? (((uint64_t) 1ULL) << (unsigned)(x)) : 0) - - -/* Size signifying variable-sized array */ -#define VAR 1 - -/* Endian swap, used in Windows related backends */ -static inline uint16_t hb_uint16_swap (const uint16_t v) -{ return (v >> 8) | (v << 8); } -static inline uint32_t hb_uint32_swap (const uint32_t v) -{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } - -/* - * Big-endian integers. Here because fundamental. - */ - -template struct BEInt; - -template -struct BEInt -{ - public: - BEInt& operator = (Type V) - { - v = V; - return *this; - } - operator Type () const { return v; } - private: uint8_t v; -}; -template -struct BEInt -{ - public: - BEInt& operator = (Type V) - { - v[0] = (V >> 8) & 0xFF; - v[1] = (V ) & 0xFF; - return *this; - } - operator Type () const - { -#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ - defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) - /* Spoon-feed the compiler a big-endian integer with alignment 1. - * https://github.com/harfbuzz/harfbuzz/pull/1398 */ - struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; -#if __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap16 (((packed_uint16_t *) this)->v); -#else /* __BYTE_ORDER == __BIG_ENDIAN */ - return ((packed_uint16_t *) this)->v; -#endif -#endif - return (v[0] << 8) - + (v[1] ); - } - private: uint8_t v[2]; -}; -template -struct BEInt -{ - public: - BEInt& operator = (Type V) - { - v[0] = (V >> 16) & 0xFF; - v[1] = (V >> 8) & 0xFF; - v[2] = (V ) & 0xFF; - return *this; - } - operator Type () const - { - return (v[0] << 16) - + (v[1] << 8) - + (v[2] ); - } - private: uint8_t v[3]; -}; -template -struct BEInt -{ - public: - BEInt& operator = (Type V) - { - v[0] = (V >> 24) & 0xFF; - v[1] = (V >> 16) & 0xFF; - v[2] = (V >> 8) & 0xFF; - v[3] = (V ) & 0xFF; - return *this; - } - operator Type () const - { - return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); - } - private: uint8_t v[4]; -}; - - -/* - * For lack of a better place, put Zawgyi script hack here. - * https://github.com/harfbuzz/harfbuzz/issues/1162 - */ - -#define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g')) - /* Headers we include for everyone. Keep topologically sorted by dependency. * They express dependency amongst themselves, but no other file should include * them directly.*/ #include "hb-meta.hh" #include "hb-mutex.hh" +#include "hb-number.hh" #include "hb-atomic.hh" // Requires: hb-meta #include "hb-null.hh" // Requires: hb-meta -#include "hb-algs.hh" // Requires: hb-meta hb-null +#include "hb-algs.hh" // Requires: hb-meta hb-null hb-number #include "hb-iter.hh" // Requires: hb-algs hb-meta #include "hb-debug.hh" // Requires: hb-algs hb-atomic #include "hb-array.hh" // Requires: hb-algs hb-iter hb-null diff --git a/src/main.cc b/src/main.cc index 0aa4a5b204b68d722bdcff4de084da61d32cd2c6..e898e6e4b60557975e6779e8202f2f5c9aa896ae 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,5 +1,7 @@ /* * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2018,2019,2020 Ebrahim Byagowi + * Copyright © 2018 Khaled Hosny * * This is part of HarfBuzz, a text shaping library. * @@ -24,48 +26,337 @@ * Red Hat Author(s): Behdad Esfahbod */ -#include "hb-static.cc" -#include "hb-open-file.hh" -#include "hb-ot-layout-gdef-table.hh" -#include "hb-ot-layout-gsubgpos.hh" - -#ifdef HAVE_GLIB -#include +#ifdef HAVE_CONFIG_H +#include "config.h" #endif -#include -#include +#include "hb.h" +#include "hb-ot.h" -using namespace OT; +#include +#include +#include #ifdef HB_NO_OPEN #define hb_blob_create_from_file(x) hb_blob_get_empty () #endif -int -main (int argc, char **argv) +#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API) +static void +svg_dump (hb_face_t *face, unsigned face_index) { - if (argc != 2) { - fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); - exit (1); + unsigned glyph_count = hb_face_get_glyph_count (face); + + for (unsigned glyph_id = 0; glyph_id < glyph_count; ++glyph_id) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id); + + if (hb_blob_get_length (blob) == 0) continue; + + unsigned length; + const char *data = hb_blob_get_data (blob, &length); + + char output_path[255]; + sprintf (output_path, "out/svg-%u-%u.svg%s", + glyph_id, + face_index, + // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405 + (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : ""); + + FILE *f = fopen (output_path, "wb"); + fwrite (data, 1, length, f); + fclose (f); + + hb_blob_destroy (blob); } +} - hb_blob_t *blob = hb_blob_create_from_file (argv[1]); - unsigned int len; - const char *font_data = hb_blob_get_data (blob, &len); - printf ("Opened font file %s: %d bytes long\n", argv[1], len); +/* _png API is so easy to use unlike the below code, don't get confused */ +static void +png_dump (hb_face_t *face, unsigned face_index) +{ + unsigned glyph_count = hb_face_get_glyph_count (face); + hb_font_t *font = hb_font_create (face); + + /* scans the font for strikes */ + unsigned sample_glyph_id; + /* we don't care about different strikes for different glyphs at this point */ + for (sample_glyph_id = 0; sample_glyph_id < glyph_count; ++sample_glyph_id) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); + unsigned blob_length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + if (blob_length != 0) + break; + } + + unsigned upem = hb_face_get_upem (face); + unsigned blob_length = 0; + unsigned strike = 0; + for (unsigned ppem = 1; ppem < upem; ++ppem) + { + hb_font_set_ppem (font, ppem, ppem); + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); + unsigned new_blob_length = hb_blob_get_length (blob); + hb_blob_destroy (blob); + if (new_blob_length != blob_length) + { + for (unsigned glyph_id = 0; glyph_id < glyph_count; ++glyph_id) + { + hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id); + + if (hb_blob_get_length (blob) == 0) continue; + + unsigned length; + const char *data = hb_blob_get_data (blob, &length); + + char output_path[255]; + sprintf (output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index); + + FILE *f = fopen (output_path, "wb"); + fwrite (data, 1, length, f); + fclose (f); + + hb_blob_destroy (blob); + } + + strike++; + blob_length = new_blob_length; + } + } + + hb_font_destroy (font); +} + +struct user_data_t +{ + FILE *f; + hb_position_t ascender; +}; + +static void +move_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data) +{ + fprintf (user_data.f, "M%d,%d", to_x, user_data.ascender - to_y); +} + +static void +line_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data) +{ + fprintf (user_data.f, "L%d,%d", to_x, user_data.ascender - to_y); +} + +static void +quadratic_to (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y, + user_data_t &user_data) +{ + fprintf (user_data.f, "Q%d,%d %d,%d", control_x, user_data.ascender - control_y, + to_x, user_data.ascender - to_y); +} + +static void +cubic_to (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y, + user_data_t &user_data) +{ + fprintf (user_data.f, "C%d,%d %d,%d %d,%d", control1_x, user_data.ascender - control1_y, + control2_x, user_data.ascender - control2_y, + to_x, user_data.ascender - to_y); +} + +static void +close_path (user_data_t &user_data) +{ + fprintf (user_data.f, "Z"); +} + +static void +layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index) +{ + hb_face_t *face = hb_font_get_face (font); + unsigned palette_count = hb_ot_color_palette_get_count (face); + for (unsigned palette = 0; palette < palette_count; ++palette) + { + unsigned num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr); + if (!num_colors) continue; + + hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t)); + hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors); + if (!num_colors) + { + free (colors); + continue; + } + + unsigned num_glyphs = hb_face_get_glyph_count (face); + for (hb_codepoint_t gid = 0; gid < num_glyphs; ++gid) + { + unsigned num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr); + if (!num_layers) continue; + + hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t)); + + hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers); + if (num_layers) + { + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + hb_glyph_extents_t extents = {0}; + if (!hb_font_get_glyph_extents (font, gid, &extents)) + { + printf ("Skip gid: %d\n", gid); + continue; + } + + char output_path[255]; + sprintf (output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index); + FILE *f = fopen (output_path, "wb"); + fprintf (f, "\n", + extents.x_bearing, 0, + extents.x_bearing + extents.width, -extents.height); + user_data_t user_data; + user_data.ascender = extents.y_bearing; + user_data.f = f; + + for (unsigned layer = 0; layer < num_layers; ++layer) + { + hb_color_t color = 0x000000FF; + if (layers[layer].color_index != 0xFFFF) + color = colors[layers[layer].color_index]; + fprintf (f, "\n"); + } + + fprintf (f, ""); + fclose (f); + } + free (layers); + } + + free (colors); + } +} + +static void +dump_glyphs (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index) +{ + unsigned num_glyphs = hb_face_get_glyph_count (hb_font_get_face (font)); + for (unsigned gid = 0; gid < num_glyphs; ++gid) + { + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + hb_glyph_extents_t extents = {0}; + if (!hb_font_get_glyph_extents (font, gid, &extents)) + { + printf ("Skip gid: %d\n", gid); + continue; + } + + char output_path[255]; + sprintf (output_path, "out/%u-%u.svg", face_index, gid); + FILE *f = fopen (output_path, "wb"); + fprintf (f, ""); + fclose (f); + } +} + +static void +dump_glyphs (hb_blob_t *blob, const char *font_name) +{ + FILE *font_name_file = fopen ("out/.dumped_font_name", "r"); + if (font_name_file) + { + fprintf (stderr, "Purge or rename ./out folder if you like to run a glyph dump,\n" + "run it like `rm -rf out && mkdir out && src/main font-file.ttf`\n"); + return; + } + + font_name_file = fopen ("out/.dumped_font_name", "w"); + if (!font_name_file) + { + fprintf (stderr, "./out is not accessible as a folder, create it please\n"); + return; + } + fwrite (font_name, 1, strlen (font_name), font_name_file); + fclose (font_name_file); + + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to); + hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to); + hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to); + hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to); + hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path); + + unsigned num_faces = hb_face_count (blob); + for (unsigned face_index = 0; face_index < num_faces; ++face_index) + { + hb_face_t *face = hb_face_create (blob, face_index); + hb_font_t *font = hb_font_create (face); + + if (hb_ot_color_has_png (face)) + printf ("Dumping png (CBDT/sbix)...\n"); + png_dump (face, face_index); + + if (hb_ot_color_has_svg (face)) + printf ("Dumping svg (SVG )...\n"); + svg_dump (face, face_index); + + if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face)) + printf ("Dumping layered color glyphs (COLR/CPAL)...\n"); + layered_glyph_dump (font, funcs, face_index); + + dump_glyphs (font, funcs, face_index); + + hb_font_destroy (font); + hb_face_destroy (face); + } + + hb_draw_funcs_destroy (funcs); +} +#endif + +#ifndef MAIN_CC_NO_PRIVATE_API +/* Only this part of this mini app uses private API */ +#include "hb-static.cc" +#include "hb-open-file.hh" +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gsubgpos.hh" - hb_blob_t *font_blob = hb_sanitize_context_t().sanitize_blob (blob); +using namespace OT; + +static void +print_layout_info_using_private_api (hb_blob_t *blob) +{ + const char *font_data = hb_blob_get_data (blob, nullptr); + hb_blob_t *font_blob = hb_sanitize_context_t ().sanitize_blob (blob); const OpenTypeFontFile* sanitized = font_blob->as (); if (!font_blob->data) { printf ("Sanitization of the file wasn't successful. Exit"); - return 1; + exit (1); } const OpenTypeFontFile& ot = *sanitized; - - switch (ot.get_tag ()) { + switch (ot.get_tag ()) + { case OpenTypeFontFile::TrueTypeTag: printf ("OpenType font with TrueType outlines\n"); break; @@ -89,41 +380,46 @@ main (int argc, char **argv) break; } - int num_fonts = ot.get_face_count (); - printf ("%d font(s) found in file\n", num_fonts); - for (int n_font = 0; n_font < num_fonts; n_font++) { + unsigned num_faces = hb_face_count (blob); + printf ("%d font(s) found in file\n", num_faces); + for (unsigned n_font = 0; n_font < num_faces; ++n_font) + { const OpenTypeFontFace &font = ot.get_face (n_font); - printf ("Font %d of %d:\n", n_font, num_fonts); + printf ("Font %d of %d:\n", n_font, num_faces); - int num_tables = font.get_table_count (); + unsigned num_tables = font.get_table_count (); printf (" %d table(s) found in font\n", num_tables); - for (int n_table = 0; n_table < num_tables; n_table++) { + for (unsigned n_table = 0; n_table < num_tables; ++n_table) + { const OpenTypeTable &table = font.get_table (n_table); printf (" Table %2d of %2d: %.4s (0x%08x+0x%08x)\n", n_table, num_tables, (const char *) table.tag, - (unsigned int) table.offset, - (unsigned int) table.length); + (unsigned) table.offset, + (unsigned) table.length); - switch (table.tag) { + switch (table.tag) + { case HB_OT_TAG_GSUB: case HB_OT_TAG_GPOS: { - const GSUBGPOS &g = *CastP (font_data + table.offset); + const GSUBGPOS &g = *reinterpret_cast (font_data + table.offset); - int num_scripts = g.get_script_count (); + unsigned num_scripts = g.get_script_count (); printf (" %d script(s) found in table\n", num_scripts); - for (int n_script = 0; n_script < num_scripts; n_script++) { + for (unsigned n_script = 0; n_script < num_scripts; ++n_script) + { const Script &script = g.get_script (n_script); printf (" Script %2d of %2d: %.4s\n", n_script, num_scripts, - (const char *)g.get_script_tag(n_script)); + (const char *) g.get_script_tag (n_script)); - if (!script.has_default_lang_sys()) + if (!script.has_default_lang_sys ()) printf (" No default language system\n"); int num_langsys = script.get_lang_sys_count (); printf (" %d language system(s) found in script\n", num_langsys); - for (int n_langsys = script.has_default_lang_sys() ? -1 : 0; n_langsys < num_langsys; n_langsys++) { + for (int n_langsys = script.has_default_lang_sys () ? -1 : 0; n_langsys < num_langsys; ++n_langsys) + { const LangSys &langsys = n_langsys == -1 ? script.get_default_lang_sys () : script.get_lang_sys (n_langsys); @@ -131,43 +427,46 @@ main (int argc, char **argv) printf (" Default Language System\n"); else printf (" Language System %2d of %2d: %.4s\n", n_langsys, num_langsys, - (const char *)script.get_lang_sys_tag (n_langsys)); + (const char *) script.get_lang_sys_tag (n_langsys)); if (!langsys.has_required_feature ()) printf (" No required feature\n"); else printf (" Required feature index: %d\n", langsys.get_required_feature_index ()); - int num_features = langsys.get_feature_count (); + unsigned num_features = langsys.get_feature_count (); printf (" %d feature(s) found in language system\n", num_features); - for (int n_feature = 0; n_feature < num_features; n_feature++) { + for (unsigned n_feature = 0; n_feature < num_features; ++n_feature) + { printf (" Feature index %2d of %2d: %d\n", n_feature, num_features, - langsys.get_feature_index (n_feature)); + langsys.get_feature_index (n_feature)); } } } - int num_features = g.get_feature_count (); + unsigned num_features = g.get_feature_count (); printf (" %d feature(s) found in table\n", num_features); - for (int n_feature = 0; n_feature < num_features; n_feature++) { + for (unsigned n_feature = 0; n_feature < num_features; ++n_feature) + { const Feature &feature = g.get_feature (n_feature); - int num_lookups = feature.get_lookup_count (); + unsigned num_lookups = feature.get_lookup_count (); printf (" Feature %2d of %2d: %c%c%c%c\n", n_feature, num_features, - HB_UNTAG(g.get_feature_tag(n_feature))); + HB_UNTAG (g.get_feature_tag (n_feature))); printf (" %d lookup(s) found in feature\n", num_lookups); - for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) { + for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup) { printf (" Lookup index %2d of %2d: %d\n", n_lookup, num_lookups, - feature.get_lookup_index (n_lookup)); + feature.get_lookup_index (n_lookup)); } } - int num_lookups = g.get_lookup_count (); + unsigned num_lookups = g.get_lookup_count (); printf (" %d lookup(s) found in table\n", num_lookups); - for (int n_lookup = 0; n_lookup < num_lookups; n_lookup++) { + for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup) + { const Lookup &lookup = g.get_lookup (n_lookup); printf (" Lookup %2d of %2d: type %d, props 0x%04X\n", n_lookup, num_lookups, - lookup.get_type(), lookup.get_props()); + lookup.get_type (), lookup.get_props ()); } } @@ -176,7 +475,7 @@ main (int argc, char **argv) case GDEF::tableTag: { - const GDEF &gdef = *CastP (font_data + table.offset); + const GDEF &gdef = *reinterpret_cast (font_data + table.offset); printf (" Has %sglyph classes\n", gdef.has_glyph_classes () ? "" : "no "); @@ -193,6 +492,28 @@ main (int argc, char **argv) } } } +} +/* end of private API use */ +#endif + +int +main (int argc, char **argv) +{ + if (argc != 2) + { + fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]); + exit (1); + } + + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + printf ("Opened font file %s: %d bytes long\n", argv[1], hb_blob_get_length (blob)); +#ifndef MAIN_CC_NO_PRIVATE_API + print_layout_info_using_private_api (blob); +#endif +#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW) && defined(HB_EXPERIMENTAL_API) + dump_glyphs (blob, argv[1]); +#endif + hb_blob_destroy (blob); return 0; } diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..dddafe9c21c2304c6b9e88050fab6d627f436c9a --- /dev/null +++ b/src/meson.build @@ -0,0 +1,721 @@ +hb_version_h = configure_file( + command: [find_program('gen-hb-version.py'), meson.project_version(), '@OUTPUT@', '@INPUT@'], + input: 'hb-version.h.in', + output: 'hb-version.h', + install: true, + install_dir: join_paths(get_option('includedir'), meson.project_name())) + +# Base and default-included sources and headers +hb_base_sources = files( + 'hb-aat-layout-ankr-table.hh', + 'hb-aat-layout-bsln-table.hh', + 'hb-aat-layout-common.hh', + 'hb-aat-layout-feat-table.hh', + 'hb-aat-layout-just-table.hh', + 'hb-aat-layout-kerx-table.hh', + 'hb-aat-layout-morx-table.hh', + 'hb-aat-layout-opbd-table.hh', + 'hb-aat-layout-trak-table.hh', + 'hb-aat-layout.cc', + 'hb-aat-layout.hh', + 'hb-aat-ltag-table.hh', + 'hb-aat-map.cc', + 'hb-aat-map.hh', + 'hb-algs.hh', + 'hb-array.hh', + 'hb-atomic.hh', + 'hb-bimap.hh', + 'hb-blob.cc', + 'hb-blob.hh', + 'hb-buffer-serialize.cc', + 'hb-buffer.cc', + 'hb-buffer.hh', + 'hb-cache.hh', + 'hb-cff-interp-common.hh', + 'hb-cff-interp-cs-common.hh', + 'hb-cff-interp-dict-common.hh', + 'hb-cff1-interp-cs.hh', + 'hb-cff2-interp-cs.hh', + 'hb-common.cc', + 'hb-config.hh', + 'hb-debug.hh', + 'hb-dispatch.hh', + 'hb-draw.cc', + 'hb-draw.hh', + 'hb-face.cc', + 'hb-face.hh', + 'hb-fallback-shape.cc', + 'hb-font.cc', + 'hb-font.hh', + 'hb-iter.hh', + 'hb-kern.hh', + 'hb-machinery.hh', + 'hb-map.cc', + 'hb-map.hh', + 'hb-meta.hh', + 'hb-mutex.hh', + 'hb-null.hh', + 'hb-number.cc', + 'hb-number.hh', + 'hb-object.hh', + 'hb-open-file.hh', + 'hb-open-type.hh', + 'hb-ot-cff-common.hh', + 'hb-ot-cff1-std-str.hh', + 'hb-ot-cff1-table.cc', + 'hb-ot-cff1-table.hh', + 'hb-ot-cff2-table.cc', + 'hb-ot-cff2-table.hh', + 'hb-ot-cmap-table.hh', + 'hb-ot-color-cbdt-table.hh', + 'hb-ot-color-colr-table.hh', + 'hb-ot-color-cpal-table.hh', + 'hb-ot-color-sbix-table.hh', + 'hb-ot-color-svg-table.hh', + 'hb-ot-color.cc', + 'hb-ot-face-table-list.hh', + 'hb-ot-face.cc', + 'hb-ot-face.hh', + 'hb-ot-font.cc', + 'hb-ot-gasp-table.hh', + 'hb-ot-glyf-table.hh', + 'hb-ot-hdmx-table.hh', + 'hb-ot-head-table.hh', + 'hb-ot-hhea-table.hh', + 'hb-ot-hmtx-table.hh', + 'hb-ot-kern-table.hh', + 'hb-ot-layout-base-table.hh', + 'hb-ot-layout-common.hh', + 'hb-ot-layout-gdef-table.hh', + 'hb-ot-layout-gpos-table.hh', + 'hb-ot-layout-gsub-table.hh', + 'hb-ot-layout-gsubgpos.hh', + 'hb-ot-layout-jstf-table.hh', + 'hb-ot-layout.cc', + 'hb-ot-layout.hh', + 'hb-ot-map.cc', + 'hb-ot-map.hh', + 'hb-ot-math-table.hh', + 'hb-ot-math.cc', + 'hb-ot-maxp-table.hh', + 'hb-ot-meta-table.hh', + 'hb-ot-meta.cc', + 'hb-ot-metrics.cc', + 'hb-ot-metrics.hh', + 'hb-ot-name-language-static.hh', + 'hb-ot-name-language.hh', + 'hb-ot-name-table.hh', + 'hb-ot-name.cc', + 'hb-ot-os2-table.hh', + 'hb-ot-os2-unicode-ranges.hh', + 'hb-ot-post-macroman.hh', + 'hb-ot-post-table.hh', + 'hb-ot-shape-complex-arabic-fallback.hh', + 'hb-ot-shape-complex-arabic-joining-list.hh', + 'hb-ot-shape-complex-arabic-table.hh', + 'hb-ot-shape-complex-arabic-win1256.hh', + 'hb-ot-shape-complex-arabic.cc', + 'hb-ot-shape-complex-arabic.hh', + 'hb-ot-shape-complex-default.cc', + 'hb-ot-shape-complex-hangul.cc', + 'hb-ot-shape-complex-hebrew.cc', + 'hb-ot-shape-complex-indic-table.cc', + 'hb-ot-shape-complex-indic.cc', + 'hb-ot-shape-complex-indic.hh', + 'hb-ot-shape-complex-khmer.cc', + 'hb-ot-shape-complex-khmer.hh', + 'hb-ot-shape-complex-myanmar.cc', + 'hb-ot-shape-complex-myanmar.hh', + 'hb-ot-shape-complex-syllabic.cc', + 'hb-ot-shape-complex-syllabic.hh', + 'hb-ot-shape-complex-thai.cc', + 'hb-ot-shape-complex-use-table.hh', + 'hb-ot-shape-complex-use.cc', + 'hb-ot-shape-complex-vowel-constraints.cc', + 'hb-ot-shape-complex-vowel-constraints.hh', + 'hb-ot-shape-complex.hh', + 'hb-ot-shape-fallback.cc', + 'hb-ot-shape-fallback.hh', + 'hb-ot-shape-normalize.cc', + 'hb-ot-shape-normalize.hh', + 'hb-ot-shape.cc', + 'hb-ot-shape.hh', + 'hb-ot-stat-table.hh', + 'hb-ot-tag-table.hh', + 'hb-ot-tag.cc', + 'hb-ot-var-avar-table.hh', + 'hb-ot-var-fvar-table.hh', + 'hb-ot-var-gvar-table.hh', + 'hb-ot-var-hvar-table.hh', + 'hb-ot-var-mvar-table.hh', + 'hb-ot-var.cc', + 'hb-ot-vorg-table.hh', + 'hb-pool.hh', + 'hb-sanitize.hh', + 'hb-serialize.hh', + 'hb-set-digest.hh', + 'hb-set.cc', + 'hb-set.hh', + 'hb-shape-plan.cc', + 'hb-shape-plan.hh', + 'hb-shape.cc', + 'hb-shaper-impl.hh', + 'hb-shaper-list.hh', + 'hb-shaper.cc', + 'hb-shaper.hh', + 'hb-static.cc', + 'hb-string-array.hh', + 'hb-style.cc', + 'hb-ucd-table.hh', + 'hb-ucd.cc', + 'hb-unicode-emoji-table.hh', + 'hb-unicode.cc', + 'hb-unicode.hh', + 'hb-utf.hh', + 'hb-vector.hh', + 'hb.hh', +) + +hb_base_ragel_generated_sources = files( + 'hb-buffer-deserialize-json.hh', + 'hb-buffer-deserialize-text.hh', + 'hb-number-parser.hh', + 'hb-ot-shape-complex-indic-machine.hh', + 'hb-ot-shape-complex-khmer-machine.hh', + 'hb-ot-shape-complex-myanmar-machine.hh', + 'hb-ot-shape-complex-use-machine.hh', +) +hb_base_ragel_sources = [ + 'hb-buffer-deserialize-json.rl', + 'hb-buffer-deserialize-text.rl', + 'hb-number-parser.rl', + 'hb-ot-shape-complex-indic-machine.rl', + 'hb-ot-shape-complex-khmer-machine.rl', + 'hb-ot-shape-complex-myanmar-machine.rl', + 'hb-ot-shape-complex-use-machine.rl', +] + +hb_base_headers = files( + 'hb-aat-layout.h', + 'hb-aat.h', + 'hb-blob.h', + 'hb-buffer.h', + 'hb-common.h', + 'hb-deprecated.h', + 'hb-draw.h', + 'hb-face.h', + 'hb-font.h', + 'hb-map.h', + 'hb-ot-color.h', + 'hb-ot-deprecated.h', + 'hb-ot-font.h', + 'hb-ot-layout.h', + 'hb-ot-math.h', + 'hb-ot-meta.h', + 'hb-ot-metrics.h', + 'hb-ot-name.h', + 'hb-ot-shape.h', + 'hb-ot-var.h', + 'hb-ot.h', + 'hb-set.h', + 'hb-shape-plan.h', + 'hb-shape.h', + 'hb-style.h', + 'hb-unicode.h', + 'hb.h', +) +hb_base_headers += hb_version_h + +# Optional Sources and Headers with external deps + +hb_ft_sources = files('hb-ft.cc') +hb_ft_headers = files('hb-ft.h') + +hb_glib_sources = files('hb-glib.cc') +hb_glib_headers = files('hb-glib.h') + +hb_graphite2_sources = files('hb-graphite2.cc') +hb_graphite2_headers = files('hb-graphite2.h') + +# System-dependent sources and headers + +hb_coretext_sources = files('hb-coretext.cc') +hb_coretext_headers = files('hb-coretext.h') + +hb_directwrite_sources = files('hb-directwrite.cc') +hb_directwrite_headers = files('hb-directwrite.h') + +hb_gdi_sources = files('hb-gdi.cc') +hb_gdi_headers = files('hb-gdi.h') + +hb_uniscribe_sources = files('hb-uniscribe.cc') +hb_uniscribe_headers = files('hb-uniscribe.h') + +# Sources for libharfbuzz-gobject and libharfbuzz-icu +hb_icu_sources = files('hb-icu.cc') +hb_icu_headers = files('hb-icu.h') + +# Sources for libharfbuzz-subset +hb_subset_sources = files( + 'hb-number.cc', + 'hb-number.hh', + 'hb-ot-cff1-table.cc', + 'hb-ot-cff2-table.cc', + 'hb-static.cc', + 'hb-subset-cff-common.cc', + 'hb-subset-cff-common.hh', + 'hb-subset-cff1.cc', + 'hb-subset-cff1.hh', + 'hb-subset-cff2.cc', + 'hb-subset-cff2.hh', + 'hb-subset-input.cc', + 'hb-subset-input.hh', + 'hb-subset-plan.cc', + 'hb-subset-plan.hh', + 'hb-subset.cc', + 'hb-subset.hh', +) + +hb_subset_headers = files('hb-subset.h') + +hb_gobject_sources = files( + 'hb-gobject-structs.cc' +) + +hb_gobject_headers = files( + 'hb-gobject.h', + 'hb-gobject-structs.h', +) + +ragel = find_program('ragel', required: false) +if not ragel.found() + warning('You have to install ragel if you are going to develop HarfBuzz itself') +else + ragel_helper = find_program('gen-ragel-artifacts.py') + foreach rl : hb_base_ragel_sources + hh = rl.split('.')[0] + '.hh' + custom_target('@0@'.format(hh), + build_by_default: true, + input: rl, + output: hh, + command: [ragel_helper, '@OUTPUT@', meson.current_source_dir(), '@INPUT@'], + ) + endforeach +endif + +custom_target('harfbuzz.cc', + build_by_default: true, + output: 'harfbuzz.cc', + input: hb_base_sources + hb_glib_sources + hb_ft_sources + + hb_graphite2_sources + hb_uniscribe_sources + hb_gdi_sources + + hb_directwrite_sources + hb_coretext_sources, + command: [find_program('gen-harfbuzzcc.py'), + '@OUTPUT@', meson.current_source_dir(), '@INPUT@'], +) + +incsrc = include_directories('.') + +hb_sources = hb_base_sources + hb_base_ragel_generated_sources +hb_headers = hb_base_headers + +harfbuzz_deps = [thread_dep, m_dep] + harfbuzz_extra_deps + +libharfbuzz_link_language = 'c' + +if conf.get('HAVE_FREETYPE', 0) == 1 + hb_sources += hb_ft_sources + hb_headers += hb_ft_headers + harfbuzz_deps += [freetype_dep] +endif + +if conf.get('HAVE_GDI', 0) == 1 + hb_sources += hb_gdi_sources + hb_headers += hb_gdi_headers + harfbuzz_deps += gdi_uniscribe_deps +endif + +if conf.get('HAVE_GRAPHITE2', 0) == 1 + hb_sources += hb_graphite2_sources + hb_headers += hb_graphite2_headers + harfbuzz_deps += [graphite2_dep] +endif + +if conf.get('HAVE_GLIB', 0) == 1 + hb_sources += hb_glib_sources + hb_headers += hb_glib_headers + harfbuzz_deps += [glib_dep] +endif + +if conf.get('HAVE_UNISCRIBE', 0) == 1 + hb_sources += hb_uniscribe_sources + hb_headers += hb_uniscribe_headers +endif + +if conf.get('HAVE_DIRECTWRITE', 0) == 1 + hb_sources += hb_directwrite_sources + hb_headers += hb_directwrite_headers + harfbuzz_deps += directwrite_dep + # hb-directwrite needs a C++ linker + libharfbuzz_link_language = 'cpp' +endif + +if conf.get('HAVE_CORETEXT', 0) == 1 + hb_sources += hb_coretext_sources + hb_headers += hb_coretext_headers + harfbuzz_deps += coretext_deps +endif + +have_icu = conf.get('HAVE_ICU', 0) == 1 +have_icu_builtin = conf.get('HAVE_ICU_BUILTIN', 0) == 1 + +if have_icu and have_icu_builtin + hb_sources += hb_icu_sources + hb_headers += hb_icu_headers + harfbuzz_deps += [icu_dep] +endif + +# harfbuzz +gen_def = find_program('gen-def.py') + +harfbuzz_def_command_args = [gen_def, '@OUTPUT@', '@INPUT@'] +if get_option('experimental_api') + harfbuzz_def_command_args += '--experimental-api' +endif + +harfbuzz_def = custom_target('harfbuzz.def', + command: harfbuzz_def_command_args, + input: hb_headers, + output: 'harfbuzz.def') +defs_list = [harfbuzz_def] + +version = '0.@0@.0'.format(hb_version_int) + +extra_hb_cpp_args = [] +if cpp.get_id() == 'msvc' + if get_option('default_library') != 'static' + extra_hb_cpp_args += '-DHB_DLL_EXPORT' + endif + hb_so_version = '' +else + hb_so_version = '0' +endif + +if get_option('fuzzer_ldflags') != '' + extra_hb_cpp_args += ['-DHB_CUSTOM_MALLOC'] + hb_sources += 'failing-alloc.c' + hb_subset_sources += 'failing-alloc.c' + hb_icu_sources += 'failing-alloc.c' + hb_gobject_sources += 'failing-alloc.c' +endif + +darwin_versions = [hb_version_int, '@0@.0.0'.format(hb_version_int)] + +libharfbuzz = library('harfbuzz', hb_sources, + include_directories: incconfig, + dependencies: harfbuzz_deps, + cpp_args: cpp_args + extra_hb_cpp_args, + soversion: hb_so_version, + version: version, + install: true, + darwin_versions: darwin_versions, + link_language: libharfbuzz_link_language, +) + +libharfbuzz_dep = declare_dependency( + link_with: libharfbuzz, + include_directories: incsrc, + dependencies: harfbuzz_deps) + +# harfbuzz-subset +harfbuzz_subset_def = custom_target('harfbuzz-subset.def', + command: [gen_def, '@OUTPUT@', '@INPUT@'], + input: hb_subset_headers, + output: 'harfbuzz-subset.def') +defs_list += [harfbuzz_subset_def] + +libharfbuzz_subset = library('harfbuzz-subset', hb_subset_sources, + include_directories: incconfig, + dependencies: [m_dep], + link_with: [libharfbuzz], + cpp_args: cpp_args + extra_hb_cpp_args, + soversion: hb_so_version, + version: version, + install: true, + darwin_versions: darwin_versions, + link_language: 'c', +) + +libharfbuzz_subset_dep = declare_dependency( + link_with: libharfbuzz_subset, + include_directories: incsrc, + dependencies: [m_dep]) + +if get_option('tests').enabled() + # TODO: MSVC gives the following, + # error LNK2019: unresolved external symbol "unsigned __int64 const * const _hb_NullPool" + if cpp.get_id() != 'msvc' + noinst_programs = { + 'main': 'main.cc', + 'test-basics': 'test.cc', + 'test-buffer-serialize': 'test-buffer-serialize.cc', + 'test-ot-meta': 'test-ot-meta.cc', + 'test-ot-name': 'test-ot-name.cc', + 'test-ot-glyphname': 'test-ot-glyphname.cc', + 'test-ot-gpos-size-params': 'test-gpos-size-params.cc', + 'test-ot-gsub-would-substitute': 'test-gsub-would-substitute.cc', + } + foreach name, source : noinst_programs + executable(name, source, + include_directories: incconfig, + cpp_args: cpp_args, + dependencies: libharfbuzz_dep, + install: false, + ) + endforeach + endif + + compiled_tests = { + 'test-algs': ['test-algs.cc', 'hb-static.cc'], + 'test-array': ['test-array.cc'], + 'test-repacker': ['test-repacker.cc', 'hb-static.cc'], + 'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'], + 'test-iter': ['test-iter.cc', 'hb-static.cc'], + 'test-meta': ['test-meta.cc', 'hb-static.cc'], + 'test-number': ['test-number.cc', 'hb-number.cc'], + 'test-ot-tag': ['hb-ot-tag.cc'], + 'test-unicode-ranges': ['test-unicode-ranges.cc'], + 'test-bimap': ['test-bimap.cc', 'hb-static.cc'], + } + foreach name, source : compiled_tests + if cpp.get_id() == 'msvc' and source.contains('hb-static.cc') + # TODO: MSVC doesn't like tests having hb-static.cc, fix them + continue + endif + test(name, executable(name, source, + include_directories: incconfig, + cpp_args: cpp_args + ['-DMAIN', '-UNDEBUG'], + dependencies: libharfbuzz_dep, + install: false, + ), suite: ['src']) + endforeach +endif + +pkgmod.generate(libharfbuzz, + description: 'HarfBuzz text shaping library', + subdirs: [meson.project_name()], + version: meson.project_version(), +) + +pkgmod.generate(libharfbuzz_subset, + description: 'HarfBuzz font subsetter', + requires: ['harfbuzz = @0@'.format(meson.project_version())], + subdirs: [meson.project_name()], + version: meson.project_version(), +) + +libharfbuzz_icu_dep = null_dep +if have_icu and not have_icu_builtin + harfbuzz_icu_def = custom_target('harfbuzz-icu.def', + command: [gen_def, '@OUTPUT@', '@INPUT@'], + input: [hb_icu_headers], + output: 'harfbuzz-icu.def') + defs_list += [harfbuzz_icu_def] + + libharfbuzz_icu = library('harfbuzz-icu', [hb_icu_sources, hb_icu_headers], + include_directories: incconfig, + dependencies: icu_dep, + link_with: [libharfbuzz], + cpp_args: cpp_args + extra_hb_cpp_args, + soversion: hb_so_version, + version: version, + install: true, + darwin_versions: darwin_versions, + # ICU links to stdc++ anyway so the default linker is good + # link_language: 'c', + ) + + libharfbuzz_icu_dep = declare_dependency( + link_with: libharfbuzz_icu, + include_directories: incsrc, + dependencies: icu_dep) + + pkgmod.generate(libharfbuzz_icu, + description: 'HarfBuzz text shaping library ICU integration', + requires: ['harfbuzz = @0@'.format(meson.project_version())], + subdirs: [meson.project_name()], + version: meson.project_version(), + ) + + install_headers(hb_icu_headers, subdir: meson.project_name()) +endif + +have_gobject = conf.get('HAVE_GOBJECT', 0) == 1 + +cmake_config = configuration_data() +cmake_config.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) +cmake_config.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) +cmake_config.set('HB_LIBTOOL_VERSION_INFO', hb_libtool_version_info) +cmake_config.set('have_gobject', '@0@'.format(have_gobject)) +configure_file(input: 'harfbuzz-config.cmake.in', + output: 'harfbuzz-config.cmake', + configuration: cmake_config, + install_dir: join_paths(get_option('libdir'), 'cmake', 'harfbuzz'), +) + +libharfbuzz_gobject_dep = null_dep +if have_gobject + gnome = import('gnome') + + h_templ = configure_file( + input: 'hb-gobject-enums.h.tmpl', + output: 'hb-gobject-enums-tmp.h.tmpl', + configuration: configuration_data(), + format: 'cmake') + + cc_templ = configure_file( + input: 'hb-gobject-enums.cc.tmpl', + output: 'hb-gobject-enums-tmp.cc.tmpl', + configuration: configuration_data(), + format: 'cmake') + + enums = gnome.mkenums('hb-gobject', + sources: hb_headers, + h_template: h_templ, + c_template: cc_templ, + identifier_prefix: 'hb_', + symbol_prefix: 'hb_gobject', + ) + + enum_c = custom_target('hb-gobject-enums.cc', + input: enums[0], + output: 'hb-gobject-enums.cc', + command: [find_program('fix_get_types.py'), '@INPUT@', '@OUTPUT@'] + ) + + enum_h = custom_target('hb-gobject-enums.h', + input: enums[1], + output: 'hb-gobject-enums.h', + command: [find_program('fix_get_types.py'), '@INPUT@', '@OUTPUT@'], + install: true, + install_dir: join_paths(get_option('prefix'), get_option('includedir'), meson.project_name()), + ) + + hb_gobject_sources += [enum_c] + + harfbuzz_gobject_def = custom_target('harfbuzz-gobject.def', + command: [gen_def, '@OUTPUT@', '@INPUT@'], + input: [hb_gobject_headers, enum_h], + output: 'harfbuzz-gobject.def') + defs_list += [harfbuzz_gobject_def] + + libharfbuzz_gobject = library('harfbuzz-gobject', [hb_gobject_sources, enum_c, enum_h], + include_directories: incconfig, + dependencies: [glib_dep, gobject_dep], + link_with: [libharfbuzz], + cpp_args: cpp_args + extra_hb_cpp_args, + soversion: hb_so_version, + version: version, + install: true, + darwin_versions: darwin_versions, + link_language: 'c', + ) + + gir = find_program('g-ir-scanner', required: get_option('introspection')) + build_gir = gir.found() and (not meson.is_cross_build() or get_option('introspection').enabled()) + + build_gir = build_gir and get_option('default_library') != 'static' + if not build_gir and get_option('introspection').enabled() + error('Introspection support is requested but the default library option should be shared or both') + endif + + if build_gir + conf.set('HAVE_INTROSPECTION', 1) + hb_gen_files_gir = gnome.generate_gir(libharfbuzz_gobject, + sources: [hb_headers, hb_sources, hb_gobject_headers, hb_gobject_sources, enum_h], + dependencies: libharfbuzz_dep, + namespace: 'HarfBuzz', + nsversion: '0.0', + identifier_prefix: 'hb_', + symbol_prefix: ['hb', 'hb_gobject'], + includes: ['GObject-2.0'], + export_packages: ['harfbuzz-gobject'], + header: 'hb-gobject.h', + install: true, + extra_args: ['--cflags-begin', + '-DHB_NO_SINGLE_HEADER_ERROR', + '-DHAVE_GOBJECT', + '-DHB_EXTERN=', + '--cflags-end']) + endif + + if build_gir + libharfbuzz_gobject_sources = hb_gen_files_gir + else + libharfbuzz_gobject_sources = hb_gobject_sources + endif + + libharfbuzz_gobject_dep = declare_dependency( + link_with: libharfbuzz_gobject, + include_directories: incsrc, + sources: libharfbuzz_gobject_sources, + dependencies: [glib_dep, gobject_dep]) + + pkgmod.generate(libharfbuzz_gobject, + description: 'HarfBuzz text shaping library GObject integration', + requires: ['harfbuzz = @0@'.format(meson.project_version()), 'glib-2.0', 'gobject-2.0'], + subdirs: [meson.project_name()], + version: meson.project_version(), + ) + + install_headers(hb_gobject_headers, subdir: meson.project_name()) +else + if get_option('introspection').enabled() + error('introspection requires gobject to be enabled') + endif +endif + +if get_option('tests').enabled() + dist_check_script = [ + 'check-c-linkage-decls', + 'check-externs', + 'check-header-guards', + 'check-includes', + ] + + env = environment() + env.set('srcdir', meson.current_source_dir()) + env.set('builddir', meson.current_build_dir()) + env.set('libs', meson.current_build_dir()) # TODO: Merge this with builddir after autotools removal + HBSOURCES = [] + foreach f : hb_sources + HBSOURCES += '@0@'.format(f) + endforeach + env.set('HBSOURCES', ' '.join(HBSOURCES)) + HBHEADERS = [] + foreach f : hb_headers + HBHEADERS += '@0@'.format(f) + endforeach + env.set('HBHEADERS', ' '.join(HBHEADERS)) + + if cpp.get_id() != 'msvc' and not meson.is_cross_build() # ensure the local tools are usable + if meson.version().version_compare('>=0.55') + dist_check_script += 'check-libstdc++' + endif + dist_check_script += ['check-static-inits', 'check-symbols'] + endif + + foreach name : dist_check_script + if name == 'check-symbols' + test_depends = defs_list + else + test_depends = [] + endif + test(name, find_program(name + '.py'), + env: env, + depends: test_depends, + suite: ['src'], + ) + endforeach +endif + +install_headers(hb_headers + hb_subset_headers, subdir: meson.project_name()) diff --git a/src/ms-use/COPYING b/src/ms-use/COPYING new file mode 100644 index 0000000000000000000000000000000000000000..9e841e7a26e4eb057b24511e7b92d42b257a80e5 --- /dev/null +++ b/src/ms-use/COPYING @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/src/ms-use/IndicPositionalCategory-Additional.txt b/src/ms-use/IndicPositionalCategory-Additional.txt new file mode 100644 index 0000000000000000000000000000000000000000..8d325adbd375974fae76c4477be18854926ed938 --- /dev/null +++ b/src/ms-use/IndicPositionalCategory-Additional.txt @@ -0,0 +1,102 @@ +# Override values For Indic_Positional_Category +# Not derivable +# Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 +# Updated for Unicode 10.0 by Andrew Glass 2017-07-25 +# Ammended for Unicode 10.0 by Andrew Glass 2018-09-21 +# Updated for L2/19-083 by Andrew Glass 2019-05-06 +# Updated for Unicode 12.1 by Andrew Glass 2019-05-30 +# Updated for Unicode 13.0 by Andrew Glass 2020-07-28 + +# ================================================ +# ================================================ +# OVERRIDES TO ASSIGNED VALUES +# ================================================ +# ================================================ + +# Indic_Positional_Category=Bottom +0F72 ; Bottom # Mn TIBETAN VOWEL SIGN I # Not really below, but need to override to fit into Universal model +0F7A..0F7D ; Bottom # Mn [4] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN OO # Not really below, but need to override to fit into Universal model +0F80 ; Bottom # Mn TIBETAN VOWEL SIGN REVERSED I # Not really below, but need to override to fit into Universal model +A9BF ; Bottom # Mc JAVANESE CONSONANT SIGN CAKRA +11127..11129; Bottom # Mn [3] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN II +1112D ; Bottom # Mn CHAKMA VOWEL SIGN AI +11130 ; Bottom # Mn CHAKMA VOWEL SIGN OI + +# ================================================ + +# Indic_Positional_Category=Left +1C29 ; Left # Mc LEPCHA VOWEL SIGN OO # Reduced from Top_And_Left + +# ================================================ + + +# Indic_Positional_Category=Right +A9BE ; Right # Mc JAVANESE CONSONANT SIGN PENGKAL # Reduced from Bottom_And_Right +10A0C ; Right # Mn KHAROSHTHI VOWEL LENGTH MARK # Follows vowels and precedes vowel modifiers +11942 ; Right # Mc DIVES AKURU MEDIAL RA # Reduced from Bottom_And_Right + +# ================================================ + +# Indic_Positional_Category=Top +0F74 ; Top # Mn TIBETAN VOWEL SIGN U # Not really above, but need to override to fit into Universal model +1A18 ; Top # Mn BUGINESE VOWEL SIGN U # Workaround to allow below to occur before above by treating all below marks as above +AA35   ; Top # Mn       CHAM CONSONANT SIGN + +# ================================================ + +# Indic_Positional_Category=Top_And_Right +0E33 ; Top_And_Right # Lo THAI CHARACTER SARA AM # IMC has Right, which seems to be a mistake. +0EB3 ; Top_And_Right # Lo LAO VOWEL SIGN AM # IMC has Right, which seems to be a mistake. + +# ================================================ +# ================================================ +# VALUES NOT ASSIGNED IN Indic_Positional_Category +# ================================================ +# ================================================ + +# Indic_Positional_Category=Bottom +0859..085B ; Bottom # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +18A9 ; Bottom # Mn MONGOLIAN LETTER ALI GALI DAGALGA +10AE5 ; Bottom # Mn MANICHAEAN ABBREVIATION MARK ABOVE # Not really bottom, but here for ccc to control +10AE6 ; Bottom # Mn MANICHAEAN ABBREVIATION MARK BELOW +10F46..10F47 ; Bottom # Mn [2] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING TWO DOTS BELOW +10F48..10F4A ; Bottom # Mn [3] SOGDIAN COMBINING DOT ABOVE..SOGDIAN COMBINING CURVE ABOVE # Overriden to below because ccc-based Normalization controls order +10F4B ; Bottom # Mn SOGDIAN COMBINING CURVE BELOW +10F4C ; Bottom # Mn SOGDIAN COMBINING HOOK ABOVE # Overriden to below because ccc-based Normalization controls order +10F4D..10F50 ; Bottom # Mn [4] SOGDIAN COMBINING HOOK BELOW..SOGDIAN COMBINING STROKE BELOW +16F4F ; Bottom # Mn MIAO SIGN CONSONANT MODIFIER BAR +16F51..16F87 ; Bottom # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI +16F8F..16F92 ; Bottom # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW + +# ================================================ + +# Indic_Positional_Category=Left +103C ; Left # Mc MYANMAR CONSONANT SIGN MEDIAL RA + +# ================================================ + +# Indic_Positional_Category=Top +07EB..07F3 ; Top # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE +07FD ; Top # Mn NKO DANTAYALAN # Not really top, but assigned here to allow ccc to control mark order +1885..1886 ; Top # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +10EAB..10EAC ; Top # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +1E944..1E94A ; Top # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA +10D24..10D27 ; Top # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI +16B30..16B36 ; Top # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +1E130..1E136 ; Top # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E2EC..1E2EF ; Top # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI + +# ================================================ + +# Indic_Positional_Category=Overstruck +1BC9D..1BC9E ; Overstruck # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK + +# ================================================ +# ================================================ +# Deliberately suppressed +# ================================================ +# ================================================ + +# Indic_Positional_Category=NA +180B..180D ; NA # Mn [3] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN FREE VARIATION SELECTOR THREE +2D7F ; NA # Mn TIFINAGH CONSONANT JOINER diff --git a/src/HBIndicVowelConstraints.txt b/src/ms-use/IndicShapingInvalidCluster.txt similarity index 93% rename from src/HBIndicVowelConstraints.txt rename to src/ms-use/IndicShapingInvalidCluster.txt index 146ae1cb80c62e382eea6b3ed796ae4130f2999e..c4efe1472a5c09d60854b614b4a183538007bc3d 100644 --- a/src/HBIndicVowelConstraints.txt +++ b/src/ms-use/IndicShapingInvalidCluster.txt @@ -1,5 +1,12 @@ -# Copied from https://docs.microsoft.com/en-us/typography/script-development/use -# On October 23, 2018; with documentd dated 02/07/2018. +# IndicShapingInvalidCluster.txt +# Date: 2015-03-12, 21:17:00 GMT [AG] +# Date: 2019-11-08, 23:22:00 GMT [AG] +# +# This file defines the following property: +# +# Indic_Shaping_Invalid_Cluster +# +# Scope: This file enumerates sequences of characters that should be treated as invalid clusters 0905 0946 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E 0905 093E ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA @@ -48,6 +55,7 @@ 0B05 0B3E ; # ORIYA LETTER A, ORIYA VOWEL SIGN AA 0B0F 0B57 ; # ORIYA LETTER E, ORIYA AU LENGTH MARK 0B13 0B57 ; # ORIYA LETTER O, ORIYA AU LENGTH MARK + 0B85 0BC2 ; # TAMIL LETTER A, TAMIL VOWEL SIGN UU 0C12 0C55 ; # TELUGU LETTER O, TELUGU LENGTH MARK 0C12 0C4C ; # TELUGU LETTER O, TELUGU VOWEL SIGN AU 0C3F 0C55 ; # TELUGU VOWEL SIGN I, TELUGU LENGTH MARK @@ -68,11 +76,11 @@ 0D8D 0DD8 ; # SINHALA LETTER IRUYANNA, SINHALA VOWEL SIGN GAETTA-PILLA 0D8F 0DDF ; # SINHALA LETTER ILUYANNA, SINHALA VOWEL SIGN GAYANUKITTA 0D91 0DCA ; # SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA - 0D91 0DD9 ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA + 0D91 0DD9 ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA 0D91 0DDA ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN DIGA KOMBUVA 0D91 0DDC ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA 0D91 0DDD ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA - 0D91 0DDD ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA + 0D91 0DDE ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA 0D94 0DDF ; # SINHALA LETTER OYANNA, SINHALA VOWEL SIGN GAYANUKITTA 11005 11038 ; # BRAHMI LETTER A, BRAHMI VOWEL SIGN AA 1100B 1103E ; # BRAHMI LETTER VOCALIC R, BRAHMI VOWEL SIGN VOCALIC R diff --git a/src/ms-use/IndicSyllabicCategory-Additional.txt b/src/ms-use/IndicSyllabicCategory-Additional.txt new file mode 100644 index 0000000000000000000000000000000000000000..0912055209aae15199bec9e2486e1c2a6a61c0be --- /dev/null +++ b/src/ms-use/IndicSyllabicCategory-Additional.txt @@ -0,0 +1,209 @@ +# Override values For Indic_Syllabic_Category +# Not derivable +# Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17 +# Updated for Unicode 10.0 by Andrew Glass 2017-07-25 +# Updated for Unicode 12.1 by Andrew Glass 2019-05-24 +# Updated for Unicode 13.0 by Andrew Glass 2020-07-28 + +# ================================================ +# OVERRIDES TO ASSIGNED VALUES +# ================================================ + +# Indic_Syllabic_Category=Bindu +193A ; Bindu # Mn LIMBU SIGN KEMPHRENG +AA29 ; Bindu # Mn  CHAM VOWEL SIGN AA +10A0D ; Bindu # Mn KHAROSHTHI SIGN DOUBLE RING BELOW + +# ================================================ + +# Indic_Syllabic_Category=Consonant +0840..0858 ; Consonant # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN +0F00..0F01 ; Consonant # Lo [2] TIBETAN SYLLABLE OM..TIBETAN MARK GTER YIG MGO TRUNCATED +0F04..0F06 ; Consonant # Po TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK CARET YIG MGO PHUR SHAD MA +19C1..19C7 ; Consonant # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B # Reassigned to avoid clustering with a base consonant +25CC ; Consonant # So DOTTED CIRCLE + +# ================================================ + +# Indic_Syllabic_Category=Consonant_Dead +0F7F ; Consonant_Dead # Mc TIBETAN SIGN RNAM BCAD # reassigned so that visarga will form an independent cluster + +# ================================================ + +# Indic_Syllabic_Category=Consonant_Final +0F35 ; Consonant_Final # Mn TIBETAN MARK NGAS BZUNG NYI ZLA +0F37 ; Consonant_Final # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS +0FC6 ; Consonant_Final # Mn TIBETAN SYMBOL PADMA GDAN + +# ================================================ + +# Indic_Syllabic_Category=Consonant_Final_Modifier +1C36 ; Consonant_Final_Modifier # Mn LEPCHA SIGN RAN + +# ================================================ + +# Indic_Syllabic_Category=Gemination_Mark +11134 ; Gemination_Mark # Mc CHAKMA MAAYYAA + +# ================================================ + +# Indic_Syllabic_Category=Nukta +0F71 ; Nukta # Mn TIBETAN VOWEL SIGN AA # Reassigned to get this before an above vowel +10A38..10A3A ; Nukta # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW + +# ================================================ + +# Indic_Syllabic_Category=Tone_Mark +A982 ; Tone_Mark # Mn JAVANESE SIGN LAYAR# Not a repha, because it does not reorder to front of cluster +1A7B..1A7C ; Tone_Mark # Mn [2] TAI THAM SIGN MAI SAM..TAI THAM SIGN KHUEN-LUE KARAN +1A7F ; Tone_Mark # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT + +# ================================================ + +# Indic_Syllabic_Category=Vowel_Independent +AAB1 ; Vowel_Independent # Lo TAI VIET VOWEL AA +AABA ; Vowel_Independent # Lo TAI VIET VOWEL UA +AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN + +# ================================================ +# ================================================ +# VALUES NOT ASSIGNED IN Indic_Syllabic_Category +# ================================================ +# ================================================ + +# Indic_Syllabic_Category=Consonant +0800..0815 ; Consonant # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF +1800 ; Consonant # Po MONGOLIAN BIRGA # Reassigned so that legacy Birga + MFVS sequences still work +1807 ; Consonant # Po MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER +180A ; Consonant # Po MONGOLIAN NIRUGU +1820..1878 ; Consonant # Lo [88] MONGOLIAN LETTER A..MONGOLIAN LETTER CHA WITH TWO DOTS +1843 ; Consonant # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN +2D30..2D67 ; Consonant # Lo [56] TIFINAGH LETTER YA..TIFINAGH LETTER YO +2D6F ; Consonant # Lm TIFINAGH MODIFIER LETTER LABIALIZATION MARK +10AC0..10AC7 ; Consonant # Lo [8] MANICHAEAN LETTER ALEPH..MANICHAEAN LETTER WAW +10AC9..10AE4 ; Consonant # Lo [28] MANICHAEAN LETTER ZAYIN..MANICHAEAN LETTER TAW +10D00..10D23 ; Consonant # Lo [36] HANIFI ROHINGYA LETTER A..HANIFI ROHINGYA MARK NA KHONNA +10E80..10EA9 ; Consonant # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET +10EB0..10EB1 ; Consonant # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE +10F30..10F45 ; Consonant # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN +111DA ; Consonant # Lo SHARADA EKAM +#HIEROGLYPHS moved to new category +#13000..1342E ; Consonant # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 +#For the Begin and End segment to be handled fully correctly, the cluster model needs to be modified. +#13437..13438 ; Consonant # Lo [2] EGYPTIAN HIEROGLYPH BEGIN SEGMENT..EGYPTIAN HIEROGLYPH END SEGMENT +16B00..16B2F ; Consonant # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU +16F00..16F4A ; Consonant # Lo [75] MIAO LETTER PA..MIAO LETTER RTE +16FE4 ; Consonant # Mn KHITAN SMALL SCRIPT FILLER +18B00..18CD5 ; Consonant # Lo [470] KHITAN SMALL SCRIPT CHARACTER-18B00..KHITAN SMALL SCRIPT CHARACTER-18CD5 +1BC00..1BC6A ; Consonant # Lo [107] DUPLOYAN LETTER H..DUPLOYAN LETTER VOCALIC M +1BC70..1BC7C ; Consonant # Lo [13] DUPLOYAN AFFIX LEFT HORIZONTAL SECANT..DUPLOYAN AFFIX ATTACHED TANGENT HOOK +1BC80..1BC88 ; Consonant # Lo [9] DUPLOYAN AFFIX HIGH ACUTE..DUPLOYAN AFFIX HIGH VERTICAL +1BC90..1BC99 ; Consonant # Lo [10] DUPLOYAN AFFIX LOW ACUTE..DUPLOYAN AFFIX LOW ARROW +1E100..1E12C ; Consonant # Lo [45] NYIAKENG PUACHUE HMONG LETTER MA..NYIAKENG PUACHUE HMONG LETTER W +1E137..1E13D ; Consonant # Lm [7] NYIAKENG PUACHUE HMONG SIGN FOR PERSON..NYIAKENG PUACHUE HMONG SYLLABLE LENGTHENER +1E14E ; Consonant # Lo NYIAKENG PUACHUE HMONG LOGOGRAM NYAJ +1E14F ; Consonant # So NYIAKENG PUACHUE HMONG CIRCLED CA +1E2C0..1E2EB ; Consonant # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH +1E900..1E921 ; Consonant # Lu [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA +1E922..1E943 ; Consonant # Ll [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA +1E94B ; Consonant # Lm ADLAM NASALIZATION MARK + +# ================================================ + +# Indic_Syllabic_Category=Consonant_Placeholder +1880..1884 ; Consonant_Placeholder # Lo [5] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER ALI GALI INVERTED UBADAMA + +# ================================================ + +# Indic_Syllabic_Category=Gemination_Mark +10D27 ; Gemination_Mark # Mn HANIFI ROHINGYA SIGN TASSI + +# ================================================ + +# Indic_Syllabic_Category=Modifying_Letter +FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SELECTOR-16# Need to treat them as isolated bases so they don't merge with a cluster in invalid scenarios +16F50 ; Modifying_Letter # Lo MIAO LETTER NASALIZATION + +# ================================================ + +# Indic_Syllabic_Category=Nukta +0859..085B ; Nukta # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK +0F39 ; Nukta # Mn TIBETAN MARK TSA -PHRU # NOW IN UNICODE 10.0 +1885..1886 ; Nukta # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA +18A9 ; Nukta # Mn MONGOLIAN LETTER ALI GALI DAGALGA +1B6B..1B73 ; Nukta # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG +10AE5..10AE6 ; Nukta # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW +16F4F ; Nukta # Mn MIAO SIGN CONSONANT MODIFIER BAR +1BC9D..1BC9E ; Nukta # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK +1E944..1E94A ; Nukta # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA + +# ================================================ + +# Indic_Syllabic_Category=Number +10D30..10D39 ; Number # Nd [10] HANIFI ROHINGYA DIGIT ZERO..HANIFI ROHINGYA DIGIT NINE +10F51..10F54 ; Number # No [4] SOGDIAN NUMBER ONE..SOGDIAN NUMBER ONE HUNDRED +1E140..1E149 ; Number # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE +1E2F0..1E2F9 ; Number # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE +1E950..1E959 ; Number # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE + +# ================================================ + +# Indic_Syllabic_Category=Tone_Mark +07EB..07F3 ; Tone_Mark # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE +07FD ; Tone_Mark # Mn NKO DANTAYALAN +0F86..0F87 ; Tone_Mark # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +17CF ; Tone_Mark # Mn KHMER SIGN AHSDA +10D24..10D26 ; Tone_Mark # Mn [3] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TANA +10F46..10F50 ; Tone_Mark # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW +16B30..16B36 ; Tone_Mark # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM +16F8F..16F92 ; Tone_Mark # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW +1E130..1E136 ; Tone_Mark # Mn [7] NYIAKENG PUACHUE HMONG TONE-B..NYIAKENG PUACHUE HMONG TONE-D +1E2EC..1E2EF ; Tone_Mark # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI + +# ================================================ + +# Indic_Syllabic_Category=Virama +2D7F ; Virama # Mn TIFINAGH CONSONANT JOINER +13430..13436 ; Virama # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE + +# ================================================ + +# Indic_Syllabic_Category=Vowel_Independent +AAB1 ; Vowel_Independent # Lo TAI VIET VOWEL AA +AABA ; Vowel_Independent # Lo TAI VIET VOWEL UA +AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN + +# ================================================ + +# Indic_Syllabic_Category=Vowel_Dependent +0B55 ; Vowel_Dependent # Mn ORIYA SIGN OVERLINE +10EAB..10EAC ; Vowel_Dependent # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK +16F51..16F87 ; Vowel_Dependent # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI + +# ================================================ +# ================================================ +# PROPERTIES NOT ASSIGNED IN Indic_Syllabic_Category +# ================================================ +# ================================================ + +# USE_Syllabic_Category=Hieroglyph +# 13000..1342E ; Hieroglyph # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032 + +# ================================================ + +# USE_Syllabic_Category=Hieroglyph_Joiner +# 13430..13436 ; Hieroglyph_Joiner # Cf EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE + +# ================================================ + +# USE_Syllabic_Category= Hieroglyph_Segment_Begin +# 13437 ; Hieroglyph_Segment_Begin # Cf EGYPTIAN HIEROGLYPH BEGIN SEGMENT + +# ================================================ + +# USE_Syllabic_Category= Hieroglyph_Segment_End +# 13438 ; Hieroglyph_Segment_End # Cf EGYPTIAN HIEROGLYPH END SEGMENT + +# ================================================ + +# eof diff --git a/src/sample.py b/src/sample.py index 5d65aa09e1ddd3ec3caddc57341234d1030eadef..fd8504800f24d133d4c19ee9596a0a5456560b38 100755 --- a/src/sample.py +++ b/src/sample.py @@ -1,27 +1,12 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import print_function, division, absolute_import +#!/usr/bin/env python3 import sys import array from gi.repository import HarfBuzz as hb from gi.repository import GLib -# Python 2/3 compatibility -try: - unicode -except NameError: - unicode = str - -def tounicode(s, encoding='utf-8'): - if not isinstance(s, unicode): - return s.decode(encoding) - else: - return s - fontdata = open (sys.argv[1], 'rb').read () -text = tounicode(sys.argv[2]) +text = sys.argv[2] # Need to create GLib.Bytes explicitly until this bug is fixed: # https://bugzilla.gnome.org/show_bug.cgi?id=729541 blob = hb.glib_blob_create (GLib.Bytes.new (fontdata)) @@ -35,11 +20,11 @@ hb.font_set_scale (font, upem, upem) hb.ot_font_set_funcs (font) buf = hb.buffer_create () -class Debugger(object): +class Debugger (object): def message (self, buf, font, msg, data, _x_what_is_this): - print(msg) + print (msg) return True -debugger = Debugger() +debugger = Debugger () hb.buffer_set_message_func (buf, debugger.message, 1, 0) ## @@ -48,17 +33,16 @@ hb.buffer_set_message_func (buf, debugger.message, 1, 0) # # See https://github.com/harfbuzz/harfbuzz/pull/271 # -if False: - # If you do not care about cluster values reflecting Python - # string indices, then this is quickest way to add text to - # buffer: - hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1) - # Otherwise, then following handles both narrow and wide - # Python builds (the first item in the array is BOM, so we skip it): -elif sys.maxunicode == 0x10FFFF: - hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32'))[1:], 0, -1) +# If you do not care about cluster values reflecting Python +# string indices, then this is quickest way to add text to +# buffer: +# hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1) +# Otherwise, then following handles both narrow and wide +# Python builds (the first item in the array is BOM, so we skip it): +if sys.maxunicode == 0x10FFFF: + hb.buffer_add_utf32 (buf, array.array ('I', text.encode ('utf-32'))[1:], 0, -1) else: - hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16'))[1:], 0, -1) + hb.buffer_add_utf16 (buf, array.array ('H', text.encode ('utf-16'))[1:], 0, -1) hb.buffer_guess_segment_properties (buf) @@ -69,11 +53,11 @@ del font infos = hb.buffer_get_glyph_infos (buf) positions = hb.buffer_get_glyph_positions (buf) -for info,pos in zip(infos, positions): +for info, pos in zip (infos, positions): gid = info.codepoint cluster = info.cluster x_advance = pos.x_advance x_offset = pos.x_offset y_offset = pos.y_offset - print("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset)) + print ("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset)) diff --git a/src/test-algs.cc b/src/test-algs.cc index 333a892429d58881b7322b962a31c4a566982c58..f8b8ff66682e3b1255bfe1e8b9a3815eb364a147 100644 --- a/src/test-algs.cc +++ b/src/test-algs.cc @@ -87,5 +87,9 @@ main (int argc, char **argv) assert (hb_add (2) (5) == 7); assert (hb_add (5) (2) == 7); + x = 1; + assert (++hb_inc (x) == 3); + assert (x == 3); + return 0; } diff --git a/src/test-array.cc b/src/test-array.cc new file mode 100644 index 0000000000000000000000000000000000000000..6c888138e74fd6aa44003a18748e3d187206fd96 --- /dev/null +++ b/src/test-array.cc @@ -0,0 +1,76 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "hb.hh" +#include "hb-array.hh" + +static void +test_reverse () +{ + int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + hb_array_t a (values, 9); + a.reverse(); + + int expected_values[] = {9, 8, 7, 6, 5, 4, 3, 2, 1}; + hb_array_t expected (expected_values, 9); + assert (a == expected); +} + +static void +test_reverse_range () +{ + int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + hb_array_t a (values, 9); + a.reverse(2, 6); + + int expected_values[] = {1, 2, 6, 5, 4, 3, 7, 8, 9}; + hb_array_t expected (expected_values, 9); + assert (a == expected); +} + +static void +test_reverse_invalid () +{ + int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + hb_array_t a (values, 9); + + a.reverse(4, 3); + a.reverse(2, 3); + a.reverse(5, 5); + a.reverse(12, 15); + + int expected_values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + hb_array_t expected (expected_values, 9); + assert (a == expected); +} + +int +main (int argc, char **argv) +{ + test_reverse (); + test_reverse_range (); + test_reverse_invalid (); +} diff --git a/src/test-buffer-serialize.cc b/src/test-buffer-serialize.cc index 6393f0b7f68ca181cb244757b08b1f2ca19bdd51..4a3d4bc107be496355e1bd53793f8b97dbca9552 100644 --- a/src/test-buffer-serialize.cc +++ b/src/test-buffer-serialize.cc @@ -32,8 +32,6 @@ #include "hb-ft.h" #endif -#include - #ifdef HB_NO_OPEN #define hb_blob_create_from_file(x) hb_blob_get_empty () #endif @@ -68,7 +66,7 @@ main (int argc, char **argv) buf = hb_buffer_create (); char line[BUFSIZ], out[BUFSIZ]; - while (fgets (line, sizeof(line), stdin) != nullptr) + while (fgets (line, sizeof(line), stdin)) { hb_buffer_clear_contents (buf); diff --git a/src/test-gpos-size-params.cc b/src/test-gpos-size-params.cc index ad10ed40d4a36317c0ccc1aacdcb9b712f3b86ec..549f5ae06a04ccdc4568dcfeb8076aec5cf70229 100644 --- a/src/test-gpos-size-params.cc +++ b/src/test-gpos-size-params.cc @@ -29,8 +29,6 @@ #include "hb.h" #include "hb-ot.h" -#include - #ifdef HB_NO_OPEN #define hb_blob_create_from_file(x) hb_blob_get_empty () #endif diff --git a/src/test-gsub-would-substitute.cc b/src/test-gsub-would-substitute.cc index 7ad9e084cb6c97b6d1918145cccfac040d6e3dfc..508217dde9ee16d4c353b3c26a321ddfc8360662 100644 --- a/src/test-gsub-would-substitute.cc +++ b/src/test-gsub-would-substitute.cc @@ -29,8 +29,6 @@ #include "hb.h" #include "hb-ot.h" -#include - #ifdef HAVE_FREETYPE #include "hb-ft.h" #endif diff --git a/src/test-iter.cc b/src/test-iter.cc index 156a5fcadda8df94c21b166a2209f354211abc2f..fd201c85e8879bd42bc5759b80baa9b9b010687a 100644 --- a/src/test-iter.cc +++ b/src/test-iter.cc @@ -105,7 +105,7 @@ test_iterator (Iter it) template static void -test_iterable (const Iterable &lst = Null(Iterable)) +test_iterable (const Iterable &lst = Null (Iterable)) { for (auto _ : lst) (void) _; @@ -234,7 +234,7 @@ main (int argc, char **argv) { hb_set_t *set = hb_set_create (); for (unsigned int i = 0; i < temp1; ++i) - hb_set_add (set, i); + hb_set_add (set, i); temp1++; return set; }) @@ -267,7 +267,12 @@ main (int argc, char **argv) hb_iota (); hb_iota (3); hb_iota (3, 2); + assert ((&vl) + 1 == *++hb_iota (&vl, hb_inc)); hb_range (); + hb_repeat (7u); + hb_repeat (nullptr); + hb_repeat (vl) | hb_chop (3); + assert (hb_len (hb_range (10) | hb_take (3)) == 3); assert (hb_range (9).len () == 9); assert (hb_range (2, 9).len () == 7); assert (hb_range (2, 9, 3).len () == 3); diff --git a/src/test-meta.cc b/src/test-meta.cc index 0b6e02c269c76e1c7a5f8832261d14f5c1a7b03c..9436b9038e04486a5f6bab51eb413b127420fafe 100644 --- a/src/test-meta.cc +++ b/src/test-meta.cc @@ -29,6 +29,8 @@ #include +template struct U { typedef T type; }; + int main (int argc, char **argv) { @@ -122,6 +124,9 @@ main (int argc, char **argv) static_assert (hb_is_trivial (X), ""); static_assert (hb_is_trivial (Y), ""); + static_assert (hb_is_signed (hb_unwrap_type (U>>)), ""); + static_assert (hb_is_unsigned (hb_unwrap_type (U>>>)), ""); + /* TODO Add more meaningful tests. */ return 0; diff --git a/src/test-number.cc b/src/test-number.cc new file mode 100644 index 0000000000000000000000000000000000000000..57835288c42ff5881e5c46747a9c1f448c2b6f6f --- /dev/null +++ b/src/test-number.cc @@ -0,0 +1,224 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#include "hb.hh" +#include "hb-number.hh" + + +int +main (int argc, char **argv) +{ + { + const char str[] = "123"; + const char *pp = str; + const char *end = str + 3; + + int pv; + assert (hb_parse_int (&pp, end, &pv)); + assert (pv == 123); + assert (pp - str == 3); + assert (end - pp == 0); + assert (!*end); + } + + { + const char str[] = "123"; + const char *pp = str; + const char *end = str + strlen (str); + + unsigned int pv; + assert (hb_parse_uint (&pp, end, &pv)); + assert (pv == 123); + assert (pp - str == 3); + assert (end - pp == 0); + assert (!*end); + } + + { + const char str[] = "12F"; + const char *pp = str; + const char *end = str + 3; + + unsigned int pv; + assert (hb_parse_uint (&pp, end, &pv, true, 16)); + assert (pv == 0x12F); + assert (pp - str == 3); + assert (end - pp == 0); + assert (!*end); + } + + { + const char str[] = "12Fq"; + const char *pp = str; + const char *end = str + 4; + + unsigned int pv; + assert (!hb_parse_uint (&pp, end, &pv, true, 16)); + assert (hb_parse_uint (&pp, end, &pv, false, 16)); + assert (pv == 0x12F); + assert (pp - str == 3); + assert (end - pp == 1); + assert (!*end); + } + + { + const char str[] = "-123"; + const char *pp = str; + const char *end = str + 4; + + int pv; + assert (hb_parse_int (&pp, end, &pv)); + assert (pv == -123); + assert (pp - str == 4); + assert (end - pp == 0); + assert (!*end); + } + + { + const char str[] = "123"; + const char *pp = str; + assert (ARRAY_LENGTH (str) == 4); + const char *end = str + ARRAY_LENGTH (str); + + unsigned int pv; + assert (hb_parse_uint (&pp, end, &pv)); + assert (pv == 123); + assert (pp - str == 3); + assert (end - pp == 1); + } + + { + const char str[] = "123\0"; + const char *pp = str; + assert (ARRAY_LENGTH (str) == 5); + const char *end = str + ARRAY_LENGTH (str); + + unsigned int pv; + assert (hb_parse_uint (&pp, end, &pv)); + assert (pv == 123); + assert (pp - str == 3); + assert (end - pp == 2); + } + + { + const char str[] = "123V"; + const char *pp = str; + assert (ARRAY_LENGTH (str) == 5); + const char *end = str + ARRAY_LENGTH (str); + + unsigned int pv; + assert (hb_parse_uint (&pp, end, &pv)); + assert (pv == 123); + assert (pp - str == 3); + assert (end - pp == 2); + } + + { + const char str[] = ".123"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str); + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == 123); + assert (pp - str == 4); + assert (end - pp == 1); + } + + { + const char str[] = "0.123"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str) - 1; + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == 123); + assert (pp - str == 5); + assert (end - pp == 0); + } + + { + const char str[] = "0.123e0"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str) - 1; + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == 123); + assert (pp - str == 7); + assert (end - pp == 0); + } + + { + const char str[] = "123e-3"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str) - 1; + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == 123); + assert (pp - str == 6); + assert (end - pp == 0); + } + + { + const char str[] = ".000123e+3"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str) - 1; + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == 123); + assert (pp - str == 10); + assert (end - pp == 0); + } + + { + const char str[] = "-.000000123e6"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str) - 1; + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == -123); + assert (pp - str == 13); + assert (end - pp == 0); + + } + + { + const char str[] = "-1.23E-1"; + const char *pp = str; + const char *end = str + ARRAY_LENGTH (str) - 1; + + double pv; + assert (hb_parse_double (&pp, end, &pv)); + assert ((int) roundf (pv * 1000.) == -123); + assert (pp - str == 8); + assert (end - pp == 0); + } + + return 0; +} diff --git a/src/test-ot-color.cc b/src/test-ot-color.cc deleted file mode 100644 index 3b4c8b6c266b2234a8962ed608e5e1b86ad96bd6..0000000000000000000000000000000000000000 --- a/src/test-ot-color.cc +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright © 2018 Ebrahim Byagowi - * Copyright © 2018 Khaled Hosny - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - */ - -#include "hb.hh" - -#include - -#ifdef HB_NO_OPEN -#define hb_blob_create_from_file(x) hb_blob_get_empty () -#endif - -#if !defined(HB_NO_COLOR) && defined(CAIRO_HAS_SVG_SURFACE) - -#include "hb-ot.h" - -#include "hb-ft.h" - -#include -#include FT_FREETYPE_H -#include FT_GLYPH_H - -#include -#include - -#include -#include - -static void -svg_dump (hb_face_t *face, unsigned int face_index) -{ - unsigned glyph_count = hb_face_get_glyph_count (face); - - for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++) - { - hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id); - - if (hb_blob_get_length (blob) == 0) continue; - - unsigned int length; - const char *data = hb_blob_get_data (blob, &length); - - char output_path[255]; - sprintf (output_path, "out/svg-%u-%u.svg%s", - glyph_id, - face_index, - // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405 - (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : ""); - - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); - - hb_blob_destroy (blob); - } -} - -/* _png API is so easy to use unlike the below code, don't get confused */ -static void -png_dump (hb_face_t *face, unsigned int face_index) -{ - unsigned glyph_count = hb_face_get_glyph_count (face); - hb_font_t *font = hb_font_create (face); - - /* scans the font for strikes */ - unsigned int sample_glyph_id; - /* we don't care about different strikes for different glyphs at this point */ - for (sample_glyph_id = 0; sample_glyph_id < glyph_count; sample_glyph_id++) - { - hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); - unsigned int blob_length = hb_blob_get_length (blob); - hb_blob_destroy (blob); - if (blob_length != 0) - break; - } - - unsigned int upem = hb_face_get_upem (face); - unsigned int blob_length = 0; - unsigned int strike = 0; - for (unsigned int ppem = 1; ppem < upem; ppem++) - { - hb_font_set_ppem (font, ppem, ppem); - hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id); - unsigned int new_blob_length = hb_blob_get_length (blob); - hb_blob_destroy (blob); - if (new_blob_length != blob_length) - { - for (unsigned int glyph_id = 0; glyph_id < glyph_count; glyph_id++) - { - hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id); - - if (hb_blob_get_length (blob) == 0) continue; - - unsigned int length; - const char *data = hb_blob_get_data (blob, &length); - - char output_path[255]; - sprintf (output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index); - - FILE *f = fopen (output_path, "wb"); - fwrite (data, 1, length, f); - fclose (f); - - hb_blob_destroy (blob); - } - - strike++; - blob_length = new_blob_length; - } - } - - hb_font_destroy (font); -} - -static void -layered_glyph_dump (hb_face_t *face, cairo_font_face_t *cairo_face, unsigned int face_index) -{ - unsigned int upem = hb_face_get_upem (face); - - unsigned glyph_count = hb_face_get_glyph_count (face); - for (hb_codepoint_t gid = 0; gid < glyph_count; ++gid) - { - unsigned int num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr); - if (!num_layers) - continue; - - hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t)); - - hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers); - if (num_layers) - { - // Measure - cairo_text_extents_t extents; - { - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - - cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t)); - for (unsigned int j = 0; j < num_layers; ++j) - glyphs[j].index = layers[j].glyph; - cairo_glyph_extents (cr, glyphs, num_layers, &extents); - free (glyphs); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - - // Add a slight margin - extents.width += extents.width / 10; - extents.height += extents.height / 10; - extents.x_bearing -= extents.width / 20; - extents.y_bearing -= extents.height / 20; - - // Render - unsigned int palette_count = hb_ot_color_palette_get_count (face); - for (unsigned int palette = 0; palette < palette_count; palette++) - { - unsigned int num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr); - if (!num_colors) - continue; - - hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t)); - hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors); - if (num_colors) - { - char output_path[255]; - sprintf (output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index); - - cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - - for (unsigned int layer = 0; layer < num_layers; ++layer) - { - hb_color_t color = 0x000000FF; - if (layers[layer].color_index != 0xFFFF) - color = colors[layers[layer].color_index]; - cairo_set_source_rgba (cr, - hb_color_get_red (color) / 255., - hb_color_get_green (color) / 255., - hb_color_get_blue (color) / 255., - hb_color_get_alpha (color) / 255.); - - cairo_glyph_t glyph; - glyph.index = layers[layer].glyph; - glyph.x = -extents.x_bearing; - glyph.y = -extents.y_bearing; - cairo_show_glyphs (cr, &glyph, 1); - } - - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - free (colors); - } - } - - free (layers); - } -} - -static void -dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, - unsigned int num_glyphs, unsigned int face_index) -{ - for (unsigned int i = 0; i < num_glyphs; ++i) - { - cairo_text_extents_t extents; - cairo_glyph_t glyph = {0}; - glyph.index = i; - - // Measure - { - cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - - cairo_glyph_extents (cr, &glyph, 1, &extents); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - - // Add a slight margin - extents.width += extents.width / 10; - extents.height += extents.height / 10; - extents.x_bearing -= extents.width / 20; - extents.y_bearing -= extents.height / 20; - - // Render - { - char output_path[255]; - sprintf (output_path, "out/%u-%u.svg", face_index, i); - cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height); - cairo_t *cr = cairo_create (surface); - cairo_set_font_face (cr, cairo_face); - cairo_set_font_size (cr, upem); - glyph.x = -extents.x_bearing; - glyph.y = -extents.y_bearing; - cairo_show_glyphs (cr, &glyph, 1); - cairo_surface_destroy (surface); - cairo_destroy (cr); - } - } -} - -int -main (int argc, char **argv) -{ - if (argc != 2) { - fprintf (stderr, "usage: %s font-file.ttf\n" - "run it like `rm -rf out && mkdir out && %s font-file.ttf`\n", - argv[0], argv[0]); - exit (1); - } - - - FILE *font_name_file = fopen ("out/.dumped_font_name", "r"); - if (font_name_file != nullptr) - { - fprintf (stderr, "Purge or move ./out folder in order to run a new dump\n"); - exit (1); - } - - font_name_file = fopen ("out/.dumped_font_name", "w"); - if (font_name_file == nullptr) - { - fprintf (stderr, "./out is not accessible as a folder, create it please\n"); - exit (1); - } - fwrite (argv[1], 1, strlen (argv[1]), font_name_file); - fclose (font_name_file); - - hb_blob_t *blob = hb_blob_create_from_file (argv[1]); - unsigned int num_faces = hb_face_count (blob); - if (num_faces == 0) - { - fprintf (stderr, "error: The file (%s) was corrupted, empty or not found", argv[1]); - exit (1); - } - - for (unsigned int face_index = 0; face_index < hb_face_count (blob); face_index++) - { - hb_face_t *face = hb_face_create (blob, face_index); - hb_font_t *font = hb_font_create (face); - - if (hb_ot_color_has_png (face)) printf ("Dumping png (cbdt/sbix)...\n"); - png_dump (face, face_index); - - if (hb_ot_color_has_svg (face)) printf ("Dumping svg...\n"); - svg_dump (face, face_index); - - cairo_font_face_t *cairo_face; - { - FT_Library library; - FT_Init_FreeType (&library); - FT_Face ft_face; - FT_New_Face (library, argv[1], 0, &ft_face); - cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); - } - if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face)) - printf ("Dumping layered color glyphs...\n"); - layered_glyph_dump (face, cairo_face, face_index); - - unsigned int num_glyphs = hb_face_get_glyph_count (face); - unsigned int upem = hb_face_get_upem (face); - - // disabled when color font as cairo rendering of NotoColorEmoji is soooo slow - if (!hb_ot_color_has_layers (face) && - !hb_ot_color_has_png (face) && - !hb_ot_color_has_svg (face)) - dump_glyphs (cairo_face, upem, num_glyphs, face_index); - - hb_font_destroy (font); - hb_face_destroy (face); - } - - hb_blob_destroy (blob); - - return 0; -} - -#else -int main (int argc, char **argv) { return 0; } -#endif diff --git a/src/test-ot-glyphname.cc b/src/test-ot-glyphname.cc new file mode 100644 index 0000000000000000000000000000000000000000..b2d4b3bcf020f1fa1490b104f489af4e935ffa83 --- /dev/null +++ b/src/test-ot-glyphname.cc @@ -0,0 +1,88 @@ +/* + * Copyright © 2019 Adobe, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb.hh" +#include "hb-ot.h" + +#ifdef HB_NO_OPEN +#define hb_blob_create_from_file(x) hb_blob_get_empty () +#endif + +int +main (int argc, char **argv) +{ + if (argc != 2) { + fprintf (stderr, "usage: %s font-file\n", argv[0]); + exit (1); + } + + hb_blob_t *blob = hb_blob_create_from_file (argv[1]); + hb_face_t *face = hb_face_create (blob, 0 /* first face */); + hb_font_t *font = hb_font_create (face); + hb_blob_destroy (blob); + blob = nullptr; + + + const unsigned int num_glyphs = hb_face_get_glyph_count (face); + int result = 1; + + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + char buf[64]; + unsigned int buf_size = sizeof (buf); + if (hb_font_get_glyph_name (font, gid, buf, buf_size)) + { + hb_codepoint_t gid_inv; + if (hb_font_get_glyph_from_name(font, buf, strlen (buf), &gid_inv)) + { + if (gid == gid_inv) + { + printf ("%u <-> %s\n", gid, buf); + } + else + { + printf ("%u -> %s -> %u\n", gid, buf, gid_inv); + result = 0; + } + } + else + { + printf ("%u -> %s -> ?\n", gid, buf); + result = 0; + } + } + else + { + printf ("%u -> ?\n", gid); + result = 0; + } + } + + hb_font_destroy (font); + hb_face_destroy (face); + + return result; +} diff --git a/src/test-ot-meta.cc b/src/test-ot-meta.cc index 1045007f7d82cb44d38b14ce63e8577ec2f79fb8..f7a755cd599ce40f11f7c932981f3bb34259ee54 100644 --- a/src/test-ot-meta.cc +++ b/src/test-ot-meta.cc @@ -25,9 +25,6 @@ #include "hb.hh" #include "hb-ot.h" -#include -#include - #ifdef HB_NO_OPEN #define hb_blob_create_from_file(x) hb_blob_get_empty () #endif diff --git a/src/test-ot-name.cc b/src/test-ot-name.cc index 4a484c6d66291d551ac524d0bad87aaa8bfce364..f331161fa4d10f466b63af44369df08c2cbd9533 100644 --- a/src/test-ot-name.cc +++ b/src/test-ot-name.cc @@ -27,9 +27,6 @@ #include "hb.hh" #include "hb-ot.h" -#include -#include - #ifdef HB_NO_OPEN #define hb_blob_create_from_file(x) hb_blob_get_empty () #endif diff --git a/src/test-priority-queue.cc b/src/test-priority-queue.cc new file mode 100644 index 0000000000000000000000000000000000000000..fab63acb63b60d5a0dcb329fecd25ec86d8fdf49 --- /dev/null +++ b/src/test-priority-queue.cc @@ -0,0 +1,89 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "hb.hh" +#include "hb-priority-queue.hh" + +static void +test_insert () +{ + hb_priority_queue_t queue; + assert (queue.is_empty ()); + + queue.insert (10, 0); + assert (!queue.is_empty ()); + assert (queue.minimum () == hb_pair (10, 0)); + + queue.insert (20, 1); + assert (queue.minimum () == hb_pair (10, 0)); + + queue.insert (5, 2); + assert (queue.minimum () == hb_pair (5, 2)); + + queue.insert (15, 3); + assert (queue.minimum () == hb_pair (5, 2)); + + queue.insert (1, 4); + assert (queue.minimum () == hb_pair (1, 4)); +} + +static void +test_extract () +{ + hb_priority_queue_t queue; + queue.insert (0, 0); + queue.insert (60, 6); + queue.insert (30, 3); + queue.insert (40 ,4); + queue.insert (20, 2); + queue.insert (50, 5); + queue.insert (70, 7); + queue.insert (10, 1); + + for (int i = 0; i < 8; i++) + { + assert (!queue.is_empty ()); + assert (queue.minimum () == hb_pair (i * 10, i)); + assert (queue.pop_minimum () == hb_pair (i * 10, i)); + } + + assert (queue.is_empty ()); +} + +static void +test_extract_empty () +{ + hb_priority_queue_t queue; + assert (queue.pop_minimum () == hb_pair (0, 0)); +} + +int +main (int argc, char **argv) +{ + test_insert (); + test_extract (); + test_extract_empty (); +} diff --git a/src/test-repacker.cc b/src/test-repacker.cc new file mode 100644 index 0000000000000000000000000000000000000000..a8cc6395f9ea6f7a262592fe4a4ca32ed07dec00 --- /dev/null +++ b/src/test-repacker.cc @@ -0,0 +1,485 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include + +#include "hb-repacker.hh" +#include "hb-open-type.hh" + +static void start_object(const char* tag, + unsigned len, + hb_serialize_context_t* c) +{ + c->push (); + char* obj = c->allocate_size (len); + strncpy (obj, tag, len); +} + + +static unsigned add_object(const char* tag, + unsigned len, + hb_serialize_context_t* c) +{ + start_object (tag, len, c); + return c->pop_pack (false); +} + + +static void add_offset (unsigned id, + hb_serialize_context_t* c) +{ + OT::Offset16* offset = c->start_embed (); + c->extend_min (offset); + c->add_link (*offset, id); +} + +static void +populate_serializer_simple (hb_serialize_context_t* c) +{ + c->start_serialize (); + + unsigned obj_1 = add_object ("ghi", 3, c); + unsigned obj_2 = add_object ("def", 3, c); + + start_object ("abc", 3, c); + add_offset (obj_2, c); + add_offset (obj_1, c); + c->pop_pack (); + + c->end_serialize(); +} + +static void +populate_serializer_with_overflow (hb_serialize_context_t* c) +{ + std::string large_string(50000, 'a'); + c->start_serialize (); + + unsigned obj_1 = add_object (large_string.c_str(), 10000, c); + unsigned obj_2 = add_object (large_string.c_str(), 20000, c); + unsigned obj_3 = add_object (large_string.c_str(), 50000, c); + + start_object ("abc", 3, c); + add_offset (obj_3, c); + add_offset (obj_2, c); + add_offset (obj_1, c); + c->pop_pack (); + + c->end_serialize(); +} + +static void +populate_serializer_with_dedup_overflow (hb_serialize_context_t* c) +{ + std::string large_string(70000, 'a'); + c->start_serialize (); + + unsigned obj_1 = add_object ("def", 3, c); + + start_object (large_string.c_str(), 60000, c); + add_offset (obj_1, c); + unsigned obj_2 = c->pop_pack (false); + + start_object (large_string.c_str(), 10000, c); + add_offset (obj_2, c); + add_offset (obj_1, c); + c->pop_pack (false); + + c->end_serialize(); +} + +static void +populate_serializer_complex_1 (hb_serialize_context_t* c) +{ + c->start_serialize (); + + unsigned obj_4 = add_object ("jkl", 3, c); + unsigned obj_3 = add_object ("ghi", 3, c); + + start_object ("def", 3, c); + add_offset (obj_3, c); + unsigned obj_2 = c->pop_pack (false); + + start_object ("abc", 3, c); + add_offset (obj_2, c); + add_offset (obj_4, c); + c->pop_pack (); + + c->end_serialize(); +} + +static void +populate_serializer_complex_2 (hb_serialize_context_t* c) +{ + c->start_serialize (); + + unsigned obj_5 = add_object ("mn", 2, c); + + unsigned obj_4 = add_object ("jkl", 3, c); + + start_object ("ghi", 3, c); + add_offset (obj_4, c); + unsigned obj_3 = c->pop_pack (false); + + start_object ("def", 3, c); + add_offset (obj_3, c); + unsigned obj_2 = c->pop_pack (false); + + start_object ("abc", 3, c); + add_offset (obj_2, c); + add_offset (obj_4, c); + add_offset (obj_5, c); + c->pop_pack (); + + c->end_serialize(); +} + +static void +populate_serializer_complex_3 (hb_serialize_context_t* c) +{ + c->start_serialize (); + + unsigned obj_6 = add_object ("opqrst", 6, c); + + unsigned obj_5 = add_object ("mn", 2, c); + + start_object ("jkl", 3, c); + add_offset (obj_6, c); + unsigned obj_4 = c->pop_pack (false); + + start_object ("ghi", 3, c); + add_offset (obj_4, c); + unsigned obj_3 = c->pop_pack (false); + + start_object ("def", 3, c); + add_offset (obj_3, c); + unsigned obj_2 = c->pop_pack (false); + + start_object ("abc", 3, c); + add_offset (obj_2, c); + add_offset (obj_4, c); + add_offset (obj_5, c); + c->pop_pack (); + + c->end_serialize(); +} + +static void test_sort_kahn_1 () +{ + size_t buffer_size = 100; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_complex_1 (&c); + + graph_t graph (c.object_graph ()); + graph.sort_kahn (); + + assert(strncmp (graph.object (3).head, "abc", 3) == 0); + assert(graph.object (3).links.length == 2); + assert(graph.object (3).links[0].objidx == 2); + assert(graph.object (3).links[1].objidx == 1); + + assert(strncmp (graph.object (2).head, "def", 3) == 0); + assert(graph.object (2).links.length == 1); + assert(graph.object (2).links[0].objidx == 0); + + assert(strncmp (graph.object (1).head, "jkl", 3) == 0); + assert(graph.object (1).links.length == 0); + + assert(strncmp (graph.object (0).head, "ghi", 3) == 0); + assert(graph.object (0).links.length == 0); + + free (buffer); +} + +static void test_sort_kahn_2 () +{ + size_t buffer_size = 100; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_complex_2 (&c); + + graph_t graph (c.object_graph ()); + graph.sort_kahn (); + + + assert(strncmp (graph.object (4).head, "abc", 3) == 0); + assert(graph.object (4).links.length == 3); + assert(graph.object (4).links[0].objidx == 3); + assert(graph.object (4).links[1].objidx == 0); + assert(graph.object (4).links[2].objidx == 2); + + assert(strncmp (graph.object (3).head, "def", 3) == 0); + assert(graph.object (3).links.length == 1); + assert(graph.object (3).links[0].objidx == 1); + + assert(strncmp (graph.object (2).head, "mn", 2) == 0); + assert(graph.object (2).links.length == 0); + + assert(strncmp (graph.object (1).head, "ghi", 3) == 0); + assert(graph.object (1).links.length == 1); + assert(graph.object (1).links[0].objidx == 0); + + assert(strncmp (graph.object (0).head, "jkl", 3) == 0); + assert(graph.object (0).links.length == 0); + + free (buffer); +} + +static void test_sort_shortest () +{ + size_t buffer_size = 100; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_complex_2 (&c); + + graph_t graph (c.object_graph ()); + graph.sort_shortest_distance (); + + assert(strncmp (graph.object (4).head, "abc", 3) == 0); + assert(graph.object (4).links.length == 3); + assert(graph.object (4).links[0].objidx == 2); + assert(graph.object (4).links[1].objidx == 0); + assert(graph.object (4).links[2].objidx == 3); + + assert(strncmp (graph.object (3).head, "mn", 2) == 0); + assert(graph.object (3).links.length == 0); + + assert(strncmp (graph.object (2).head, "def", 3) == 0); + assert(graph.object (2).links.length == 1); + assert(graph.object (2).links[0].objidx == 1); + + assert(strncmp (graph.object (1).head, "ghi", 3) == 0); + assert(graph.object (1).links.length == 1); + assert(graph.object (1).links[0].objidx == 0); + + assert(strncmp (graph.object (0).head, "jkl", 3) == 0); + assert(graph.object (0).links.length == 0); + + free (buffer); +} + +static void test_duplicate_leaf () +{ + size_t buffer_size = 100; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_complex_2 (&c); + + graph_t graph (c.object_graph ()); + graph.duplicate (4, 1); + + assert(strncmp (graph.object (5).head, "abc", 3) == 0); + assert(graph.object (5).links.length == 3); + assert(graph.object (5).links[0].objidx == 3); + assert(graph.object (5).links[1].objidx == 4); + assert(graph.object (5).links[2].objidx == 0); + + assert(strncmp (graph.object (4).head, "jkl", 3) == 0); + assert(graph.object (4).links.length == 0); + + assert(strncmp (graph.object (3).head, "def", 3) == 0); + assert(graph.object (3).links.length == 1); + assert(graph.object (3).links[0].objidx == 2); + + assert(strncmp (graph.object (2).head, "ghi", 3) == 0); + assert(graph.object (2).links.length == 1); + assert(graph.object (2).links[0].objidx == 1); + + assert(strncmp (graph.object (1).head, "jkl", 3) == 0); + assert(graph.object (1).links.length == 0); + + assert(strncmp (graph.object (0).head, "mn", 2) == 0); + assert(graph.object (0).links.length == 0); + + free (buffer); +} + +static void test_duplicate_interior () +{ + size_t buffer_size = 100; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_complex_3 (&c); + + graph_t graph (c.object_graph ()); + graph.duplicate (3, 2); + + assert(strncmp (graph.object (6).head, "abc", 3) == 0); + assert(graph.object (6).links.length == 3); + assert(graph.object (6).links[0].objidx == 4); + assert(graph.object (6).links[1].objidx == 2); + assert(graph.object (6).links[2].objidx == 1); + + assert(strncmp (graph.object (5).head, "jkl", 3) == 0); + assert(graph.object (5).links.length == 1); + assert(graph.object (5).links[0].objidx == 0); + + assert(strncmp (graph.object (4).head, "def", 3) == 0); + assert(graph.object (4).links.length == 1); + assert(graph.object (4).links[0].objidx == 3); + + assert(strncmp (graph.object (3).head, "ghi", 3) == 0); + assert(graph.object (3).links.length == 1); + assert(graph.object (3).links[0].objidx == 5); + + assert(strncmp (graph.object (2).head, "jkl", 3) == 0); + assert(graph.object (2).links.length == 1); + assert(graph.object (2).links[0].objidx == 0); + + assert(strncmp (graph.object (1).head, "mn", 2) == 0); + assert(graph.object (1).links.length == 0); + + assert(strncmp (graph.object (0).head, "opqrst", 6) == 0); + assert(graph.object (0).links.length == 0); + + free (buffer); +} + +static void +test_serialize () +{ + size_t buffer_size = 100; + void* buffer_1 = malloc (buffer_size); + hb_serialize_context_t c1 (buffer_1, buffer_size); + populate_serializer_simple (&c1); + hb_bytes_t expected = c1.copy_bytes (); + + void* buffer_2 = malloc (buffer_size); + hb_serialize_context_t c2 (buffer_2, buffer_size); + + graph_t graph (c1.object_graph ()); + graph.serialize (&c2); + hb_bytes_t actual = c2.copy_bytes (); + + assert (actual == expected); + + actual.free (); + expected.free (); + free (buffer_1); + free (buffer_2); +} + +static void test_will_overflow_1 () +{ + size_t buffer_size = 100; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_complex_2 (&c); + graph_t graph (c.object_graph ()); + + assert (!graph.will_overflow (nullptr)); + + free (buffer); +} + +static void test_will_overflow_2 () +{ + size_t buffer_size = 160000; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_with_overflow (&c); + graph_t graph (c.object_graph ()); + + assert (graph.will_overflow (nullptr)); + + free (buffer); +} + +static void test_will_overflow_3 () +{ + size_t buffer_size = 160000; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_with_dedup_overflow (&c); + graph_t graph (c.object_graph ()); + + assert (graph.will_overflow (nullptr)); + + free (buffer); +} + +static void test_resolve_overflows_via_sort () +{ + size_t buffer_size = 160000; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_with_overflow (&c); + graph_t graph (c.object_graph ()); + + void* out_buffer = malloc (buffer_size); + hb_serialize_context_t out (out_buffer, buffer_size); + + hb_resolve_overflows (c.object_graph (), &out); + assert (!out.offset_overflow ()); + hb_bytes_t result = out.copy_bytes (); + assert (result.length == (80000 + 3 + 3 * 2)); + + result.free (); + free (buffer); + free (out_buffer); +} + +static void test_resolve_overflows_via_duplication () +{ + size_t buffer_size = 160000; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_with_dedup_overflow (&c); + graph_t graph (c.object_graph ()); + + void* out_buffer = malloc (buffer_size); + hb_serialize_context_t out (out_buffer, buffer_size); + + hb_resolve_overflows (c.object_graph (), &out); + assert (!out.offset_overflow ()); + hb_bytes_t result = out.copy_bytes (); + assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2)); + + result.free (); + free (buffer); + free (out_buffer); +} + +// TODO(garretrieger): update will_overflow tests to check the overflows array. +// TODO(garretrieger): add a test(s) using a real font. +// TODO(garretrieger): add tests for priority raising. + +int +main (int argc, char **argv) +{ + test_serialize (); + test_sort_kahn_1 (); + test_sort_kahn_2 (); + test_sort_shortest (); + test_will_overflow_1 (); + test_will_overflow_2 (); + test_will_overflow_3 (); + test_resolve_overflows_via_sort (); + test_resolve_overflows_via_duplication (); + test_duplicate_leaf (); + test_duplicate_interior (); +} diff --git a/src/test-unicode-ranges.cc b/src/test-unicode-ranges.cc index 0eef8c24b50b8ce003f6c64fe870dd0b0f18d54c..33cac6b71579bb86ab5f491a45755216429ff2fe 100644 --- a/src/test-unicode-ranges.cc +++ b/src/test-unicode-ranges.cc @@ -33,9 +33,9 @@ test (hb_codepoint_t cp, unsigned int bit) if (OT::_hb_ot_os2_get_unicode_range_bit (cp) != bit) { fprintf (stderr, "got incorrect bit (%d) for cp 0x%X. Should have been %d.", - OT::_hb_ot_os2_get_unicode_range_bit (cp), - cp, - bit); + OT::_hb_ot_os2_get_unicode_range_bit (cp), + cp, + bit); abort(); } } diff --git a/src/test.cc b/src/test.cc index 65b469feb7b985247cd5f371bb07bbd70257957c..347b71d38b53b1ea5eed11f2601c7e4f9f33f25d 100644 --- a/src/test.cc +++ b/src/test.cc @@ -26,10 +26,6 @@ #include "hb.hh" -#include "hb.h" - -#include - #ifdef HAVE_FREETYPE #include "hb-ft.h" #endif diff --git a/src/update-unicode-tables.make b/src/update-unicode-tables.make new file mode 100644 index 0000000000000000000000000000000000000000..95edb9a75f2436ea840ca101816215b729818e7e --- /dev/null +++ b/src/update-unicode-tables.make @@ -0,0 +1,57 @@ +#!/usr/bin/env -S make -f + +all: packtab \ + hb-ot-shape-complex-arabic-joining-list.hh \ + hb-ot-shape-complex-arabic-table.hh hb-unicode-emoji-table.hh \ + hb-ot-shape-complex-indic-table.cc hb-ot-tag-table.hh \ + hb-ucd-table.hh hb-ot-shape-complex-use-table.hh \ + hb-ot-shape-complex-vowel-constraints.cc + +.PHONY: all clean packtab + +hb-ot-shape-complex-arabic-joining-list.hh: gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt + ./$^ > $@ || ($(RM) $@; false) +hb-ot-shape-complex-arabic-table.hh: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt + ./$^ > $@ || ($(RM) $@; false) +hb-unicode-emoji-table.hh: gen-emoji-table.py emoji-data.txt + ./$^ > $@ || ($(RM) $@; false) +hb-ot-shape-complex-indic-table.cc: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt + ./$^ > $@ || ($(RM) $@; false) +hb-ot-tag-table.hh: gen-tag-table.py languagetags language-subtag-registry + ./$^ > $@ || ($(RM) $@; false) +hb-ucd-table.hh: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h + ./$^ > $@ || ($(RM) $@; false) +hb-ot-shape-complex-use-table.hh: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt ArabicShaping.txt Blocks.txt ms-use/IndicSyllabicCategory-Additional.txt ms-use/IndicPositionalCategory-Additional.txt + ./$^ > $@ || ($(RM) $@; false) +hb-ot-shape-complex-vowel-constraints.cc: gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt + ./$^ > $@ || ($(RM) $@; false) + +packtab: + /usr/bin/env python3 -c "import packTab" 2>/dev/null || /usr/bin/env python3 -m pip install git+https://github.com/harfbuzz/packtab + +ArabicShaping.txt: + curl -O https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt +UnicodeData.txt: + curl -O https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt +Blocks.txt: + curl -O https://unicode.org/Public/UCD/latest/ucd/Blocks.txt +emoji-data.txt: + curl -O https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt +IndicSyllabicCategory.txt: + curl -O https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt +IndicPositionalCategory.txt: + curl -O https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt +languagetags: + curl -O https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags +language-subtag-registry: + curl -O https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry +ucd.nounihan.grouped.zip: + curl -O https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip +Scripts.txt: + curl -O https://unicode.org/Public/UCD/latest/ucd/Scripts.txt + +clean: + $(RM) \ + ArabicShaping.txt UnicodeData.txt Blocks.txt emoji-data.txt \ + IndicSyllabicCategory.txt IndicPositionalCategory.txt \ + languagetags language-subtag-registry ucd.nounihan.grouped.zip Scripts.txt diff --git a/subprojects/.gitignore b/subprojects/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..269debb3ef7cee1e57e7fa67aa1048e3f2df0f39 --- /dev/null +++ b/subprojects/.gitignore @@ -0,0 +1,11 @@ +/expat-2.2.5 +/freetype2 +/glib +/libffi +/proxy-libintl +/zlib +/packagecache +/benchmark-1.4.1 +/cairo +/pixman +/libpng-1.6.35 diff --git a/subprojects/cairo.wrap b/subprojects/cairo.wrap new file mode 100644 index 0000000000000000000000000000000000000000..afb2695d46394e9a4d4d6893fa2ead3fbfc7092b --- /dev/null +++ b/subprojects/cairo.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=cairo +url=https://gitlab.freedesktop.org/cairo/cairo.git +depth=1 +revision=1.17.4 diff --git a/subprojects/expat.wrap b/subprojects/expat.wrap new file mode 100644 index 0000000000000000000000000000000000000000..f5f595c02a399bd65f7551ade0bd929b0d7c6f2b --- /dev/null +++ b/subprojects/expat.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = expat-2.2.9 +source_url = https://github.com/libexpat/libexpat/releases/download/R_2_2_9/expat-2.2.9.tar.xz +source_filename = expat-2.2.9.tar.bz2 +source_hash = 1ea6965b15c2106b6bbe883397271c80dfa0331cdf821b2c319591b55eadc0a4 +patch_url = https://wrapdb.mesonbuild.com/v1/projects/expat/2.2.9/3/get_zip +patch_filename = expat-2.2.9-3-wrap.zip +patch_hash = e9aaace62e9a158b5e96f5c38c9f81f369179206acd87697653d777c0d3975d3 + diff --git a/subprojects/freetype2.wrap b/subprojects/freetype2.wrap new file mode 100644 index 0000000000000000000000000000000000000000..7c88f89cbc0a9fab2ad0a92ac5990bc564566a95 --- /dev/null +++ b/subprojects/freetype2.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=freetype2 +url=https://github.com/centricular/freetype2.git +depth=1 +push-url=git@github.com:centricular/freetype2.git +revision=meson diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap new file mode 100644 index 0000000000000000000000000000000000000000..7a4eae17534cea7404c6800e0b4d22c9ef0c72fa --- /dev/null +++ b/subprojects/glib.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=glib +url=https://gitlab.gnome.org/GNOME/glib.git +depth=1 +push-url=git@gitlab.gnome.org:GNOME/glib.git +revision=2.58.1 diff --git a/subprojects/google-benchmark.wrap b/subprojects/google-benchmark.wrap new file mode 100644 index 0000000000000000000000000000000000000000..876927d6ef06a940152783e778a733362ad548fe --- /dev/null +++ b/subprojects/google-benchmark.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = benchmark-1.5.2 +source_url = https://github.com/google/benchmark/archive/v1.5.2.zip +source_filename = benchmark-1.5.2.zip +source_hash = 21e6e096c9a9a88076b46bd38c33660f565fa050ca427125f64c4a8bf60f336b +patch_url = https://wrapdb.mesonbuild.com/v1/projects/google-benchmark/1.5.2/1/get_zip +patch_filename = google-benchmark-1.5.2-1-wrap.zip +patch_hash = 49f41e4a7e68ac258b6509b9de9857441903be4fb473454c4cba8be885f0c6c3 + diff --git a/subprojects/libffi.wrap b/subprojects/libffi.wrap new file mode 100644 index 0000000000000000000000000000000000000000..466ca81b6ee2306bace8bfb5b814f847f75b4e5a --- /dev/null +++ b/subprojects/libffi.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=libffi +url=https://gitlab.freedesktop.org/gstreamer/meson-ports/libffi.git +depth=1 +revision=meson diff --git a/subprojects/libpng.wrap b/subprojects/libpng.wrap new file mode 100644 index 0000000000000000000000000000000000000000..8c7e3fdced467e1fb7382926f9c0ff12045d73c4 --- /dev/null +++ b/subprojects/libpng.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = libpng-1.6.37 +source_url = https://github.com/glennrp/libpng/archive/v1.6.37.tar.gz +source_filename = libpng-1.6.37.tar.gz +source_hash = ca74a0dace179a8422187671aee97dd3892b53e168627145271cad5b5ac81307 +patch_url = https://wrapdb.mesonbuild.com/v1/projects/libpng/1.6.37/3/get_zip +patch_filename = libpng-1.6.37-3-wrap.zip +patch_hash = 6c9f32fd9150b3a96ab89be52af664e32207e10aa9f5fb9aa015989ee2dd7100 + +[provide] +libpng = libpng_dep + diff --git a/subprojects/pixman.wrap b/subprojects/pixman.wrap new file mode 100644 index 0000000000000000000000000000000000000000..ad18e856b4fc070eaefe4a2859d7d092c0486a43 --- /dev/null +++ b/subprojects/pixman.wrap @@ -0,0 +1,6 @@ +[wrap-git] +directory=pixman +url=https://gitlab.freedesktop.org/pixman/pixman +push-url=git@gitlab.freedesktop.org:pixman/pixman.git +depth=1 +revision=9b49f4e08751885289333fed652bf5e0f45976b4 diff --git a/subprojects/proxy-libintl.wrap b/subprojects/proxy-libintl.wrap new file mode 100644 index 0000000000000000000000000000000000000000..22dd8505cded3f06f261a6ed0efe960d87fe5dde --- /dev/null +++ b/subprojects/proxy-libintl.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=proxy-libintl +url=https://github.com/frida/proxy-libintl.git +depth=1 +revision=50bd2525261d44d80533a523873b9344a6d741c5 diff --git a/subprojects/ttf-parser.wrap b/subprojects/ttf-parser.wrap new file mode 100644 index 0000000000000000000000000000000000000000..11cda545706b46b12ce5b774ba109b08926d173b --- /dev/null +++ b/subprojects/ttf-parser.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=ttf-parser +url=https://github.com/RazrFalcon/ttf-parser.git +depth=1 +revision=master diff --git a/subprojects/zlib.wrap b/subprojects/zlib.wrap new file mode 100644 index 0000000000000000000000000000000000000000..ce20fb0532012aa34acc56c44e0101f85e0bf52c --- /dev/null +++ b/subprojects/zlib.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = zlib-1.2.11 +source_url = http://zlib.net/fossils/zlib-1.2.11.tar.gz +source_filename = zlib-1.2.11.tar.gz +source_hash = c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1 +patch_url = https://wrapdb.mesonbuild.com/v1/projects/zlib/1.2.11/5/get_zip +patch_filename = zlib-1.2.11-5-wrap.zip +patch_hash = 728c8e24acbc2e6682fbd950fec39e2fc77528af361adb87259f8a8511434004 + +[provide] +zlib = zlib_dep + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index d2b199428466f9a1f54612e5ab71ec8f5ea6bf23..0000000000000000000000000000000000000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_subdirectory(api) -add_subdirectory(shaping) -add_subdirectory(subset) -add_subdirectory(fuzzing) diff --git a/test/Makefile.am b/test/Makefile.am index 66b3e6e2e462d583f2675f88b59aab26ffa4cd29..b67d707b03b9dc052f1fe5df59fc9f71042b19e1 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -5,7 +5,7 @@ EXTRA_DIST = SUBDIRS = api shaping fuzzing subset EXTRA_DIST += \ - CMakeLists.txt \ + meson.build \ $(NULL) # Convenience targets: diff --git a/test/api/CMakeLists.txt b/test/api/CMakeLists.txt deleted file mode 100644 index 0c7337cb5a25e4adfb68220956cbdb32ed26b425..0000000000000000000000000000000000000000 --- a/test/api/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -if (HB_HAVE_GLIB) - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM) - extract_make_variable (TEST_PROGS ${MAKEFILEAM}) - - list (APPEND TEST_PROGS - test-ot-color - test-ot-name - test-ot-tag - test-c - test-cplusplus - ) - - if (HB_HAVE_FREETYPE) - list (APPEND TEST_PROGS test-ot-math) - endif () - - foreach (test_name IN ITEMS ${TEST_PROGS}) - if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.c) - add_executable (${test_name} ${test_name}.c) - elseif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.cc) - add_executable (${test_name} ${test_name}.cc) - else () - message (FATAL_ERROR "No source file found for test ${test_name}") - endif () - target_link_libraries (${test_name} harfbuzz harfbuzz-subset) - if (WIN32) - set_property (TARGET ${test_name} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - add_test (NAME ${test_name} COMMAND ${test_name}) - else (WIN32) - add_test (${test_name} ${test_name}) - endif (WIN32) - endforeach () - set_tests_properties (${TEST_PROGS} PROPERTIES ENVIRONMENT - "G_TEST_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};G_TEST_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}" - ) -endif () diff --git a/test/api/Makefile.am b/test/api/Makefile.am index 2386e53eabee3d22106b6decde2c84a7bbb6a9f7..bf29d2200dccb57f3ee1b5cb2517d409750c9ad3 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -12,7 +12,7 @@ lib: libs: @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs -EXTRA_DIST += CMakeLists.txt +EXTRA_DIST += meson.build EXTRA_DIST += fonts @@ -32,28 +32,50 @@ TEST_PROGS = \ test-baseline \ test-blob \ test-buffer \ + test-c \ test-collect-unicodes \ + test-cplusplus \ test-common \ + test-draw \ test-font \ test-map \ test-object \ + test-ot-alternates \ + test-ot-color \ test-ot-face \ + test-ot-glyphname \ + test-ot-ligature-carets \ + test-ot-name \ + test-ot-meta \ + test-ot-metrics \ + test-ot-tag \ + test-ot-extents-cff \ + test-ot-metrics-tt-var \ test-set \ test-shape \ + test-style \ test-subset \ test-subset-cmap \ test-subset-drop-tables \ test-subset-glyf \ test-subset-hdmx \ test-subset-hmtx \ + test-subset-nameids \ test-subset-os2 \ test-subset-post \ test-subset-vmtx \ test-subset-cff1 \ test-subset-cff2 \ + test-subset-gvar \ + test-subset-hvar \ + test-subset-vvar \ + test-subset-sbix \ + test-subset-gpos \ + test-subset-colr \ + test-subset-cbdt \ test-unicode \ + test-var-coords \ test-version \ - test-subset-nameids \ $(NULL) test_subset_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la @@ -67,7 +89,14 @@ test_subset_post_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_vmtx_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_cff1_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_cff2_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_gvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_hvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_vvar_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_sbix_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_cbdt_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_subset_nameids_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_gpos_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la +test_subset_colr_LDADD = $(LDADD) $(top_builddir)/src/libharfbuzz-subset.la test_unicode_CPPFLAGS = \ $(AM_CPPFLAGS) \ @@ -79,18 +108,6 @@ test_unicode_CPPFLAGS += $(ICU_CFLAGS) test_unicode_LDADD += $(top_builddir)/src/libharfbuzz-icu.la $(ICU_LIBS) endif - -TEST_PROGS += \ - test-ot-color \ - test-ot-ligature-carets \ - test-ot-name \ - test-ot-meta \ - test-ot-metrics \ - test-ot-tag \ - test-ot-extents-cff \ - $(NULL) - - if HAVE_PTHREAD if HAVE_FREETYPE TEST_PROGS += test-multithread @@ -110,12 +127,7 @@ test_ot_math_LDADD = $(LDADD) $(FREETYPE_LIBS) test_ot_math_CPPFLAGS = $(AM_CPPFLAGS) $(FREETYPE_CFLAGS) endif # HAVE_FREETYPE - # Tests for header compilation -TEST_PROGS += \ - test-c \ - test-cplusplus \ - $(NULL) test_cplusplus_SOURCES = test-cplusplus.cc test_c_CPPFLAGS = $(AM_CPPFLAGS) test_cplusplus_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/test/api/fonts/AdobeVFPrototype-Subset.otf b/test/api/fonts/AdobeVFPrototype-Subset.otf new file mode 100644 index 0000000000000000000000000000000000000000..5cc7279fcbe20355a029e5120f5149c3a022d506 Binary files /dev/null and b/test/api/fonts/AdobeVFPrototype-Subset.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.WA.gpos.otf b/test/api/fonts/AdobeVFPrototype.WA.gpos.otf new file mode 100644 index 0000000000000000000000000000000000000000..7dd6fb5288d156938561521f6e3ada3c52588eb5 Binary files /dev/null and b/test/api/fonts/AdobeVFPrototype.WA.gpos.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.WAV.gpos.otf b/test/api/fonts/AdobeVFPrototype.WAV.gpos.otf new file mode 100644 index 0000000000000000000000000000000000000000..c9da07b6eda3a7fe17cdf0090b3ffda96303dbfd Binary files /dev/null and b/test/api/fonts/AdobeVFPrototype.WAV.gpos.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.abc.otf b/test/api/fonts/AdobeVFPrototype.abc.otf index cc477088ebdec87d1970e7d4acc8ce50dd7cd36c..5e6a92844b9ca122bdb747f7e9b6a2df1b31675a 100644 Binary files a/test/api/fonts/AdobeVFPrototype.abc.otf and b/test/api/fonts/AdobeVFPrototype.abc.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf index 935bdbfb13d9aed807bcf5f27eab0863051d5e0b..19b78973be4ce0792b5fe94f9d6eb22ef25c5a73 100644 Binary files a/test/api/fonts/AdobeVFPrototype.ac.nohints.otf and b/test/api/fonts/AdobeVFPrototype.ac.nohints.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf index 85f6cf6a34e446d02ee0cc2fd3e1cc9d428d1478..73ff879845760316283eee4401981ab7c1389e04 100644 Binary files a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf and b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.nohints.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf index ad4d53b874827c32af3b4a1a109d8f88b68b148b..7d2f79a7b9c46a6419d3ff9a82dd8f4bdd92a6f7 100644 Binary files a/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf and b/test/api/fonts/AdobeVFPrototype.ac.nosubrs.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.ac.otf b/test/api/fonts/AdobeVFPrototype.ac.otf index beab7d585b36eaeb60c11e8e9c991f1aeb4f851b..193404fa58b80796f1a758175894888fa14430d7 100644 Binary files a/test/api/fonts/AdobeVFPrototype.ac.otf and b/test/api/fonts/AdobeVFPrototype.ac.otf differ diff --git a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf index 8cb3005aec5e82a0ede38969f5184ac42ccccbbc..15419b04dc81a32dbcdf9456a60833710346c853 100644 Binary files a/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf and b/test/api/fonts/AdobeVFPrototype.ac.retaingids.otf differ diff --git a/test/api/fonts/Estedad-VF.ttf b/test/api/fonts/Estedad-VF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f6c22b75e2cb98797aafdcdd5af64dd3337c7875 Binary files /dev/null and b/test/api/fonts/Estedad-VF.ttf differ diff --git a/test/api/fonts/Mada-VF.ttf b/test/api/fonts/Mada-VF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e6f44045c46007c98f05684a8e9f6a10d56f4d78 Binary files /dev/null and b/test/api/fonts/Mada-VF.ttf differ diff --git a/test/api/fonts/Mplus1p-Regular-cmap4-testing.ttf b/test/api/fonts/Mplus1p-Regular-cmap4-testing.ttf new file mode 100644 index 0000000000000000000000000000000000000000..00a4b0a89c0bdaee0e6aa7323ab5126da55f3efc Binary files /dev/null and b/test/api/fonts/Mplus1p-Regular-cmap4-testing.ttf differ diff --git a/test/api/fonts/Mplus1p-Regular.ttf b/test/api/fonts/Mplus1p-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f89a28ef32b9aebefaf3a39764d1d15e20855fb8 Binary files /dev/null and b/test/api/fonts/Mplus1p-Regular.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.cmap.38,AE,2049.ttf b/test/api/fonts/NotoColorEmoji.cmap.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..94efc6aa708bd8e32d7b5fddf4199144c33ba328 Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.cmap.38,AE,2049.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.cmap.ttf b/test/api/fonts/NotoColorEmoji.cmap.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c1dd86915841b0a66f8987c147590d1d1fe2b28d Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.cmap.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.default.2049.ttf b/test/api/fonts/NotoColorEmoji.subset.default.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b577752aeb87a2c7dc23f975f0430f5591d692ec Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.default.2049.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.default.39.ttf b/test/api/fonts/NotoColorEmoji.subset.default.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34e878ee0e96c8d1abbe7f7f2d95d1f5c7f80cad Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.default.39.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf b/test/api/fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e7f361a599f26b0cc9b0972c051e86d7d440cf9a Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.index_format3.ttf b/test/api/fonts/NotoColorEmoji.subset.index_format3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..df1ff9bb3c3a2e9dc64df51c171067b2ae933ae2 Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.index_format3.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8d2fb18aac1b9b66084f6843538dfe0ac7a7c4b7 Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cdccdeda2b4458028ff7c7301584d11f79512a2f Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf differ diff --git a/test/api/fonts/NotoColorEmoji.subset.ttf b/test/api/fonts/NotoColorEmoji.subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14a544ad5fbf4d31ef8339d7393d2aa071d41bac Binary files /dev/null and b/test/api/fonts/NotoColorEmoji.subset.ttf differ diff --git a/test/api/fonts/NotoNastaliqUrdu-Regular.ttf b/test/api/fonts/NotoNastaliqUrdu-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..891f633d802bbece8eb3a701a62bdcb69c45b74c Binary files /dev/null and b/test/api/fonts/NotoNastaliqUrdu-Regular.ttf differ diff --git a/test/api/fonts/NotoSansCJKkr-Regular-subset-colon.ttf b/test/api/fonts/NotoSansCJKkr-Regular-subset-colon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..42bb6081fd3c46e2bbf72e5fd8d8a2dc0ba6da9f Binary files /dev/null and b/test/api/fonts/NotoSansCJKkr-Regular-subset-colon.ttf differ diff --git a/test/api/fonts/OpenSans-Regular.ttf b/test/api/fonts/OpenSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..db433349b7047f72f40072630c1bc110620bf09e Binary files /dev/null and b/test/api/fonts/OpenSans-Regular.ttf differ diff --git a/test/api/fonts/README b/test/api/fonts/README index 4830c47bb0506adc0f5d61a97a876e88a5e0fbf3..29038b5d435d963861c165748a019780bbef309b 100644 --- a/test/api/fonts/README +++ b/test/api/fonts/README @@ -3,3 +3,9 @@ cmap-format12-only files created by ttx & remove all other cmap entries Inconsolata-Regular.abc.widerc.ttf has the hmtx width of "c" set to 600; everything else is 500. Subsetting out c should reduce numberOfHMetrics to 1. chromacheck-* fonts are from https://github.com/RoelN/ChromaCheck/tree/master/fonts and licensed under MIT by Roel Nieskens and Google. + +RanaKufi-Regular.subset.otf is from https://github.com/alif-type/rana-kufi/ but the subset is licensed for us in MIT for the project use. + +glyphs.ttf is from https://github.com/RazrFalcon/ttf-parser/blob/337e7d1/tests/fonts/glyphs.ttf + +Estedad-VF.ttf, licensed under OFL 1.1, is from https://github.com/aminabedi68/Estedad diff --git a/test/api/fonts/RanaKufi-Regular.subset.otf b/test/api/fonts/RanaKufi-Regular.subset.otf new file mode 100644 index 0000000000000000000000000000000000000000..a327a2cc85257bf8d76c4381179d0c6fd25a45c1 Binary files /dev/null and b/test/api/fonts/RanaKufi-Regular.subset.otf differ diff --git a/test/api/fonts/Roboto-Regular-gpos-.aw.ttf b/test/api/fonts/Roboto-Regular-gpos-.aw.ttf new file mode 100644 index 0000000000000000000000000000000000000000..74ab2bd98931492a6b74eed932f7f1355bf62741 Binary files /dev/null and b/test/api/fonts/Roboto-Regular-gpos-.aw.ttf differ diff --git a/test/api/fonts/Roboto-Regular-gpos-aw.ttf b/test/api/fonts/Roboto-Regular-gpos-aw.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2d03cc36c72b13b80876034051e78b3eea93f98a Binary files /dev/null and b/test/api/fonts/Roboto-Regular-gpos-aw.ttf differ diff --git a/test/api/fonts/Roboto-Regular.empty.ttf b/test/api/fonts/Roboto-Regular.empty.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fbd4fbac0327ff4bea25234f056c585b4168cb95 Binary files /dev/null and b/test/api/fonts/Roboto-Regular.empty.ttf differ diff --git a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf index fa2a0e4469e99944f90be57b6e70da09eee8e138..1e5cc967fddff645a34991d693672de2e50131c8 100644 Binary files a/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf and b/test/api/fonts/SourceHanSans-Regular.41,4C2E.retaingids.otf differ diff --git a/test/api/fonts/SourceSansPro-Regular.otf b/test/api/fonts/SourceSansPro-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..279e6914a6fa7fe0dfa06c2563b8b6842ac95c97 Binary files /dev/null and b/test/api/fonts/SourceSansPro-Regular.otf differ diff --git a/test/api/fonts/SourceSansVariable-Roman-modHVAR.abc.ttf b/test/api/fonts/SourceSansVariable-Roman-modHVAR.abc.ttf new file mode 100644 index 0000000000000000000000000000000000000000..397e7a5476f57db89614c93f21c84dda5e6b3fa9 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman-modHVAR.abc.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman-modHVAR.ac.ttf b/test/api/fonts/SourceSansVariable-Roman-modHVAR.ac.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cfdbe1de72d0e77d3e268f6087c93ea5eabc89e4 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman-modHVAR.ac.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf b/test/api/fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dc237e7904d6137cb9343c7e1418782ac8b241da Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman.abc.ttf b/test/api/fonts/SourceSansVariable-Roman.abc.ttf new file mode 100644 index 0000000000000000000000000000000000000000..690d7d5392e21dc9ad01b86dfbe35ce8591c02ac Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.abc.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf b/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b2e744df2bac63d56277272d571593b6ca7818a4 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.ac.retaingids.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman.ac.ttf b/test/api/fonts/SourceSansVariable-Roman.ac.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2387ea77615ec001108f60b640b216a2ad935c80 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.ac.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman.anchor.ttf b/test/api/fonts/SourceSansVariable-Roman.anchor.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4e8dc9db4741fbdf45a1dfe4517a08f4c1e1fab5 Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.anchor.ttf differ diff --git a/test/api/fonts/SourceSansVariable-Roman.modcomp.ttf b/test/api/fonts/SourceSansVariable-Roman.modcomp.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c75041f5db7b7b8d17200bcc2d1e8ab6dfcad7ab Binary files /dev/null and b/test/api/fonts/SourceSansVariable-Roman.modcomp.ttf differ diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d94abcb0b2cd08e99adcc2d59f51cb3371c12e3 Binary files /dev/null and b/test/api/fonts/SourceSerifVariable-Roman-VVAR.abc.ttf differ diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf new file mode 100644 index 0000000000000000000000000000000000000000..734f6e82a6488c5f7c85ecf12f3972ea28aac5a0 Binary files /dev/null and b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf differ diff --git a/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.ttf b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b6b9e9715c72364613d919364e629b76a61f8ffc Binary files /dev/null and b/test/api/fonts/SourceSerifVariable-Roman-VVAR.ac.ttf differ diff --git a/test/api/fonts/Stroking.otf b/test/api/fonts/Stroking.otf new file mode 100644 index 0000000000000000000000000000000000000000..a14c3618c2dc96c1f6768abf178e53cb088c51bf Binary files /dev/null and b/test/api/fonts/Stroking.otf differ diff --git a/test/api/fonts/Stroking.ttf b/test/api/fonts/Stroking.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b88c6fa03855e420d2a61d8e32e8d1ba82495321 Binary files /dev/null and b/test/api/fonts/Stroking.ttf differ diff --git a/test/api/fonts/TestGVAREight.ttf b/test/api/fonts/TestGVAREight.ttf new file mode 100644 index 0000000000000000000000000000000000000000..271dc4b587c10750f77f6a726e7d649f5759a42c Binary files /dev/null and b/test/api/fonts/TestGVAREight.ttf differ diff --git a/test/api/fonts/TestGVARFour.ttf b/test/api/fonts/TestGVARFour.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3524f37412efcb489b0b8ff1cf23a2d57bc680cd Binary files /dev/null and b/test/api/fonts/TestGVARFour.ttf differ diff --git a/test/api/fonts/TestGVAROne.ttf b/test/api/fonts/TestGVAROne.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e155d8f5aa399278258bf69e5cdd0dbfd831de81 Binary files /dev/null and b/test/api/fonts/TestGVAROne.ttf differ diff --git a/test/api/fonts/TestGVARThree.ttf b/test/api/fonts/TestGVARThree.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ac2d7eb5d4e1ecaed0d2bb30e28c3ac7ce745889 Binary files /dev/null and b/test/api/fonts/TestGVARThree.ttf differ diff --git a/test/api/fonts/TestGVARTwo.ttf b/test/api/fonts/TestGVARTwo.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bd144c6b76e89545812e39229c44a45f72fe2226 Binary files /dev/null and b/test/api/fonts/TestGVARTwo.ttf differ diff --git a/test/api/fonts/TwemojiMozilla.subset.default.32,3299.ttf b/test/api/fonts/TwemojiMozilla.subset.default.32,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..be3a53d6dec69a7f67c7e7e99ad9ff8064bf947e Binary files /dev/null and b/test/api/fonts/TwemojiMozilla.subset.default.32,3299.ttf differ diff --git a/test/api/fonts/TwemojiMozilla.subset.default.32.ttf b/test/api/fonts/TwemojiMozilla.subset.default.32.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b7d70ade9553cc78e31be35f09631ea7f86d0c71 Binary files /dev/null and b/test/api/fonts/TwemojiMozilla.subset.default.32.ttf differ diff --git a/test/api/fonts/TwemojiMozilla.subset.default.3297.ttf b/test/api/fonts/TwemojiMozilla.subset.default.3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..09e5056f78d34df801c372b3328a03799e569d1f Binary files /dev/null and b/test/api/fonts/TwemojiMozilla.subset.default.3297.ttf differ diff --git a/test/api/fonts/TwemojiMozilla.subset.ttf b/test/api/fonts/TwemojiMozilla.subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..357dda3b96d86c569e94f579d14a2c87bc4cfbce Binary files /dev/null and b/test/api/fonts/TwemojiMozilla.subset.ttf differ diff --git a/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf b/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf index 8c198b767af89581394d900f6d2e9b0ff5653961..dc79b69458a9624628f0459853f3c19e0fc2284f 100644 Binary files a/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf and b/test/api/fonts/cff1_expert.2D,F6E9,FB00.otf differ diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5753845452636160 b/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5753845452636160 new file mode 100644 index 0000000000000000000000000000000000000000..b36f5b1ad7f10b6085fff1a00e216879606b95d6 Binary files /dev/null and b/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5753845452636160 differ diff --git a/test/api/fonts/cmunrm.otf b/test/api/fonts/cmunrm.otf new file mode 100644 index 0000000000000000000000000000000000000000..b449df04c3c62152d99906a90a772d463d81e712 Binary files /dev/null and b/test/api/fonts/cmunrm.otf differ diff --git a/test/api/fonts/glyphs.ttf b/test/api/fonts/glyphs.ttf new file mode 100644 index 0000000000000000000000000000000000000000..64ff55eb342972bf03d8a02be14789a08fed8187 Binary files /dev/null and b/test/api/fonts/glyphs.ttf differ diff --git a/test/api/fonts/lcar.ttf b/test/api/fonts/lcar.ttf deleted file mode 100644 index 4d176636ec64de94fb6fce55c8c7469d6879c262..0000000000000000000000000000000000000000 Binary files a/test/api/fonts/lcar.ttf and /dev/null differ diff --git a/test/api/fonts/sbix.ttf b/test/api/fonts/sbix.ttf new file mode 100644 index 0000000000000000000000000000000000000000..575af900a811e0334ca677ef0cf62cfe94242815 Binary files /dev/null and b/test/api/fonts/sbix.ttf differ diff --git a/test/api/fonts/sbix_X.ttf b/test/api/fonts/sbix_X.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6960f8f98f89832d5dcd3fef32f48e1a7b9e0457 Binary files /dev/null and b/test/api/fonts/sbix_X.ttf differ diff --git a/test/api/hb-subset-test.h b/test/api/hb-subset-test.h index 25cf1e3e647a8fc0667aec05fd56fc71f847dbb6..cdd41ed880cf0b411d583b566b28d78c1a7e6cdf 100644 --- a/test/api/hb-subset-test.h +++ b/test/api/hb-subset-test.h @@ -71,12 +71,17 @@ hb_subset_test_create_input_from_nameids (const hb_set_t *name_ids) hb_subset_input_t *input = hb_subset_input_create_or_fail (); hb_set_t * input_name_ids = hb_subset_input_nameid_set (input); hb_set_set (input_name_ids, name_ids); + + hb_set_t *name_langids = hb_subset_input_namelangid_set (input); + hb_set_add_range (name_langids, 0, 0x5FFF); + + hb_subset_input_set_name_legacy (input, true); return input; } static inline hb_face_t * hb_subset_test_create_subset (hb_face_t *source, - hb_subset_input_t *input) + hb_subset_input_t *input) { hb_face_t *subset = hb_subset (source, input); g_assert (subset); @@ -87,14 +92,17 @@ hb_subset_test_create_subset (hb_face_t *source, static inline void hb_subset_test_check (hb_face_t *expected, - hb_face_t *actual, - hb_tag_t table) + hb_face_t *actual, + hb_tag_t table) { hb_blob_t *expected_blob, *actual_blob; expected_blob = hb_face_reference_table (expected, table); actual_blob = hb_face_reference_table (actual, table); fprintf(stderr, "comparing %c%c%c%c, expected %d bytes, actual %d bytes\n", HB_UNTAG(table), hb_blob_get_length(expected_blob), hb_blob_get_length (actual_blob)); - hb_test_assert_blobs_equal (expected_blob, actual_blob); + + if (hb_blob_get_length (expected_blob) != 0 || + hb_blob_get_length (actual_blob) != 0) + hb_test_assert_blobs_equal (expected_blob, actual_blob); hb_blob_destroy (expected_blob); hb_blob_destroy (actual_blob); } diff --git a/test/api/hb-test.h b/test/api/hb-test.h index b866e442a90946350ea5ff9d5166208525391d5a..c5eb870860c88e17a90057c444e18237db0093ea 100644 --- a/test/api/hb-test.h +++ b/test/api/hb-test.h @@ -104,25 +104,25 @@ hb_test_bug (const char *uri_base, unsigned int number) static inline void hb_test_bug_freedesktop (unsigned int number) { - hb_test_bug ("http://bugs.freedesktop.org/", number); + hb_test_bug ("https://bugs.freedesktop.org/", number); } static inline void hb_test_bug_gnome (unsigned int number) { - hb_test_bug ("http://bugzilla.gnome.org/", number); + hb_test_bug ("https://bugzilla.gnome.org/", number); } static inline void hb_test_bug_mozilla (unsigned int number) { - hb_test_bug ("http://bugzilla.mozilla.org/", number); + hb_test_bug ("https://bugzilla.mozilla.org/", number); } static inline void hb_test_bug_redhat (unsigned int number) { - hb_test_bug ("http://bugzilla.redhat.com/", number); + hb_test_bug ("https://bugzilla.redhat.com/", number); } diff --git a/test/api/meson.build b/test/api/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..5c8b6022f6da9ea6f03db707001ab552a152f649 --- /dev/null +++ b/test/api/meson.build @@ -0,0 +1,88 @@ +if conf.get('HAVE_GLIB', 0) == 0 + message('You need to have glib support enabled to run test/api tests') + subdir_done() +endif + +tests = [ + 'test-aat-layout.c', + 'test-baseline.c', + 'test-blob.c', + 'test-buffer.c', + 'test-c.c', + 'test-collect-unicodes.c', + 'test-cplusplus.cc', + 'test-common.c', + 'test-draw.c', + 'test-font.c', + 'test-map.c', + 'test-object.c', + 'test-ot-alternates.c', + 'test-ot-color.c', + 'test-ot-face.c', + 'test-ot-glyphname.c', + 'test-ot-ligature-carets.c', + 'test-ot-name.c', + 'test-ot-meta.c', + 'test-ot-metrics.c', + 'test-ot-tag.c', + 'test-ot-extents-cff.c', + 'test-ot-metrics-tt-var.c', + 'test-set.c', + 'test-shape.c', + 'test-style.c', + 'test-subset.c', + 'test-subset-cmap.c', + 'test-subset-drop-tables.c', + 'test-subset-glyf.c', + 'test-subset-hdmx.c', + 'test-subset-hmtx.c', + 'test-subset-nameids.c', + 'test-subset-os2.c', + 'test-subset-post.c', + 'test-subset-vmtx.c', + 'test-subset-cff1.c', + 'test-subset-cff2.c', + 'test-subset-gvar.c', + 'test-subset-hvar.c', + 'test-subset-vvar.c', + 'test-subset-sbix.c', + 'test-subset-gpos.c', + 'test-subset-colr.c', + 'test-subset-cbdt.c', + 'test-unicode.c', + 'test-var-coords.c', + 'test-version.c', +] + +if conf.get('HAVE_FREETYPE', 0) == 1 + tests += 'test-ot-math.c' +endif + +if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_PTHREAD', 0) == 1 + tests += 'test-multithread.c' +endif + +# Default test running environment +env = environment() +env.set('MALLOC_CHECK_', '2') +env.set('G_DEBUG', 'gc-friendly') +env.set('G_SLICE', 'always-malloc') +env.set('G_TEST_SRCDIR', meson.current_source_dir()) +env.set('G_TEST_BUILDDIR', meson.current_build_dir()) + +foreach source : tests + test_name = source.split('.')[0] + + deps = [glib_dep, freetype_dep, thread_dep, libharfbuzz_dep, libharfbuzz_icu_dep] + suite = ['api'] + if test_name.contains('-subset') + deps += libharfbuzz_subset_dep + suite += 'subset' + endif + + test(test_name, executable(test_name, source, + include_directories: [incconfig], + dependencies: deps, + install: false, + ), env: env, suite: suite) +endforeach diff --git a/test/api/test-buffer.c b/test/api/test-buffer.c index 64ab3db9929dad260ea2f443c5a2a5a93491ee6a..4b48d5c7838caceaa6e1919886e95c3506fbd39b 100644 --- a/test/api/test-buffer.c +++ b/test/api/test-buffer.c @@ -71,7 +71,7 @@ fixture_init (fixture_t *fixture, gconstpointer user_data) case BUFFER_ONE_BY_ONE: for (i = 1; i < G_N_ELEMENTS (utf32) - 1; i++) - hb_buffer_add (b, utf32[i], i); + hb_buffer_add (b, utf32[i], i); break; case BUFFER_UTF32: @@ -208,7 +208,7 @@ test_buffer_contents (fixture_t *fixture, gconstpointer user_data) if (buffer_type == BUFFER_UTF16) cluster++; else if (buffer_type == BUFFER_UTF8) - cluster += 3; + cluster += 3; } g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); g_assert_cmphex (glyphs[i].cluster, ==, cluster); @@ -856,6 +856,74 @@ test_buffer_empty (void) g_assert (!hb_buffer_allocation_successful (b)); } +typedef struct { + const char *contents; + hb_buffer_serialize_format_t format; + unsigned int num_items; + hb_bool_t success; +} serialization_test_t; + +static const serialization_test_t serialization_tests[] = { + { "", HB_BUFFER_SERIALIZE_FORMAT_TEXT, 2, 1 }, + { "[{\"u\":1600,\"cl\":0},{\"u\":1589,\"cl\":1}]", HB_BUFFER_SERIALIZE_FORMAT_JSON, 2, 1 }, + + /* Mixed glyphs/Unicodes -> parse fail */ + { "[{\"u\":1600,\"cl\":0},{\"g\":1589,\"cl\":1}]", HB_BUFFER_SERIALIZE_FORMAT_JSON, 0, 0 }, + { "", HB_BUFFER_SERIALIZE_FORMAT_TEXT, 0, 0 }, +}; + +static void +test_buffer_serialize_deserialize (void) +{ + hb_buffer_t *b; + unsigned int i; + + for (i = 0; i < G_N_ELEMENTS (serialization_tests); i++) + { + unsigned int consumed; + char round_trip[1024]; + + b = hb_buffer_create (); + hb_buffer_set_replacement_codepoint (b, (hb_codepoint_t) -1); + + const serialization_test_t *test = &serialization_tests[i]; + g_test_message ("serialize test #%d", i); + + (void) hb_buffer_deserialize_unicode (b, test->contents, -1, NULL, test->format); + + // Expected parse failure, got one, don't round-trip + if (test->success != 0) + { + unsigned int num_glyphs = hb_buffer_get_length (b); + g_assert_cmpint (num_glyphs, ==, test->num_items); + + hb_buffer_serialize_unicode (b, 0, num_glyphs, round_trip, + sizeof(round_trip), &consumed, test->format, + HB_BUFFER_SERIALIZE_FLAG_DEFAULT); + g_assert_cmpstr (round_trip, ==, test->contents); + } + + hb_buffer_destroy (b); + + } + + char test[1024]; + unsigned int consumed; + hb_buffer_t *indeterminate = hb_buffer_get_empty (); + hb_buffer_serialize (indeterminate, 0, (unsigned) -1, + test, sizeof(test), &consumed, NULL, + HB_BUFFER_SERIALIZE_FORMAT_JSON, + HB_BUFFER_SERIALIZE_FLAG_DEFAULT); + g_assert_cmpstr ( test, ==, "[]"); + + hb_buffer_serialize (indeterminate, 0, (unsigned) - 1, + test, sizeof(test), &consumed, NULL, + HB_BUFFER_SERIALIZE_FORMAT_TEXT, + HB_BUFFER_SERIALIZE_FLAG_DEFAULT); + g_assert_cmpstr ( test, ==, "!!"); + +} + int main (int argc, char **argv) { @@ -880,6 +948,7 @@ main (int argc, char **argv) hb_test_add (test_buffer_utf16_conversion); hb_test_add (test_buffer_utf32_conversion); hb_test_add (test_buffer_empty); + hb_test_add (test_buffer_serialize_deserialize); return hb_test_run(); } diff --git a/test/api/test-collect-unicodes.c b/test/api/test-collect-unicodes.c index 50965a9026ce3649f24858618b6607c6616de3a8..8a857e1c0fa7331f3e6b52b429003e2c0a5ba3cc 100644 --- a/test/api/test-collect-unicodes.c +++ b/test/api/test-collect-unicodes.c @@ -49,6 +49,27 @@ test_collect_unicodes_format4 (void) hb_face_destroy (face); } +static void +test_collect_unicodes_format12_notdef (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/cmunrm.otf"); + hb_set_t *codepoints = hb_set_create(); + hb_codepoint_t cp; + + hb_face_collect_unicodes (face, codepoints); + + cp = HB_SET_VALUE_INVALID; + g_assert (hb_set_next (codepoints, &cp)); + g_assert_cmpuint (0x20, ==, cp); + g_assert (hb_set_next (codepoints, &cp)); + g_assert_cmpuint (0x21, ==, cp); + g_assert (hb_set_next (codepoints, &cp)); + g_assert_cmpuint (0x22, ==, cp); + + hb_set_destroy (codepoints); + hb_face_destroy (face); +} + static void test_collect_unicodes_format12 (void) { @@ -101,6 +122,7 @@ main (int argc, char **argv) hb_test_add (test_collect_unicodes); hb_test_add (test_collect_unicodes_format4); hb_test_add (test_collect_unicodes_format12); + hb_test_add (test_collect_unicodes_format12_notdef); return hb_test_run(); } diff --git a/test/api/test-draw.c b/test/api/test-draw.c new file mode 100644 index 0000000000000000000000000000000000000000..c502f7d3aef66a47b6804d959a1d5703823a00bd --- /dev/null +++ b/test/api/test-draw.c @@ -0,0 +1,945 @@ +/* + * Copyright © 2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb-test.h" + +#include + +#ifdef HB_EXPERIMENTAL_API +typedef struct user_data_t +{ + char *str; + unsigned size; + unsigned consumed; +} user_data_t; + +/* Our modified itoa, why not using libc's? it is going to be used + in harfbuzzjs where libc isn't available */ +static void _hb_reverse (char *buf, unsigned int len) +{ + unsigned start = 0, end = len - 1; + while (start < end) + { + char c = buf[end]; + buf[end] = buf[start]; + buf[start] = c; + start++; end--; + } +} +static unsigned _hb_itoa (int32_t num, char *buf) +{ + unsigned int i = 0; + hb_bool_t is_negative = num < 0; + if (is_negative) num = -num; + do + { + buf[i++] = '0' + num % 10; + num /= 10; + } while (num); + if (is_negative) buf[i++] = '-'; + _hb_reverse (buf, i); + buf[i] = '\0'; + return i; +} + +#define ITOA_BUF_SIZE 12 // 10 digits in int32, 1 for negative sign, 1 for \0 + +static void +test_itoa (void) +{ + char s[] = "12345"; + _hb_reverse (s, 5); + g_assert_cmpmem (s, 5, "54321", 5); + + { + unsigned num = 12345; + char buf[ITOA_BUF_SIZE]; + unsigned len = _hb_itoa (num, buf); + g_assert_cmpmem (buf, len, "12345", 5); + } + + { + unsigned num = 3152; + char buf[ITOA_BUF_SIZE]; + unsigned len = _hb_itoa (num, buf); + g_assert_cmpmem (buf, len, "3152", 4); + } + + { + int num = -6457; + char buf[ITOA_BUF_SIZE]; + unsigned len = _hb_itoa (num, buf); + g_assert_cmpmem (buf, len, "-6457", 5); + } +} + +static void +move_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data) +{ + /* 4 = command character space + comma + array starts with 0 index + nul character space */ + if (user_data->consumed + 2 * ITOA_BUF_SIZE + 4 > user_data->size) return; + user_data->str[user_data->consumed++] = 'M'; + user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed); +} + +static void +line_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data) +{ + if (user_data->consumed + 2 * ITOA_BUF_SIZE + 4 > user_data->size) return; + user_data->str[user_data->consumed++] = 'L'; + user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed); +} + +static void +quadratic_to (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y, + user_data_t *user_data) +{ + + if (user_data->consumed + 4 * ITOA_BUF_SIZE + 6 > user_data->size) return; + user_data->str[user_data->consumed++] = 'Q'; + user_data->consumed += _hb_itoa (control_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (control_y, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ' '; + user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed); +} + +static void +cubic_to (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y, + user_data_t *user_data) +{ + if (user_data->consumed + 6 * ITOA_BUF_SIZE + 8 > user_data->size) return; + user_data->str[user_data->consumed++] = 'C'; + user_data->consumed += _hb_itoa (control1_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (control1_y, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ' '; + user_data->consumed += _hb_itoa (control2_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (control2_y, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ' '; + user_data->consumed += _hb_itoa (to_x, user_data->str + user_data->consumed); + user_data->str[user_data->consumed++] = ','; + user_data->consumed += _hb_itoa (to_y, user_data->str + user_data->consumed); +} + +static void +close_path (user_data_t *user_data) +{ + if (user_data->consumed + 2 > user_data->size) return; + user_data->str[user_data->consumed++] = 'Z'; +} + +static hb_draw_funcs_t *funcs; +static hb_draw_funcs_t *funcs2; /* this one translates quadratic calls to cubic ones */ + +static void +test_hb_draw_empty (void) +{ + g_assert (!hb_font_draw_glyph (hb_font_get_empty (), 3, funcs, NULL)); +} + +static void +test_hb_draw_glyf (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + char str[1024]; + user_data_t user_data = { + .str = str, + .size = sizeof (str), + .consumed = 0 + }; + + user_data.consumed = 0; + g_assert (!hb_font_draw_glyph (font, 4, funcs, &user_data)); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data)); + char expected[] = "M275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245" + "Q126,182 147,139Q167,95 204,73Q240,50 287,50Q330,50 367,70" + "Q404,90 427,128L451,116Q431,54 384,21Q336,-13 266,-13" + "Q198,-13 148,18Q97,48 70,104Q43,160 43,236Q43,314 76,371" + "Q108,427 160,457Q212,487 272,487Q316,487 354,470Q392,453 417,424" + "Q442,395 448,358Q441,321 403,321Q378,321 367,334" + "Q355,347 350,366L325,454L371,417Q346,430 321,436Q296,442 275,442Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + /* Test translating quadratic calls to cubic by a _draw_funcs_t that doesn't set the callback */ + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 3, funcs2, &user_data)); + char expected2[] = "M275,442C246,442 221,435 198,420C175,405 158,382 145,353" + "C132,324 126,288 126,245C126,203 133,168 147,139C160,110 179,88 204,73" + "C228,58 256,50 287,50C316,50 342,57 367,70C392,83 412,103 427,128" + "L451,116C438,75 415,43 384,21C352,-2 313,-13 266,-13C221,-13 181,-3 148,18" + "C114,38 88,67 70,104C52,141 43,185 43,236C43,288 54,333 76,371" + "C97,408 125,437 160,457C195,477 232,487 272,487C301,487 329,481 354,470" + "C379,459 400,443 417,424C434,405 444,383 448,358C443,333 428,321 403,321" + "C386,321 374,325 367,334C359,343 353,353 350,366L325,454L371,417" + "C354,426 338,432 321,436C304,440 289,442 275,442Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + hb_variation_t var; + var.tag = HB_TAG ('w','g','h','t'); + var.value = 800; + hb_font_set_variations (font, &var, 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data)); + char expected3[] = "M323,448Q297,448 271,430Q244,412 226,371Q209,330 209,261" + "Q209,204 225,166Q242,127 272,107Q303,86 344,86Q378,86 404,101" + "Q430,115 451,137L488,103Q458,42 404,13Q350,-16 279,-16" + "Q211,-16 153,13Q95,41 60,98Q25,156 25,241Q25,323 62,382" + "Q99,440 163,470Q226,501 303,501Q357,501 399,480Q440,460 464,426" + "Q488,392 492,352Q475,297 420,297Q390,297 366,319Q342,342 339,401" + "L333,469L411,427Q387,438 367,443Q348,448 323,448Z"; + g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1); + + hb_font_destroy (font); +} + +static void +test_hb_draw_cff1 (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/cff1_seac.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + char str[1024]; + user_data_t user_data = { + .str = str, + .size = sizeof (str), + .consumed = 0 + }; + g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data)); + char expected[] = "M203,367C227,440 248,512 268,588L272,588C293,512 314,440 338,367L369,267L172,267L203,367Z" + "M3,0L88,0L151,200L390,200L452,0L541,0L319,656L225,656L3,0Z" + "M300,653L342,694L201,861L143,806L300,653Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); +} + +static void +test_hb_draw_cff1_rline (void) +{ + /* https://github.com/harfbuzz/harfbuzz/pull/2053 */ + hb_face_t *face = hb_test_open_font_file ("fonts/RanaKufi-Regular.subset.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + char str[1024]; + user_data_t user_data = { + .str = str, + .size = sizeof (str), + .consumed = 0 + }; + g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data)); + char expected[] = "M775,400C705,400 650,343 650,274L650,250L391,250L713,572L392,893" + "L287,1000C311,942 296,869 250,823C250,823 286,858 321,823L571,572" + "L150,150L750,150L750,276C750,289 761,300 775,300C789,300 800,289 800,276" + "L800,100L150,100C100,100 100,150 100,150C100,85 58,23 0,0L900,0L900,274" + "C900,343 844,400 775,400Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); +} + +static void +test_hb_draw_cff2 (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + char str[1024]; + user_data_t user_data = { + .str = str, + .size = sizeof (str) + }; + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data)); + char expected[] = "M275,442C303,442 337,435 371,417L325,454L350,366" + "C357,341 370,321 403,321C428,321 443,333 448,358" + "C435,432 361,487 272,487C153,487 43,393 43,236" + "C43,83 129,-13 266,-13C360,-13 424,33 451,116L427,128" + "C396,78 345,50 287,50C193,50 126,119 126,245C126,373 188,442 275,442Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_variation_t var; + var.tag = HB_TAG ('w','g','h','t'); + var.value = 800; + hb_font_set_variations (font, &var, 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data)); + char expected2[] = "M323,448C356,448 380,441 411,427L333,469L339,401" + "C343,322 379,297 420,297C458,297 480,314 492,352" + "C486,433 412,501 303,501C148,501 25,406 25,241" + "C25,70 143,-16 279,-16C374,-16 447,22 488,103L451,137" + "C423,107 390,86 344,86C262,86 209,148 209,261C209,398 271,448 323,448Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + hb_font_destroy (font); +} + +static void +test_hb_draw_ttf_parser_tests (void) +{ + /* https://github.com/RazrFalcon/ttf-parser/blob/337e7d1c/tests/tests.rs#L50-L133 */ + char str[1024]; + user_data_t user_data = { + .str = str, + .size = sizeof (str) + }; + { + hb_face_t *face = hb_test_open_font_file ("fonts/glyphs.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + { + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 0, funcs, &user_data)); + char expected[] = "M50,0L50,750L450,750L450,0L50,0Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + { + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data)); + char expected[] = "M56,416L56,487L514,487L514,416L56,416ZM56,217L56,288L514,288L514,217L56,217Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + { + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data)); + char expected[] = "M332,468L197,468L197,0L109,0L109,468L15,468L15,509L109,539" + "L109,570Q109,674 155,720Q201,765 283,765Q315,765 342,760" + "Q368,754 387,747L364,678Q348,683 327,688Q306,693 284,693" + "Q240,693 219,664Q197,634 197,571L197,536L332,536L332,468Z" + "M474,737Q494,737 510,724Q525,710 525,681Q525,653 510,639" + "Q494,625 474,625Q452,625 437,639Q422,653 422,681" + "Q422,710 437,724Q452,737 474,737ZM517,536L517,0L429,0L429,536L517,536Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + { + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data)); + char expected[] = ""; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + { + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data)); + char expected[] = "M346,468L211,468L211,0L123,0L123,468L29,468L29,509L123,539" + "L123,570Q123,674 169,720Q215,765 297,765Q329,765 356,760" + "Q382,754 401,747L378,678Q362,683 341,688Q320,693 298,693" + "Q254,693 233,664Q211,634 211,571L211,536L346,536L346,468Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + + hb_font_destroy (font); + } + { + hb_face_t *face = hb_test_open_font_file ("fonts/cff1_flex.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data)); + char expected[] = "M0,0C100,0 150,-20 250,-20C350,-20 400,0 500,0C500,100 520,150 520,250" + "C520,350 500,400 500,500C400,500 350,520 250,520C150,520 100,500 0,500" + "C0,400 -20,350 -20,250C-20,150 0,100 0,0ZM50,50C50,130 34,170 34,250" + "C34,330 50,370 50,450C130,450 170,466 250,466C330,466 370,450 450,450" + "C450,370 466,330 466,250C466,170 450,130 450,50C370,50 330,34 250,34" + "C170,34 130,50 50,50Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } + { + hb_face_t *face = hb_test_open_font_file ("fonts/cff1_dotsect.nohints.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data)); + char expected[] = "M82,0L164,0L164,486L82,486L82,0Z" + "M124,586C156,586 181,608 181,639C181,671 156,692 124,692" + "C92,692 67,671 67,639C67,608 92,586 124,586Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } +} + +static void +test_hb_draw_font_kit_glyphs_tests (void) +{ + /* https://github.com/foliojs/fontkit/blob/master/test/glyphs.js */ + char str[2048]; + user_data_t user_data = { + .str = str, + .size = sizeof (str) + }; + /* truetype glyphs */ + { + hb_face_t *face = hb_test_open_font_file ("fonts/OpenSans-Regular.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + /* should get a path for the glyph */ + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 37, funcs, &user_data)); + char expected[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100" + "Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416" + "Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836" + "Q831,836 910,893Q989,949 989,1083Q989,1206 901,1261" + "Q813,1315 621,1315L371,1315L371,836ZM371,692L371,145L676,145" + "Q853,145 943,214Q1032,282 1032,428Q1032,564 941,628Q849,692 662,692L371,692Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + /* should get a path for the glyph */ + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 171, funcs, &user_data)); + char expected2[] = "M639,-20Q396,-20 256,128Q115,276 115,539Q115,804 246,960Q376,1116 596,1116" + "Q802,1116 922,981Q1042,845 1042,623L1042,518L287,518Q292,325 385,225" + "Q477,125 645,125Q822,125 995,199L995,51Q907,13 829,-3Q750,-20 639,-20Z" + "M594,977Q462,977 384,891Q305,805 291,653L864,653Q864,810 794,894" + "Q724,977 594,977ZM471,1266Q519,1328 575,1416Q630,1504 662,1569" + "L864,1569L864,1548Q820,1483 733,1388Q646,1293 582,1241L471,1241L471,1266Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + hb_font_destroy (font); + } + { + hb_face_t *face = hb_test_open_font_file ("fonts/Mada-VF.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = 1610; /* ي */ + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_RTL); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + /* should resolve composite glyphs recursively */ + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M581,274L443,274Q409,274 384,259Q359,243 348,219Q336,194 340,166" + "Q343,138 365,111L468,-13Q470,-10 473,-6Q475,-3 477,0L253,0Q225,0 203,8" + "Q180,15 168,32Q155,48 155,73L155,269L50,269L50,73Q50,24 69,-10" + "Q88,-44 118,-64Q147,-85 181,-94Q214,-104 243,-104L473,-104" + "Q501,-104 525,-91Q549,-78 564,-56Q578,-34 578,-8Q578,18 557,43" + "L442,182Q439,179 437,176Q435,173 432,170L581,170L581,274ZM184,-194" + "Q184,-216 199,-231Q214,-246 236,-246Q258,-246 273,-231Q288,-216 288,-194" + "Q288,-172 273,-157Q258,-142 236,-142Q214,-142 199,-157Q184,-172 184,-194Z" + "M360,-194Q360,-216 375,-231Q390,-246 412,-246Q434,-246 449,-231" + "Q464,-216 464,-194Q464,-172 449,-157Q434,-142 412,-142" + "Q390,-142 375,-157Q360,-172 360,-194Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + /* should transform points of a composite glyph */ + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 2, funcs, &user_data)); /* 2 == arAlef.fina */ + char expected2[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105" + "L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51" + "Q50,74 50,104L50,624L155,624ZM282,105L312,105" + "L312,0L282,0L282,105Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + hb_font_destroy (font); + } + /* CFF glyphs, should get a path for the glyph */ + { + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data)); + char expected[] = "M90,0L258,0C456,0 564,122 564,331C564,539 456,656 254,656L90,656L90,0Z" + "M173,68L173,588L248,588C401,588 478,496 478,331C478,165 401,68 248,68L173,68Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } + /* CFF glyphs (CID font) */ + { + /* replaced with a subset as the original one was 15MB */ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoSansCJKkr-Regular-subset-colon.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data)); + char expected[] = "M139,390C175,390 205,419 205,459C205,501 175,530 139,530C103,530 73,501 73,459" + "C73,419 103,390 139,390ZM139,-13C175,-13 205,15 205,56C205,97 175,127 139,127" + "C103,127 73,97 73,56C73,15 103,-13 139,-13Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } + /* Skip SBIX glyphs (empty path), COLR glyphs (empty path), WOFF ttf glyphs, WOFF2 ttf glyph */ +} + +static void +test_hb_draw_font_kit_variations_tests (void) +{ + /* https://github.com/foliojs/fontkit/blob/b310db5/test/variations.js */ + char str[2048]; + user_data_t user_data = { + .str = str, + .size = sizeof (str) + }; + /* Skia */ + { + /* Skipping Skia tests for now even the fact we can actually do platform specific tests using our CIs */ + } + /* truetype variations */ + /* should support sharing all points */ + { + hb_face_t *face = hb_test_open_font_file ("fonts/TestGVAROne.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + hb_variation_t var; + var.tag = HB_TAG ('w','g','h','t'); + var.value = 300; + hb_font_set_variations (font, &var, 1); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = 24396; /* 彌 */ + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_LTR); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102" + "Q796,-102 755,-98L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504" + "L414,504L414,-102L371,-102ZM203,-94Q138,-94 86,-90L74,-52" + "Q137,-59 188,-59Q211,-59 222,-46Q233,-34 236,12Q238,58 240,135" + "Q242,211 242,262L74,262L94,527L242,527L242,719L63,719L63,754" + "L285,754L285,492L133,492L117,297L285,297Q285,241 284,185" + "Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94Z" + "M461,12L434,43Q473,73 503,115Q478,150 441,188L469,211Q501,179 525,147" + "Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43L566,20" + "Q544,64 528,86Q500,44 461,12ZM465,258L438,285Q474,316 501,351" + "Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453L598,434" + "Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322Q491,280 465,258Z" + "M707,12L680,43Q717,68 753,115Q731,147 691,188L719,211Q739,190 754,172" + "Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117Q828,82 852,43" + "L820,20Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730L664,-94" + "L621,-94ZM348,570L324,605Q425,629 527,688L555,656Q491,621 439,601" + "Q386,581 348,570ZM715,258L688,285Q727,318 753,351Q733,378 695,418L723,441" + "Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352Q823,321 848,281" + "L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754L941,754L941,719" + "L348,719ZM936,570Q870,602 817,622Q764,641 727,652L749,688Q852,655 957,605L936,570Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } + /* should support sharing enumerated points */ + { + hb_face_t *face = hb_test_open_font_file ("fonts/TestGVARTwo.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + hb_variation_t var; + var.tag = HB_TAG ('w','g','h','t'); + var.value = 300; + hb_font_set_variations (font, &var, 1); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = 24396; /* 彌 */ + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_LTR); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98" + "L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102" + "L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46" + "Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527" + "L242,719L63,719L63,754L285,754L285,492L133,492L117,297L285,297" + "Q285,241 284,185Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94Z" + "M461,12L434,43Q473,73 503,115Q478,150 441,188L469,211Q501,179 525,147" + "Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43L566,20" + "Q544,64 528,86Q500,44 461,12ZM465,258L438,285Q474,316 501,351" + "Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453L598,434" + "Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322Q491,280 465,258Z" + "M707,12L680,43Q717,68 753,115Q731,147 691,188L719,211Q739,190 754,172" + "Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117Q828,82 852,43L820,20" + "Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730L664,-94L621,-94ZM348,570" + "L324,605Q425,629 527,688L555,656Q491,621 439,601Q386,581 348,570ZM715,258L688,285" + "Q727,318 753,351Q733,378 695,418L723,441Q754,410 775,381Q794,407 813,453" + "L848,434Q826,387 801,352Q823,321 848,281L813,262Q791,301 775,323Q749,288 715,258Z" + "M348,719L348,754L941,754L941,719L348,719ZM936,570Q870,602 817,622" + "Q764,641 727,652L749,688Q852,655 957,605L936,570Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } + /* should support sharing no points */ + { + hb_face_t *face = hb_test_open_font_file ("fonts/TestGVARThree.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + hb_variation_t var; + var.tag = HB_TAG ('w','g','h','t'); + var.value = 300; + hb_font_set_variations (font, &var, 1); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = 24396; /* 彌 */ + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_LTR); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98" + "L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102" + "L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-46" + "Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527L242,719" + "L63,719L63,754L285,754L285,492L133,492L117,297L285,297Q285,241 284,185" + "Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94ZM461,12" + "L434,43Q473,73 503,115Q478,150 441,188L469,211Q501,179 525,147" + "Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43L566,20Q544,64 528,86" + "Q500,44 461,12ZM465,258L438,285Q474,316 501,351Q474,388 445,418L473,441" + "Q500,414 523,381Q546,413 563,453L598,434Q571,382 549,352Q576,320 598,285" + "L563,262Q546,294 525,322Q491,280 465,258ZM707,12L680,43Q717,68 753,115" + "Q731,147 691,188L719,211Q739,190 754,172Q769,154 774,147Q793,185 809,230" + "L844,211Q822,155 801,117Q828,82 852,43L820,20Q798,58 778,87Q747,43 707,12Z" + "M621,-94L621,730L664,730L664,-94L621,-94ZM348,570L324,605Q425,629 527,688" + "L555,656Q491,621 439,601Q386,581 348,570ZM715,258L688,285Q727,318 753,351" + "Q733,378 695,418L723,441Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352" + "Q823,321 848,281L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754" + "L941,754L941,719L348,719ZM936,570Q870,602 817,622" + "Q764,641 727,652L749,688Q852,655 957,605L936,570Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + hb_font_destroy (font); + } + + /* CFF2 variations */ + { + hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype-Subset.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + hb_variation_t var; + var.tag = HB_TAG ('w','g','h','t'); + /* applies variations to CFF2 glyphs */ + { + var.value = 100; + hb_font_set_variations (font, &var, 1); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = '$'; + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_LTR); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M246,15C188,15 147,27 101,68L142,23L117,117C111,143 96,149 81,149" + "C65,149 56,141 52,126C71,40 137,-13 244,-13C348,-13 436,46 436,156" + "C436,229 405,295 271,349L247,359C160,393 119,439 119,506" + "C119,592 178,637 262,637C311,637 346,626 390,585L348,629L373,535" + "C380,510 394,503 408,503C424,503 434,510 437,526C418,614 348,665 259,665" + "C161,665 78,606 78,500C78,414 128,361 224,321L261,305C367,259 395,217 395,152" + "C395,65 334,15 246,15ZM267,331L267,759L240,759L240,331L267,331ZM240,-115" + "L267,-115L267,331L240,331L240,-115Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + { + var.value = 500; + hb_font_set_variations (font, &var, 1); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = '$'; + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_LTR); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M251,36C206,36 165,42 118,61L176,21L161,99C151,152 129,167 101,167" + "C78,167 61,155 51,131C54,43 133,-14 247,-14C388,-14 474,64 474,171" + "C474,258 430,321 294,370L257,383C188,406 150,438 150,499" + "C150,571 204,606 276,606C308,606 342,601 386,582L327,621" + "L343,546C355,490 382,476 408,476C428,476 448,487 455,512" + "C450,597 370,656 264,656C140,656 57,576 57,474C57,373 119,318 227,279" + "L263,266C345,236 379,208 379,145C379,76 329,36 251,36ZM289,320" + "L289,746L242,746L242,320L289,320ZM240,-115L286,-115L286,320L240,320L240,-115Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + /* substitutes GSUB features depending on variations */ + { + var.value = 900; + hb_font_set_variations (font, &var, 1); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_codepoint_t codepoint = '$'; + hb_buffer_add_codepoints (buffer, &codepoint, 1, 0, -1); + hb_buffer_set_direction (buffer, HB_DIRECTION_LTR); + hb_shape (font, buffer, NULL, 0); + codepoint = hb_buffer_get_glyph_infos (buffer, NULL)[0].codepoint; + hb_buffer_destroy (buffer); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data)); + char expected[] = "M258,38C197,38 167,48 118,71L192,19L183,103C177,155 155,174 115,174" + "C89,174 64,161 51,125C52,36 124,-16 258,-16C417,-16 513,67 513,175" + "C513,278 457,328 322,388L289,403C232,429 203,452 203,500C203,562 244,589 301,589" + "C342,589 370,585 420,562L341,607L352,539C363,468 398,454 434,454C459,454 486,468 492,506" + "C491,590 408,643 290,643C141,643 57,563 57,460C57,357 122,307 233,256L265,241" + "C334,209 363,186 363,130C363,77 320,38 258,38ZM318,616L318,734L252,734L252,616" + "L318,616ZM253,-115L319,-115L319,14L253,14L253,-115Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + } + + hb_font_destroy (font); + } +} + +static void +test_hb_draw_estedad_vf (void) +{ + /* https://github.com/harfbuzz/harfbuzz/issues/2215 */ + char str[2048]; + user_data_t user_data = { + .str = str, + .size = sizeof (str) + }; + { + /* See https://github.com/google/skia/blob/d38f00a1/gm/stroketext.cpp#L115-L124 */ + hb_face_t *face = hb_test_open_font_file ("fonts/Estedad-VF.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + hb_variation_t var; + hb_variation_from_string ("wght=100", -1, &var); + hb_font_set_variations (font, &var, 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 156, funcs, &user_data)); + /* Skip empty path where all the points of a path are equal */ + char expected[] = "M150,1158L182,1158Q256,1158 317,1170Q377,1182 421,1213L421,430L521,430" + "L521,1490L421,1490L421,1320Q393,1279 344,1262Q294,1244 182,1244L150,1244" + "L150,1158ZM1815,-122L1669,-122L1669,642L1552,642L1055,-117L1055,-206" + "L1569,-206L1569,-458L1669,-458L1669,-206L1815,-206L1815,-122ZM1569,-122" + "L1166,-122L1569,494L1569,-122ZM609,-79L1639,1288L1555,1334L525,-33L609,-79Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 180, funcs, &user_data)); + /* Skip empty path where all the points of a path are equal */ + char expected2[] = "M120,693Q120,545 177,414Q233,282 333,182Q433,81 567,24" + "Q701,-33 856,-33Q1010,-33 1144,24Q1277,81 1377,182Q1477,282 1534,414" + "Q1590,545 1590,693Q1590,842 1534,973Q1477,1104 1377,1205" + "Q1277,1305 1144,1362Q1010,1419 856,1419Q701,1419 567,1362" + "Q433,1305 333,1205Q233,1104 177,973Q120,842 120,693Z" + "M220,693Q220,828 270,945Q320,1061 409,1148Q497,1235 612,1284" + "Q726,1333 855,1333Q984,1333 1099,1284Q1213,1235 1302,1148" + "Q1390,1061 1440,945Q1490,828 1490,693Q1490,558 1440,442" + "Q1390,325 1302,237Q1213,149 1099,100Q984,51 855,51" + "Q726,51 611,100Q497,149 408,237Q320,325 270,442" + "Q220,558 220,693ZM690,643L690,997L886,997Q970,997 1029,949" + "Q1087,901 1087,819Q1087,737 1028,690Q969,643 886,643L690,643Z" + "M1165,334L973,568Q1065,591 1126,658Q1187,725 1187,819" + "Q1187,896 1147,956Q1106,1015 1037,1049Q969,1083 886,1083" + "L590,1083L590,310L690,310L690,557L860,557L1083,286L1165,334Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 262, funcs, &user_data)); + /* Skip empty path where all the points of a path are equal */ + char expected3[] = "M422,598Q495,598 545,548Q595,498 595,426Q595,353 545,303Q494,252 422,252" + "Q350,252 300,303Q250,353 250,426Q250,499 300,549Q349,598 422,598ZM422,698" + "Q347,698 285,662Q223,625 187,564Q150,502 150,426Q150,351 187,289" + "Q223,226 285,189Q346,152 422,152Q498,152 560,189Q622,226 658,288" + "Q695,351 695,426Q695,502 658,563Q621,625 559,661Q498,698 422,698Z"; + g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1); + + hb_font_destroy (font); + } +} + +static void +test_hb_draw_stroking (void) +{ + /* https://skia-review.googlesource.com/c/skia/+/266945 + https://savannah.nongnu.org/bugs/index.php?57701 */ + char str[2048]; + user_data_t user_data = { + .str = str, + .size = sizeof (str) + }; + { + /* See https://github.com/google/skia/blob/d38f00a1/gm/stroketext.cpp#L115-L124 */ + hb_face_t *face = hb_test_open_font_file ("fonts/Stroking.ttf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data)); + /* Skip empty path where all the points of a path are equal */ + char expected[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427Q1384,332 1626,332" + "Q1868,332 2089,427Q2309,521 2468,680Q2627,839 2722,1060Q2816,1280 2816,1522" + "Q2816,1764 2722,1985Q2627,2205 2468,2364Q2309,2523 2089,2618Q1868,2712 1626,2712" + "Q1384,2712 1164,2618Q943,2523 784,2364Q625,2205 531,1985Q436,1764 436,1522ZM256,1528" + "Q256,1714 306,1892Q355,2069 443,2220Q531,2370 658,2497Q784,2623 935,2711" + "Q1085,2799 1263,2849Q1440,2898 1626,2898Q1812,2898 1990,2849Q2167,2799 2318,2711" + "Q2468,2623 2595,2497Q2721,2370 2809,2220Q2897,2069 2947,1892Q2996,1714 2996,1528" + "Q2996,1342 2947,1165Q2897,987 2809,837Q2721,686 2595,560Q2468,433 2318,345" + "Q2167,257 1990,208Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345" + "Q784,433 658,560Q531,686 443,837Q355,987 306,1165Q256,1342 256,1528Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 7, funcs, &user_data)); + char expected2[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427" + "Q1384,332 1626,332Q1868,332 2089,427Q2309,521 2468,680" + "Q2627,839 2722,1060Q2816,1280 2816,1522Q2816,1764 2722,1985" + "Q2627,2205 2468,2364Q2309,2523 2089,2618Q1868,2712 1626,2712" + "Q1384,2712 1164,2618Q943,2523 784,2364Q625,2205 531,1985" + "Q436,1764 436,1522ZM256,1528Q256,1714 306,1892Q355,2069 443,2220" + "Q531,2370 658,2497Q784,2623 935,2711Q1085,2799 1263,2849" + "Q1440,2898 1626,2898Q1812,2898 1990,2849Q2167,2799 2318,2711" + "Q2468,2623 2595,2497Q2721,2370 2809,2220Q2897,2069 2947,1892" + "Q2996,1714 2996,1528Q2996,1342 2947,1165Q2897,987 2809,837" + "Q2721,686 2595,560Q2468,433 2318,345Q2167,257 1990,208" + "Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345" + "Q784,433 658,560Q531,686 443,837Q355,987 306,1165" + "Q256,1342 256,1528Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + hb_font_destroy (font); + } + { + /* https://github.com/google/skia/blob/d38f00a1/gm/stroketext.cpp#L131-L138 */ + hb_face_t *face = hb_test_open_font_file ("fonts/Stroking.otf"); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data)); + /* Skip empty path in CFF */ + char expected[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372C688,212 557,81 397,81C237,81 106,212 106,372Z" + "M62,373C62,188 212,39 397,39C582,39 731,188 731,373C731,558 582,708 397,708C212,708 62,558 62,373Z"; + g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1); + + user_data.consumed = 0; + g_assert (hb_font_draw_glyph (font, 5, funcs, &user_data)); + /* Fold consequent move-to commands */ + char expected2[] = "M106,372C106,532 237,662 397,662C557,662 688,532 688,372" + "C688,212 557,81 397,81C237,81 106,212 106,372ZM62,373" + "C62,188 212,39 397,39C582,39 731,188 731,373" + "C731,558 582,708 397,708C212,708 62,558 62,373Z"; + g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1); + + hb_font_destroy (font); + } +} + +static void +test_hb_draw_immutable (void) +{ + hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create (); + g_assert (!hb_draw_funcs_is_immutable (draw_funcs)); + hb_draw_funcs_make_immutable (draw_funcs); + g_assert (hb_draw_funcs_is_immutable (draw_funcs)); + hb_draw_funcs_destroy (draw_funcs); +} + +int +main (int argc, char **argv) +{ + funcs = hb_draw_funcs_create (); + hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to); + hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to); + hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to); + hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to); + hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path); + hb_draw_funcs_make_immutable (funcs); + + funcs2 = hb_draw_funcs_create (); + hb_draw_funcs_set_move_to_func (funcs2, (hb_draw_move_to_func_t) move_to); + hb_draw_funcs_set_line_to_func (funcs2, (hb_draw_line_to_func_t) line_to); + hb_draw_funcs_set_cubic_to_func (funcs2, (hb_draw_cubic_to_func_t) cubic_to); + hb_draw_funcs_set_close_path_func (funcs2, (hb_draw_close_path_func_t) close_path); + hb_draw_funcs_make_immutable (funcs2); + + hb_test_init (&argc, &argv); + hb_test_add (test_itoa); + hb_test_add (test_hb_draw_empty); + hb_test_add (test_hb_draw_glyf); + hb_test_add (test_hb_draw_cff1); + hb_test_add (test_hb_draw_cff1_rline); + hb_test_add (test_hb_draw_cff2); + hb_test_add (test_hb_draw_ttf_parser_tests); + hb_test_add (test_hb_draw_font_kit_glyphs_tests); + hb_test_add (test_hb_draw_font_kit_variations_tests); + hb_test_add (test_hb_draw_estedad_vf); + hb_test_add (test_hb_draw_stroking); + hb_test_add (test_hb_draw_immutable); + unsigned result = hb_test_run (); + + hb_draw_funcs_destroy (funcs); + hb_draw_funcs_destroy (funcs2); + return result; +} +#else +int main (int argc HB_UNUSED, char **argv HB_UNUSED) +{ + return 0; +} +#endif diff --git a/test/api/test-object.c b/test/api/test-object.c index 093615e8cc241869b6d2ed9a12f1fcf4fff5dad0..5154621e9633524314d20c8eae42ef278a3ced2b 100644 --- a/test/api/test-object.c +++ b/test/api/test-object.c @@ -345,7 +345,7 @@ test_object (void) if (!obj) continue; if (obj == o->get_empty ()) - continue; /* Tested already */ + continue; /* Tested already */ g_assert (obj == o->reference (obj)); o->destroy (obj); diff --git a/src/dump-myanmar-data.cc b/test/api/test-ot-alternates.c similarity index 57% rename from src/dump-myanmar-data.cc rename to test/api/test-ot-alternates.c index c1a303f8f1ac99fd1db76043f57805aa41388db8..4db6b15586eda714bae8d849d872d8512c49b2d5 100644 --- a/src/dump-myanmar-data.cc +++ b/test/api/test-ot-alternates.c @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Google, Inc. + * Copyright © 2020 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -20,24 +20,34 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod */ -#include "hb-ot-shape-complex-myanmar.hh" +#include "hb-test.h" + +#include +#include + +static void +test_ot_layout_lookup_get_glyph_alternates (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansPro-Regular.otf"); + + hb_codepoint_t alternates[3]; + unsigned alternates_count = 3; + g_assert_cmpuint (7, ==, hb_ot_layout_lookup_get_glyph_alternates (face, 1, 1091, 2, &alternates_count, alternates)); + + g_assert_cmpuint (3, ==, alternates_count); + g_assert_cmpuint (1606, ==, alternates[0]); + g_assert_cmpuint (1578, ==, alternates[1]); + g_assert_cmpuint (1592, ==, alternates[2]); + + hb_face_destroy (face); +} int -main () +main (int argc, char **argv) { - for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++) - { - hb_glyph_info_t info; - info.codepoint = u; - set_myanmar_properties (info); - if (info.myanmar_category() != INDIC_SYLLABIC_CATEGORY_OTHER || - info.myanmar_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE) - printf("U+%04X %u %u\n", u, - info.myanmar_category(), - info.myanmar_position()); - } + hb_test_init (&argc, &argv); + hb_test_add (test_ot_layout_lookup_get_glyph_alternates); + return hb_test_run (); } diff --git a/test/api/test-ot-color.c b/test/api/test-ot-color.c index d646f7371885083dc7a1fd44fabb5e818da9ade7..c2bbad2d560cd6cc5f1cad290c07b74d4ce28331 100644 --- a/test/api/test-ot-color.c +++ b/test/api/test-ot-color.c @@ -210,7 +210,7 @@ static void test_hb_ot_color_palette_get_colors_v0 (void) { unsigned int num_colors = hb_ot_color_palette_get_colors (cpal_v0, 0, 0, NULL, NULL); - hb_color_t *colors = (hb_color_t*) alloca (num_colors * sizeof (hb_color_t)); + hb_color_t *colors = (hb_color_t*) malloc (num_colors * sizeof (hb_color_t)); size_t colors_size = num_colors * sizeof(*colors); g_assert_cmpint (num_colors, ==, 2); @@ -252,6 +252,8 @@ test_hb_ot_color_palette_get_colors_v0 (void) g_assert_cmpint (num_colors, ==, 0); assert_color_rgba (colors, 0, 0x44, 0x44, 0x44, 0x44); /* untouched */ assert_color_rgba (colors, 1, 0x44, 0x44, 0x44, 0x44); /* untouched */ + + free (colors); } diff --git a/test/api/test-ot-extents-cff.c b/test/api/test-ot-extents-cff.c index 6810ea4572049ad1f45657a5a3c3ebf734fcfcc9..e6aeb0d6e171fb9b2f4dbef2ed1b0bef70003963 100644 --- a/test/api/test-ot-extents-cff.c +++ b/test/api/test-ot-extents-cff.c @@ -146,8 +146,8 @@ test_extents_cff2 (void) g_assert_cmpint (extents.x_bearing, ==, 38); g_assert_cmpint (extents.y_bearing, ==, 493); - g_assert_cmpint (extents.width, ==, 481); - g_assert_cmpint (extents.height, ==, -508); + g_assert_cmpint (extents.width, ==, 480); + g_assert_cmpint (extents.height, ==, -507); hb_font_destroy (font); } @@ -168,17 +168,17 @@ test_extents_cff2_vsindex (void) hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 11); - g_assert_cmpint (extents.y_bearing, ==, 656); - g_assert_cmpint (extents.width, ==, 653); - g_assert_cmpint (extents.height, ==, -656); + g_assert_cmpint (extents.x_bearing, ==, 12); + g_assert_cmpint (extents.y_bearing, ==, 655); + g_assert_cmpint (extents.width, ==, 651); + g_assert_cmpint (extents.height, ==, -655); result = hb_font_get_glyph_extents (font, 2, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 7); + g_assert_cmpint (extents.x_bearing, ==, 8); g_assert_cmpint (extents.y_bearing, ==, 669); - g_assert_cmpint (extents.width, ==, 650); + g_assert_cmpint (extents.width, ==, 648); g_assert_cmpint (extents.height, ==, -669); hb_font_destroy (font); @@ -199,9 +199,9 @@ test_extents_cff2_vsindex_named_instance (void) hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents); g_assert (result); - g_assert_cmpint (extents.x_bearing, ==, 12); + g_assert_cmpint (extents.x_bearing, ==, 13); g_assert_cmpint (extents.y_bearing, ==, 652); - g_assert_cmpint (extents.width, ==, 653); + g_assert_cmpint (extents.width, ==, 652); g_assert_cmpint (extents.height, ==, -652); result = hb_font_get_glyph_extents (font, 2, &extents); diff --git a/test/api/test-ot-face.c b/test/api/test-ot-face.c index 44a911682cea438aff32a5774d532a62af7db1c3..6a8ebcdf37d18744290cc2f863592c4cc0a0ab52 100644 --- a/test/api/test-ot-face.c +++ b/test/api/test-ot-face.c @@ -27,22 +27,24 @@ #ifndef TEST_OT_FACE_NO_MAIN #include "hb-test.h" #endif +#include #include /* Unit tests for hb-ot-*.h */ - -static void -test_face (hb_face_t *face, - hb_codepoint_t cp) +/* Return some dummy result so that compiler won't just optimize things */ +static long long +test_font (hb_font_t *font, hb_codepoint_t cp) { - hb_font_t *font = hb_font_create (face); + long long result = 0; + + hb_face_t *face = hb_font_get_face (font); hb_set_t *set; - hb_codepoint_t g; - hb_position_t x, y; + hb_codepoint_t g = 0; + hb_position_t x = 0, y = 0; char buf[5] = {0}; - unsigned int len; - hb_glyph_extents_t extents; + unsigned int len = 0; + hb_glyph_extents_t extents = {0}; hb_ot_font_set_funcs (font); set = hb_set_create (); @@ -74,12 +76,55 @@ test_face (hb_face_t *face, hb_ot_color_has_png (face); hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp)); + { + hb_aat_layout_feature_type_t feature = HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC; + unsigned count = 1; + hb_aat_layout_get_feature_types (face, 0, &count, &feature); + hb_aat_layout_feature_type_get_name_id (face, HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE); + hb_aat_layout_feature_selector_info_t setting = {0}; + unsigned default_index; + count = 1; + hb_aat_layout_feature_type_get_selector_infos (face, HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE, 0, &count, &setting, &default_index); + result += count + feature + setting.disable + setting.disable + setting.name_id + setting.reserved + default_index; + } + + hb_set_t *lookup_indexes = hb_set_create (); + hb_set_add (lookup_indexes, 0); + + hb_map_t *lookup_mapping = hb_map_create (); + hb_map_set (lookup_mapping, 0, 0); + hb_set_t *feature_indices = hb_set_create (); + hb_set_destroy (lookup_indexes); + hb_set_destroy (feature_indices); + hb_map_destroy (lookup_mapping); + hb_ot_layout_get_baseline (font, HB_OT_LAYOUT_BASELINE_TAG_HANGING, HB_DIRECTION_RTL, HB_SCRIPT_HANGUL, HB_TAG_NONE, NULL); hb_ot_layout_has_glyph_classes (face); hb_ot_layout_has_substitution (face); hb_ot_layout_has_positioning (face); + hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, cp, 0, NULL, NULL); + + { + unsigned temp = 0, temp2 = 0; + hb_ot_name_id_t name = HB_OT_NAME_ID_FULL_NAME; + hb_ot_layout_get_size_params (face, &temp, &temp, &name, &temp, &temp); + hb_tag_t cv01 = HB_TAG ('c','v','0','1'); + unsigned feature_index = 0; + hb_ot_layout_language_find_feature (face, HB_OT_TAG_GSUB, 0, + HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, + cv01, &feature_index); + hb_ot_layout_feature_get_name_ids (face, HB_OT_TAG_GSUB, feature_index, + &name, &name, &name, &temp, &name); + temp = 1; + hb_ot_layout_feature_get_characters (face, HB_OT_TAG_GSUB, feature_index, 0, &temp, &g); + temp = 1; + hb_ot_layout_language_get_feature_indexes (face, HB_OT_TAG_GSUB, 0, 0, 0, &temp, &temp2); + + result += temp + name + feature_index + temp2; + } + hb_ot_math_has_data (face); hb_ot_math_get_constant (font, HB_OT_MATH_CONSTANT_MATH_LEADING); hb_ot_math_get_glyph_italics_correction (font, cp); @@ -104,20 +149,36 @@ test_face (hb_face_t *face, hb_ot_name_get_utf16 (face, cp, NULL, NULL, NULL); hb_ot_name_get_utf32 (face, cp, NULL, NULL, NULL); +#if 0 + hb_style_get_value (font, HB_STYLE_TAG_ITALIC); + hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE); + hb_style_get_value (font, HB_STYLE_TAG_SLANT); + hb_style_get_value (font, HB_STYLE_TAG_WIDTH); + hb_style_get_value (font, HB_STYLE_TAG_WEIGHT); +#endif + hb_ot_var_get_axis_count (face); hb_ot_var_get_axis_infos (face, 0, NULL, NULL); hb_ot_var_normalize_variations (face, NULL, 0, NULL, 0); hb_ot_var_normalize_coords (face, 0, NULL, NULL); +#ifdef HB_EXPERIMENTAL_API + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + hb_font_draw_glyph (font, cp, funcs, NULL); + hb_draw_funcs_destroy (funcs); +#endif + hb_set_destroy (set); - hb_font_destroy (font); + + return result + g + x + y + buf[0] + buf[1] + buf[2] + buf[3] + buf[4] + len + + extents.height + extents.width + extents.x_bearing + extents.y_bearing; } #ifndef TEST_OT_FACE_NO_MAIN static void test_ot_face_empty (void) { - test_face (hb_face_get_empty (), 0); + test_font (hb_font_get_empty (), 0); } static void diff --git a/test/api/test-ot-glyphname.c b/test/api/test-ot-glyphname.c new file mode 100644 index 0000000000000000000000000000000000000000..635da9f188c3213cf4fd748a5daaaa1891785477 --- /dev/null +++ b/test/api/test-ot-glyphname.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2019 Adobe, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-ot.h" + +static void +test_one_glyph (hb_font_t *font, hb_codepoint_t gid, const char *name) +{ + char buf[64]; + hb_codepoint_t glyph; + + g_assert(hb_font_get_glyph_name (font, gid, buf, sizeof (buf))); + g_assert_cmpstr(buf, ==, name); + g_assert(hb_font_get_glyph_from_name (font, name, -1, &glyph)); + g_assert_cmpint(glyph, ==, gid); +} + +/* Unit tests for CFF glyph names */ + +static void +test_standard_names (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/MathTestFontFull.otf"); + hb_font_t *font = hb_font_create (face); + + test_one_glyph (font, 0, ".notdef"); + test_one_glyph (font, 27, "Z"); + + hb_font_destroy (font); + hb_face_destroy (face); +} + +static void +test_non_standard_names (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/MathTestFontFull.otf"); + hb_font_t *font = hb_font_create (face); + + test_one_glyph (font, 46, "arrowdblright"); + test_one_glyph (font, 138, "uni21E7_size5"); + + hb_font_destroy (font); + hb_face_destroy (face); +} + +static void +test_predef_charset_names (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/cff1_expert.otf"); + hb_font_t *font = hb_font_create (face); + + test_one_glyph (font, 0, ".notdef"); + test_one_glyph (font, 29, "centsuperior"); + test_one_glyph (font, 86, "commainferior"); + + hb_font_destroy (font); + hb_face_destroy (face); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_standard_names); + hb_test_add (test_non_standard_names); + hb_test_add (test_predef_charset_names); + + return hb_test_run(); +} diff --git a/test/api/test-ot-ligature-carets.c b/test/api/test-ot-ligature-carets.c index d84278513bad9c91fd6fed26459150781b2bf661..7e2d91b3ab5d8c44362d5026a486b70ba209a77b 100644 --- a/test/api/test-ot-ligature-carets.c +++ b/test/api/test-ot-ligature-carets.c @@ -28,29 +28,135 @@ #include static void -test_ot_layout_feature_get_name_ids_and_characters (void) +test_ot_layout_get_ligature_carets_ot_gdef (void) { - hb_face_t *face = hb_test_open_font_file ("fonts/lcar.ttf"); + hb_face_t *face = hb_test_open_font_file ("fonts/NotoNastaliqUrdu-Regular.ttf"); hb_font_t *font = hb_font_create (face); hb_font_set_scale (font, hb_face_get_upem (face) * 2, hb_face_get_upem (face) * 4); - hb_position_t caret_array[2]; - unsigned int caret_count = 2; - g_assert_cmpuint (2, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_RTL, - 98, 0, &caret_count, - caret_array)); + hb_position_t caret_array[16]; + + /* call with no result */ + { + unsigned caret_count = 16; + g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 188, 0, &caret_count, + caret_array)); + + g_assert_cmpuint (0, ==, caret_count); + } + + /* call with no result and some offset */ + { + unsigned caret_count = 16; + g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 188, 10, &caret_count, + caret_array)); + + g_assert_cmpuint (0, ==, caret_count); + } + + /* a glyph with 3 ligature carets */ + { + unsigned caret_count = 16; + g_assert_cmpuint (3, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1020, 0, &caret_count, + caret_array)); + + g_assert_cmpuint (3, ==, caret_count); + g_assert_cmpuint (2718, ==, caret_array[0]); + g_assert_cmpuint (5438, ==, caret_array[1]); + g_assert_cmpuint (8156, ==, caret_array[2]); + } + + /* the same glyph as above but with offset */ + { + caret_array[2] = 123; + + unsigned caret_count = 16; + g_assert_cmpuint (3, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1020, 1, &caret_count, + caret_array)); + + g_assert_cmpuint (2, ==, caret_count); + g_assert_cmpuint (5438, ==, caret_array[0]); + g_assert_cmpuint (8156, ==, caret_array[1]); + + g_assert_cmpuint (123, ==, caret_array[2]); + } + + /* the same glyph as above but with another offset */ + { + unsigned caret_count = 16; + g_assert_cmpuint (3, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1020, 2, &caret_count, + caret_array)); + + g_assert_cmpuint (1, ==, caret_count); + g_assert_cmpuint (8156, ==, caret_array[0]); + } + + /* call with no result */ + { + unsigned caret_count = 16; + g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1021, 0, &caret_count, + caret_array)); + + g_assert_cmpuint (0, ==, caret_count); + } - g_assert_cmpuint (2, ==, caret_count); - g_assert_cmpuint (1130, ==, caret_array[0]); - g_assert_cmpuint (2344, ==, caret_array[1]); + /* a glyph with 1 ligature caret */ + { + unsigned caret_count = 16; + g_assert_cmpuint (1, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1022, 0, &caret_count, + caret_array)); + + g_assert_cmpuint (1, ==, caret_count); + g_assert_cmpuint (3530, ==, caret_array[0]); + } + + /* the same glyph as above but with offset */ + { + unsigned caret_count = 16; + g_assert_cmpuint (1, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1022, 1, &caret_count, + caret_array)); + + g_assert_cmpuint (0, ==, caret_count); + } + + /* a glyph with 2 ligature carets */ + { + unsigned caret_count = 16; + g_assert_cmpuint (2, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, + 1023, 0, &caret_count, + caret_array)); + + g_assert_cmpuint (2, ==, caret_count); + g_assert_cmpuint (2352, ==, caret_array[0]); + g_assert_cmpuint (4706, ==, caret_array[1]); + } + + hb_font_destroy (font); + hb_face_destroy (face); +} + +static void +test_ot_layout_get_ligature_carets_empty (void) +{ + hb_face_t *face = hb_face_get_empty (); + hb_font_t *font = hb_font_create (face); + hb_font_set_scale (font, hb_face_get_upem (face) * 2, hb_face_get_upem (face) * 4); - g_assert_cmpuint (2, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_BTT, - 98, 0, &caret_count, + hb_position_t caret_array[3]; + unsigned int caret_count = 3; + g_assert_cmpuint (0, ==, hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_RTL, + 1024, 0, &caret_count, caret_array)); - g_assert_cmpuint (2, ==, caret_count); - g_assert_cmpuint (2260, ==, caret_array[0]); - g_assert_cmpuint (4688, ==, caret_array[1]); + g_assert_cmpuint (0, ==, caret_count); hb_font_destroy (font); hb_face_destroy (face); @@ -61,7 +167,8 @@ main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); - hb_test_add (test_ot_layout_feature_get_name_ids_and_characters); + hb_test_add (test_ot_layout_get_ligature_carets_ot_gdef); + hb_test_add (test_ot_layout_get_ligature_carets_empty); return hb_test_run (); } diff --git a/test/api/test-ot-math.c b/test/api/test-ot-math.c index 000b0a2c50e0e5f6adc54ef9937254a77f60e931..73b1a25eebf93f07b155ddba484dd4a446399fb4 100644 --- a/test/api/test-ot-math.c +++ b/test/api/test-ot-math.c @@ -457,41 +457,41 @@ test_get_glyph_variants (void) g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph)); g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, - glyph, - HB_DIRECTION_BTT, - 0, - NULL, - NULL), ==, 0); + glyph, + HB_DIRECTION_BTT, + 0, + NULL, + NULL), ==, 0); g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, - glyph, - HB_DIRECTION_RTL, - 0, - NULL, - NULL), ==, 3); + glyph, + HB_DIRECTION_RTL, + 0, + NULL, + NULL), ==, 3); g_assert(hb_font_get_glyph_from_name (hb_font, "arrowup", -1, &glyph)); g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, - glyph, - HB_DIRECTION_BTT, - 0, - NULL, - NULL), ==, 4); + glyph, + HB_DIRECTION_BTT, + 0, + NULL, + NULL), ==, 4); g_assert_cmpint(hb_ot_math_get_glyph_variants (hb_font, - glyph, - HB_DIRECTION_RTL, - 0, - NULL, - NULL), ==, 0); + glyph, + HB_DIRECTION_RTL, + 0, + NULL, + NULL), ==, 0); g_assert(hb_font_get_glyph_from_name (hb_font, "arrowleft", -1, &glyph)); do { count = variantsSize; hb_ot_math_get_glyph_variants (hb_font, - glyph, - HB_DIRECTION_RTL, - offset, - &count, - variants); + glyph, + HB_DIRECTION_RTL, + offset, + &count, + variants); offset += count; } while (count == variantsSize); g_assert_cmpint(offset, ==, 3); @@ -510,11 +510,11 @@ test_get_glyph_variants (void) do { count = variantsSize; hb_ot_math_get_glyph_variants (hb_font, - glyph, - HB_DIRECTION_BTT, - offset, - &count, - variants); + glyph, + HB_DIRECTION_BTT, + offset, + &count, + variants); offset += count; } while (count == variantsSize); g_assert_cmpint(offset, ==, 4); @@ -581,46 +581,46 @@ test_get_glyph_assembly (void) g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph)); g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, - glyph, - HB_DIRECTION_BTT, - 0, - NULL, - NULL, - NULL), ==, 0); + glyph, + HB_DIRECTION_BTT, + 0, + NULL, + NULL, + NULL), ==, 0); g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, - glyph, - HB_DIRECTION_RTL, - 0, - NULL, - NULL, - NULL), ==, 3); + glyph, + HB_DIRECTION_RTL, + 0, + NULL, + NULL, + NULL), ==, 3); g_assert(hb_font_get_glyph_from_name (hb_font, "arrowdown", -1, &glyph)); g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, - glyph, - HB_DIRECTION_BTT, - 0, - NULL, - NULL, - NULL), ==, 5); + glyph, + HB_DIRECTION_BTT, + 0, + NULL, + NULL, + NULL), ==, 5); g_assert_cmpint(hb_ot_math_get_glyph_assembly (hb_font, - glyph, - HB_DIRECTION_RTL, - 0, - NULL, - NULL, - NULL), ==, 0); + glyph, + HB_DIRECTION_RTL, + 0, + NULL, + NULL, + NULL), ==, 0); g_assert(hb_font_get_glyph_from_name (hb_font, "arrowright", -1, &glyph)); do { count = partsSize; hb_ot_math_get_glyph_assembly (hb_font, - glyph, - HB_DIRECTION_RTL, - offset, - &count, - parts, - NULL); + glyph, + HB_DIRECTION_RTL, + offset, + &count, + parts, + NULL); offset += count; } while (count == partsSize); g_assert_cmpint(offset, ==, 3); @@ -648,12 +648,12 @@ test_get_glyph_assembly (void) do { count = partsSize; hb_ot_math_get_glyph_assembly (hb_font, - glyph, - HB_DIRECTION_BTT, - offset, - &count, - parts, - NULL); + glyph, + HB_DIRECTION_BTT, + offset, + &count, + parts, + NULL); offset += count; } while (count == partsSize); g_assert_cmpint(offset, ==, 5); diff --git a/test/api/test-ot-metrics-tt-var.c b/test/api/test-ot-metrics-tt-var.c new file mode 100644 index 0000000000000000000000000000000000000000..9871c0815b0daf4aa7100776ef4fa01fe8d3f85b --- /dev/null +++ b/test/api/test-ot-metrics-tt-var.c @@ -0,0 +1,268 @@ +/* + * Copyright © 2019 Adobe Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include + +/* Unit tests for glyph advance widths and extents of TrueType variable fonts */ + +static void +test_extents_tt_var (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + hb_glyph_extents_t extents; + hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents); + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 10); + g_assert_cmpint (extents.y_bearing, ==, 846); + g_assert_cmpint (extents.width, ==, 500); + g_assert_cmpint (extents.height, ==, -846); + + float coords[1] = { 500.0f }; + hb_font_set_var_coords_design (font, coords, 1); + result = hb_font_get_glyph_extents (font, 2, &extents); + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 0); + g_assert_cmpint (extents.y_bearing, ==, 874); + g_assert_cmpint (extents.width, ==, 551); + g_assert_cmpint (extents.height, ==, -874); + + hb_font_destroy (font); +} + +static void +test_advance_tt_var_nohvar (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-nohvar-41,C1.ttf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + hb_position_t x, y; + hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_LTR, &x, &y); + + g_assert_cmpint (x, ==, 520); + g_assert_cmpint (y, ==, 0); + + hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y); + + g_assert_cmpint (x, ==, 0); + g_assert_cmpint (y, ==, -1000); + + float coords[1] = { 500.0f }; + hb_font_set_var_coords_design (font, coords, 1); + hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_LTR, &x, &y); + + g_assert_cmpint (x, ==, 551); + g_assert_cmpint (y, ==, 0); + + hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y); + + g_assert_cmpint (x, ==, 0); + g_assert_cmpint (y, ==, -1000); + + hb_font_destroy (font); +} + +static void +test_advance_tt_var_hvarvvar (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + hb_position_t x, y; + hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_LTR, &x, &y); + + g_assert_cmpint (x, ==, 508); + g_assert_cmpint (y, ==, 0); + + hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_TTB, &x, &y); + + g_assert_cmpint (x, ==, 0); + g_assert_cmpint (y, ==, -1000); + + float coords[1] = { 700.0f }; + hb_font_set_var_coords_design (font, coords, 1); + hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_LTR, &x, &y); + + g_assert_cmpint (x, ==, 531); + g_assert_cmpint (y, ==, 0); + + hb_font_get_glyph_advance_for_direction(font, 1, HB_DIRECTION_TTB, &x, &y); + + g_assert_cmpint (x, ==, 0); + g_assert_cmpint (y, ==, -1012); + + hb_font_destroy (font); +} + +static void +test_advance_tt_var_anchor (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.anchor.ttf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + hb_glyph_extents_t extents; + hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents); + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 56); + g_assert_cmpint (extents.y_bearing, ==, 672); + g_assert_cmpint (extents.width, ==, 556); + g_assert_cmpint (extents.height, ==, -684); + + float coords[1] = { 500.0f }; + hb_font_set_var_coords_design (font, coords, 1); + result = hb_font_get_glyph_extents (font, 2, &extents); + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 50); + g_assert_cmpint (extents.y_bearing, ==, 667); + g_assert_cmpint (extents.width, ==, 592); + g_assert_cmpint (extents.height, ==, -679); + + hb_font_destroy (font); +} + +static void +test_extents_tt_var_comp (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.modcomp.ttf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + hb_glyph_extents_t extents; + float coords[1] = { 800.0f }; + hb_font_set_var_coords_design (font, coords, 1); + + hb_bool_t result; + result = hb_font_get_glyph_extents (font, 2, &extents); /* Ccedilla, cedilla y-scaled by 0.8, with unscaled component offset */ + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 19); + g_assert_cmpint (extents.y_bearing, ==, 663); + g_assert_cmpint (extents.width, ==, 519); + g_assert_cmpint (extents.height, ==, -895); + + result = hb_font_get_glyph_extents (font, 3, &extents); /* Cacute, acute y-scaled by 0.8, with unscaled component offset (default) */ + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 19); + g_assert_cmpint (extents.y_bearing, ==, 909); + g_assert_cmpint (extents.width, ==, 519); + g_assert_cmpint (extents.height, ==, -921); + + result = hb_font_get_glyph_extents (font, 4, &extents); /* Ccaron, caron y-scaled by 0.8, with scaled component offset */ + g_assert (result); + + g_assert_cmpint (extents.x_bearing, ==, 19); + g_assert_cmpint (extents.y_bearing, ==, 866); + g_assert_cmpint (extents.width, ==, 519); + g_assert_cmpint (extents.height, ==, -878); + + hb_font_destroy (font); +} + +static void +test_advance_tt_var_comp_v (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.modcomp.ttf"); + g_assert (face); + hb_font_t *font = hb_font_create (face); + hb_face_destroy (face); + g_assert (font); + hb_ot_font_set_funcs (font); + + float coords[1] = { 800.0f }; + hb_font_set_var_coords_design (font, coords, 1); + + hb_position_t x, y; + hb_font_get_glyph_advance_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y); /* No VVAR; 'C' in composite Ccedilla determines metrics */ + + g_assert_cmpint (x, ==, 0); + g_assert_cmpint (y, ==, -991); + + hb_font_get_glyph_origin_for_direction(font, 2, HB_DIRECTION_TTB, &x, &y); + + g_assert_cmpint (x, ==, 292); + g_assert_cmpint (y, ==, 1013); + + hb_font_destroy (font); +} + +static void +test_advance_tt_var_gvar_infer (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/TestGVAREight.ttf"); + hb_font_t *font = hb_font_create (face); + hb_ot_font_set_funcs (font); + hb_face_destroy (face); + + int coords[6] = {100}; + hb_font_set_var_coords_normalized (font, coords, 6); + + hb_glyph_extents_t extents = {0}; + g_assert (hb_font_get_glyph_extents (font, 4, &extents)); + + hb_font_destroy (font); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_extents_tt_var); + hb_test_add (test_advance_tt_var_nohvar); + hb_test_add (test_advance_tt_var_hvarvvar); + hb_test_add (test_advance_tt_var_anchor); + hb_test_add (test_extents_tt_var_comp); + hb_test_add (test_advance_tt_var_comp_v); + hb_test_add (test_advance_tt_var_gvar_infer); + + return hb_test_run (); +} diff --git a/test/api/test-ot-name.c b/test/api/test-ot-name.c index c2ae4fd426960febe91b52bacc987cfc055f50a9..d688eb3fb0c03ac3486fc57da8c2fe2e856dac4b 100644 --- a/test/api/test-ot-name.c +++ b/test/api/test-ot-name.c @@ -68,6 +68,15 @@ test_ot_layout_feature_get_name_ids_and_characters (void) g_assert_cmpint (char_count, ==, 2); g_assert_cmpint (characters[0], ==, 10); g_assert_cmpint (characters[1], ==, 24030); + + char_count = 100; + characters[1] = 1234; + all_chars = hb_ot_layout_feature_get_characters (face, HB_OT_TAG_GSUB, feature_index, + 1, &char_count, characters); + g_assert_cmpint (all_chars, ==, 2); + g_assert_cmpint (char_count, ==, 1); + g_assert_cmpint (characters[0], ==, 24030); + g_assert_cmpint (characters[1], ==, 1234); } static void diff --git a/test/api/test-ot-tag.c b/test/api/test-ot-tag.c index d0334cd06d47304f58c5366f4fd7cad08c80dc4c..75131ab7adf65ebc7202c683dd56e5feeab690da 100644 --- a/test/api/test-ot-tag.c +++ b/test/api/test-ot-tag.c @@ -164,10 +164,16 @@ test_ot_tag_script_from_language (void) test_script_tags_from_language ("copt", "en", HB_SCRIPT_COPTIC); test_script_tags_from_language (NULL, "x-hbsc", HB_SCRIPT_INVALID); test_script_tags_from_language ("copt", "x-hbsc", HB_SCRIPT_COPTIC); + test_script_tags_from_language (NULL, "x-hbsc-", HB_SCRIPT_INVALID); + test_script_tags_from_language (NULL, "x-hbsc-1", HB_SCRIPT_INVALID); + test_script_tags_from_language (NULL, "x-hbsc-1a", HB_SCRIPT_INVALID); + test_script_tags_from_language (NULL, "x-hbsc-1a2b3c4x", HB_SCRIPT_INVALID); + test_script_tags_from_language ("2lon", "x-hbsc-326c6f6e67", HB_SCRIPT_INVALID); test_script_tags_from_language ("abc ", "x-hbscabc", HB_SCRIPT_INVALID); test_script_tags_from_language ("deva", "x-hbscdeva", HB_SCRIPT_INVALID); test_script_tags_from_language ("dev2", "x-hbscdev2", HB_SCRIPT_INVALID); test_script_tags_from_language ("dev3", "x-hbscdev3", HB_SCRIPT_INVALID); + test_script_tags_from_language ("dev3", "x-hbsc-64657633", HB_SCRIPT_INVALID); test_script_tags_from_language ("copt", "x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID); test_script_tags_from_language (NULL, "en-x-hbsc", HB_SCRIPT_INVALID); test_script_tags_from_language ("copt", "en-x-hbsc", HB_SCRIPT_COPTIC); @@ -175,6 +181,7 @@ test_ot_tag_script_from_language (void) test_script_tags_from_language ("deva", "en-x-hbscdeva", HB_SCRIPT_INVALID); test_script_tags_from_language ("dev2", "en-x-hbscdev2", HB_SCRIPT_INVALID); test_script_tags_from_language ("dev3", "en-x-hbscdev3", HB_SCRIPT_INVALID); + test_script_tags_from_language ("dev3", "en-x-hbsc-64657633", HB_SCRIPT_INVALID); test_script_tags_from_language ("copt", "en-x-hbotpap0-hbsccopt", HB_SCRIPT_INVALID); } @@ -266,12 +273,12 @@ test_tags_to_script_and_language (const char *script_tag_s, static void test_ot_tags_to_script_and_language (void) { - test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbscdflt"); + test_tags_to_script_and_language ("DFLT", "ENG", "", "en-x-hbsc-44464c54"); test_tags_to_script_and_language ("latn", "ENG", "Latn", "en"); - test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbscdeva"); - test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbscdev2"); + test_tags_to_script_and_language ("deva", "MAR", "Deva", "mr-x-hbsc-64657661"); + test_tags_to_script_and_language ("dev2", "MAR", "Deva", "mr-x-hbsc-64657632"); test_tags_to_script_and_language ("dev3", "MAR", "Deva", "mr"); - test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbotqtz0-hbscqaa"); + test_tags_to_script_and_language ("qaa", "QTZ0", "Qaaa", "x-hbot-51545a30-hbsc-71616120"); } static void @@ -291,13 +298,17 @@ test_ot_tag_language (void) test_language_two_way ("ENG", "en"); test_tag_from_language ("ENG", "en_US"); - test_language_two_way ("CJA", "cja"); /* Western Cham */ - test_language_two_way ("CJM", "cjm"); /* Eastern Cham */ + test_language_two_way ("CJA", "cja-x-hbot-434a4120"); /* Western Cham */ + test_language_two_way ("CJM", "cjm-x-hbot-434a4d20"); /* Eastern Cham */ + test_tag_from_language ("CJM", "cjm"); test_language_two_way ("EVN", "eve"); test_language_two_way ("HAL", "cfm"); /* BCP47 and current ISO639-3 code for Halam/Falam Chin */ test_tag_from_language ("HAL", "flm"); /* Retired ISO639-3 code for Halam/Falam Chin */ + test_language_two_way ("HYE0", "hy"); + test_language_two_way ("HYE", "hyw"); + test_tag_from_language ("QIN", "bgr"); /* Bawm Chin */ test_tag_from_language ("QIN", "cbl"); /* Bualkhaw Chin */ test_tag_from_language ("QIN", "cka"); /* Khumi Awa Chin */ @@ -324,6 +335,8 @@ test_ot_tag_language (void) test_language_two_way ("FAR", "fa"); test_tag_from_language ("FAR", "fa_IR"); + test_language_two_way ("MNK", "man"); /* Mandingo [macrolanguage] */ + test_language_two_way ("SWA", "aii"); /* Swadaya Aramaic */ test_language_two_way ("SYR", "syr"); /* Syriac [macrolanguage] */ @@ -336,10 +349,12 @@ test_ot_tag_language (void) test_tag_from_language ("ZHS", "zh"); /* Chinese */ test_tag_from_language ("ZHS", "zh-cn"); /* Chinese (China) */ test_tag_from_language ("ZHS", "zh-sg"); /* Chinese (Singapore) */ - test_tag_from_language ("ZHH", "zh-mo"); /* Chinese (Macao) */ - test_tag_from_language ("ZHH", "zh-hant-mo"); /* Chinese (Macao) */ + test_tag_from_language ("ZHTM", "zh-mo"); /* Chinese (Macao) */ + test_tag_from_language ("ZHTM", "zh-hant-mo"); /* Chinese (Macao) */ + test_tag_from_language ("ZHS", "zh-hans-mo"); /* Chinese (Simplified, Macao) */ test_language_two_way ("ZHH", "zh-HK"); /* Chinese (Hong Kong) */ test_tag_from_language ("ZHH", "zH-HanT-hK"); /* Chinese (Hong Kong) */ + test_tag_from_language ("ZHS", "zH-HanS-hK"); /* Chinese (Simplified, Hong Kong) */ test_tag_from_language ("ZHT", "zh-tw"); /* Chinese (Taiwan) */ test_language_two_way ("ZHS", "zh-Hans"); /* Chinese (Simplified) */ test_language_two_way ("ZHT", "zh-Hant"); /* Chinese (Traditional) */ @@ -351,16 +366,20 @@ test_ot_tag_language (void) test_tag_from_language ("ZHH", "yue-Hant"); test_tag_from_language ("ZHS", "yue-Hans"); - test_tag_from_language ("ZHS", "zh"); /* Chinese */ - test_tag_from_language ("ZHS", "zh-xx"); - - test_language_two_way ("ABC", "abc"); - test_language_two_way ("ABCD", "x-hbotabcd"); + test_language_two_way ("ABC", "abc-x-hbot-41424320"); + test_language_two_way ("ABCD", "x-hbot-41424344"); test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc-zxc"); test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbotabc"); test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbotabcd"); + test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbot-41424320-zxc"); + test_tag_from_language ("ABC", "asdf-asdf-wer-x-hbot-41424320"); + test_tag_from_language ("ABCD", "asdf-asdf-wer-x-hbot-41424344"); + test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot"); test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc"); + test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-zxc-414243"); + test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-414243"); + test_tag_from_language ("dflt", "asdf-asdf-wer-x-hbot-4142432"); test_tag_from_language ("dflt", "xy"); test_tag_from_language ("XYZ", "xyz"); /* Unknown ISO 639-3 */ @@ -426,12 +445,27 @@ test_ot_tag_language (void) test_language_two_way ("SYRN", "und-Syrn"); /* Test that x-hbot overrides the base language */ - test_tag_from_language ("ABC", "fa-x-hbotabc-zxc"); - test_tag_from_language ("ABC", "fa-ir-x-hbotabc-zxc"); - test_tag_from_language ("ABC", "zh-x-hbotabc-zxc"); - test_tag_from_language ("ABC", "zh-cn-x-hbotabc-zxc"); - test_tag_from_language ("ABC", "zh-xy-x-hbotabc-zxc"); - test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-zxc"); + test_tag_from_language ("ABC", "fa-x-hbotabc-hbot-41686121-zxc"); + test_tag_from_language ("ABC", "fa-ir-x-hbotabc-hbot-41686121-zxc"); + test_tag_from_language ("ABC", "zh-x-hbotabc-hbot-41686121-zxc"); + test_tag_from_language ("ABC", "zh-cn-x-hbotabc-hbot-41686121-zxc"); + test_tag_from_language ("ABC", "zh-xy-x-hbotabc-hbot-41686121-zxc"); + test_tag_from_language ("ABC", "xyz-xy-x-hbotabc-hbot-41686121-zxc"); + + test_tag_from_language ("Aha!", "fa-x-hbot-41686121-hbotabc-zxc"); + test_tag_from_language ("Aha!", "fa-ir-x-hbot-41686121-hbotabc-zxc"); + test_tag_from_language ("Aha!", "zh-x-hbot-41686121-hbotabc-zxc"); + test_tag_from_language ("Aha!", "zh-cn-x-hbot-41686121-hbotabc-zxc"); + test_tag_from_language ("Aha!", "zh-xy-x-hbot-41686121-hbotabc-zxc"); + test_tag_from_language ("Aha!", "xyz-xy-x-hbot-41686121-hbotabc-zxc"); + + /* Invalid x-hbot */ + test_tag_from_language ("dflt", "x-hbot"); + test_tag_from_language ("dflt", "x-hbot-"); + test_tag_from_language ("dflt", "x-hbot-1"); + test_tag_from_language ("dflt", "x-hbot-1a"); + test_tag_from_language ("dflt", "x-hbot-1a2b3c4x"); + test_tag_from_language ("2lon", "x-hbot-326c6f6e67"); /* Unnormalized BCP 47 tags */ test_tag_from_language ("ARA", "ar-aao"); @@ -449,6 +483,10 @@ test_ot_tag_language (void) test_tag_from_language ("ZHS", "zh-min-nan"); test_tag_from_language ("ZHS", "zh-xiang"); + /* BCP 47 tags that look similar to unrelated language system tags */ + test_tag_from_language ("SQI", "als"); + test_tag_from_language ("dflt", "far"); + /* A UN M.49 region code, not an extended language subtag */ test_tag_from_language ("ARA", "ar-001"); diff --git a/test/api/test-set.c b/test/api/test-set.c index aa2b388ea645585f7315785f6f119427274776ed..30a47674f665d8319f9e0da49feceda68e913f78 100644 --- a/test/api/test-set.c +++ b/test/api/test-set.c @@ -121,6 +121,11 @@ test_set_basic (void) hb_set_del (s, 800); g_assert (!hb_set_has (s, 800)); + g_assert_cmpint (hb_set_get_max (s), ==, 799); + + hb_set_del_range (s, 0, 799); + g_assert_cmpint (hb_set_get_max (s), ==, HB_SET_VALUE_INVALID); + hb_set_destroy (s); } @@ -135,6 +140,81 @@ test_set_basic (void) // printf ("}\n"); // } +static void test_set_intersect_empty (void) +{ + hb_set_t* a = hb_set_create (); + hb_set_add (a, 3585); + hb_set_add (a, 21333); + hb_set_add (a, 24405); + + hb_set_t* b = hb_set_create(); + hb_set_add (b, 21483); + hb_set_add (b, 24064); + + hb_set_intersect (a, b); + g_assert (hb_set_is_empty (a)); + + hb_set_destroy (a); + hb_set_destroy (b); + + + a = hb_set_create (); + hb_set_add (a, 16777216); + + b = hb_set_create(); + hb_set_add (b, 0); + + hb_set_intersect (a, b); + g_assert (hb_set_is_empty (a)); + + hb_set_destroy (a); + hb_set_destroy (b); +} + +static void test_set_intersect_page_reduction (void) +{ + hb_set_t* a = hb_set_create (); + hb_set_add (a, 3585); + hb_set_add (a, 21333); + hb_set_add (a, 24405); + + hb_set_t* b = hb_set_create(); + hb_set_add (b, 3585); + hb_set_add (b, 24405); + + hb_set_intersect(a, b); + g_assert (hb_set_is_equal (a, b)); + + hb_set_destroy (a); + hb_set_destroy (b); +} + +static void test_set_union (void) +{ + hb_set_t* a = hb_set_create(); + hb_set_add (a, 3585); + hb_set_add (a, 21333); + hb_set_add (a, 24405); + + hb_set_t* b = hb_set_create(); + hb_set_add (b, 21483); + hb_set_add (b, 24064); + + hb_set_t* u = hb_set_create (); + hb_set_add (u, 3585); + hb_set_add (u, 21333); + hb_set_add (u, 21483); + hb_set_add (u, 24064); + hb_set_add (u, 24405); + + hb_set_union(b, a); + g_assert (hb_set_is_equal (u, b)); + + hb_set_destroy (a); + hb_set_destroy (b); + hb_set_destroy (u); +} + static void test_set_algebra (void) { @@ -395,6 +475,53 @@ test_set_empty (void) hb_set_destroy (b); } +static void +test_set_delrange (void) +{ + const unsigned P = 512; /* Page size. */ + struct { unsigned b, e; } ranges[] = { + { 35, P-15 }, /* From page middle thru middle. */ + { P, P+100 }, /* From page start thru middle. */ + { P+300, P*2-1 }, /* From page middle thru end. */ + { P*3, P*4+100 }, /* From page start thru next page middle. */ + { P*4+300, P*6-1 }, /* From page middle thru next page end. */ + { P*6+200,P*8+100 }, /* From page middle covering one page thru page middle. */ + { P*9, P*10+105 }, /* From page start covering one page thru page middle. */ + { P*10+305, P*12-1 }, /* From page middle covering one page thru page end. */ + { P*13, P*15-1 }, /* From page start covering two pages thru page end. */ + { P*15+100, P*18+100 } /* From page middle covering two pages thru page middle. */ + }; + unsigned n = sizeof (ranges) / sizeof(ranges[0]); + + hb_set_t *s = hb_set_create (); + + test_empty (s); + for (unsigned int g = 0; g < ranges[n - 1].e + P; g += 2) + hb_set_add (s, g); + + hb_set_add (s, P*2-1); + hb_set_add (s, P*6-1); + hb_set_add (s, P*12-1); + hb_set_add (s, P*15-1); + + for (unsigned i = 0; i < n; i++) + hb_set_del_range (s, ranges[i].b, ranges[i].e); + + hb_set_del_range (s, P*13+5, P*15-10); /* Deletion from deleted pages. */ + + for (unsigned i = 0; i < n; i++) + { + unsigned b = ranges[i].b; + unsigned e = ranges[i].e; + g_assert (hb_set_has (s, (b-2)&~1)); + while (b <= e) + g_assert (!hb_set_has (s, b++)); + g_assert (hb_set_has (s, (e+2)&~1)); + } + + hb_set_destroy (s); +} + int main (int argc, char **argv) { @@ -404,6 +531,11 @@ main (int argc, char **argv) hb_test_add (test_set_algebra); hb_test_add (test_set_iter); hb_test_add (test_set_empty); + hb_test_add (test_set_delrange); + + hb_test_add (test_set_intersect_empty); + hb_test_add (test_set_intersect_page_reduction); + hb_test_add (test_set_union); return hb_test_run(); } diff --git a/test/api/test-style.c b/test/api/test-style.c new file mode 100644 index 0000000000000000000000000000000000000000..5e72824916303383c5e13a8e7e1f61b0ffaa7675 --- /dev/null +++ b/test/api/test-style.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifdef HB_EXPERIMENTAL_API +#include "hb-test.h" + +#include + +/* Unit tests for hb-style.h */ + +#define assert_cmpfloat(n1, n2) g_assert_cmpint ((int) (n1 * 100.f), ==, (int) (n2 * 100.f)) + +#define HB_STYLE_TAG_ITALIC HB_TAG ('i','t','a','l') +#define HB_STYLE_TAG_OPTICAL_SIZE HB_TAG ('o','p','s','z') +#define HB_STYLE_TAG_SLANT HB_TAG ('s','l','n','t') +#define HB_STYLE_TAG_WIDTH HB_TAG ('w','d','t','h') +#define HB_STYLE_TAG_WEIGHT HB_TAG ('w','g','h','t') + +static void +test_empty_face (void) +{ + hb_font_t *empty = hb_font_get_empty (); + + assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (empty, HB_STYLE_TAG_WEIGHT), 400); +} + +static void +test_regular_face (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf"); + hb_font_t *font = hb_font_create (face); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 400); + + hb_font_destroy (font); + hb_face_destroy (face); +} + +static void +test_face_user_setting (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype_vsindex.otf"); + hb_font_t *font = hb_font_create (face); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 389.34f); /* its default weight */ + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 0); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 200); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 1); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 300); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 2); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 400); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 3); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT),600); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 4); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 700); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 5); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 900); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 0); + + hb_font_set_var_named_instance (font, 6); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 900); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 50); + + hb_font_set_var_named_instance (font, 7); + + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_ITALIC), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_OPTICAL_SIZE), 12); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_SLANT), 0); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WIDTH), 100); + assert_cmpfloat (hb_style_get_value (font, HB_STYLE_TAG_WEIGHT), 900); + assert_cmpfloat (hb_style_get_value (font, (hb_style_tag_t) HB_TAG ('C','N','T','R')), 100); + + hb_font_destroy (font); + hb_face_destroy (face); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_empty_face); + hb_test_add (test_regular_face); + hb_test_add (test_face_user_setting); + + return hb_test_run (); +} +#else +int main () {} +#endif diff --git a/test/api/test-subset-cbdt.c b/test/api/test-subset-cbdt.c new file mode 100644 index 0000000000000000000000000000000000000000..dcc06e191347eefc5e14216a253d1471c818f8a6 --- /dev/null +++ b/test/api/test-subset-cbdt.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for CBDT/CBLC subsetting */ + +static void +test_subset_cbdt_noop (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x38); + hb_set_add (codepoints, 0x39); + hb_set_add (codepoints, 0xAE); + hb_set_add (codepoints, 0x2049); + hb_set_add (codepoints, 0x20E3); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face, face_subset, HB_TAG ('C','B','L','C')); + hb_subset_test_check (face, face_subset, HB_TAG ('C','B','D','T')); + + hb_face_destroy (face_subset); + hb_face_destroy (face); +} + +static void +test_subset_cbdt_keep_one (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.default.39.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x39); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C')); + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +static void +test_subset_cbdt_keep_one_last_subtable (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.default.2049.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x2049); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C')); + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +static void +test_subset_cbdt_keep_multiple_subtables (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.multiple_size_tables.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x38); + hb_set_add (codepoints, 0xAE); + hb_set_add (codepoints, 0x2049); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C')); + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +static void +test_subset_cbdt_index_format_3 (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.index_format3.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x38); + hb_set_add (codepoints, 0xAE); + hb_set_add (codepoints, 0x2049); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','L','C')); + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','B','D','T')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +// TODO: add support/tests for index formats 2,4,5 (image formats are treated as +// opaque blobs when subsetting so don't need to be tested separately). +// TODO: add a test that keeps no codepoints. + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_cbdt_noop); + hb_test_add (test_subset_cbdt_keep_one); + hb_test_add (test_subset_cbdt_keep_one_last_subtable); + // The following use manually crafted expectation files as they are not + // binary compatible with FontTools. + hb_test_add (test_subset_cbdt_keep_multiple_subtables); + // Can use FontTools after https://github.com/fonttools/fonttools/issues/1817 + // is resolved. + hb_test_add (test_subset_cbdt_index_format_3); + + return hb_test_run(); +} diff --git a/test/api/test-subset-cmap.c b/test/api/test-subset-cmap.c index 74e91ca3adf99cb33cffef35c6798b822c1207b8..e16400ea558b6daeb54b51cd8b7837f74892fb75 100644 --- a/test/api/test-subset-cmap.c +++ b/test/api/test-subset-cmap.c @@ -90,6 +90,91 @@ test_subset_cmap_noop (void) hb_face_destroy (face_abc); } +static void +test_subset_cmap4_no_exceeding_maximum_codepoint (void) +{ + hb_face_t *face_origin = hb_test_open_font_file ("fonts/Mplus1p-Regular.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/Mplus1p-Regular-cmap4-testing.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x20); + hb_set_add (codepoints, 0x21); + hb_set_add (codepoints, 0x1d542); + hb_set_add (codepoints, 0x201a2); + + face_subset = hb_subset_test_create_subset (face_origin, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('c','m','a','p')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face_origin); +} + +static void +test_subset_cmap_empty_tables (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf"); + hb_face_t *face_empty = hb_test_open_font_file ("fonts/Roboto-Regular.empty.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 100); + hb_set_add (codepoints, 101); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_empty, face_abc_subset, HB_TAG ('c','m','a','p')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_empty); +} + +static void +test_subset_cmap_noto_color_emoji_noop (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.cmap.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x38); + hb_set_add (codepoints, 0x39); + hb_set_add (codepoints, 0xAE); + hb_set_add (codepoints, 0x2049); + hb_set_add (codepoints, 0x20E3); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face, face_subset, HB_TAG ('c','m','a','p')); + + hb_face_destroy (face_subset); + hb_face_destroy (face); +} + +static void +test_subset_cmap_noto_color_emoji_non_consecutive_glyphs (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/NotoColorEmoji.cmap.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/NotoColorEmoji.cmap.38,AE,2049.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x38); + hb_set_add (codepoints, 0xAE); + hb_set_add (codepoints, 0x2049); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('c','m','a','p')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + // TODO(rsheeter) test cmap to no codepoints int @@ -100,6 +185,10 @@ main (int argc, char **argv) hb_test_add (test_subset_cmap); hb_test_add (test_subset_cmap_noop); hb_test_add (test_subset_cmap_non_consecutive_glyphs); + hb_test_add (test_subset_cmap4_no_exceeding_maximum_codepoint); + hb_test_add (test_subset_cmap_empty_tables); + hb_test_add (test_subset_cmap_noto_color_emoji_noop); + hb_test_add (test_subset_cmap_noto_color_emoji_non_consecutive_glyphs); return hb_test_run(); } diff --git a/test/api/test-subset-colr.c b/test/api/test-subset-colr.c new file mode 100644 index 0000000000000000000000000000000000000000..403509265fee0a2a8106765851586afe93d63da7 --- /dev/null +++ b/test/api/test-subset-colr.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for COLR subsetting */ + +static void +test_subset_colr_noop (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, '2'); + hb_set_add (codepoints, 0x3297); + hb_set_add (codepoints, 0x3299); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face, face_subset, HB_TAG ('C','O','L','R')); + + hb_face_destroy (face_subset); + hb_face_destroy (face); +} + +static void +test_subset_colr_keep_one_colr_glyph (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.3297.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, 0x3297); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +static void +test_subset_colr_keep_mixed_glyph (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.32,3299.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, '2'); + hb_set_add (codepoints, 0x3299); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +static void +test_subset_colr_keep_no_colr_glyph (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.ttf"); + hb_face_t *face_expected = hb_test_open_font_file ("fonts/TwemojiMozilla.subset.default.32.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_subset; + hb_set_add (codepoints, '2'); + face_subset = hb_subset_test_create_subset (face, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_expected, face_subset, HB_TAG ('C','O','L','R')); + + hb_face_destroy (face_subset); + hb_face_destroy (face_expected); + hb_face_destroy (face); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_colr_noop); + hb_test_add (test_subset_colr_keep_one_colr_glyph); + hb_test_add (test_subset_colr_keep_mixed_glyph); + hb_test_add (test_subset_colr_keep_no_colr_glyph); + + return hb_test_run(); +} diff --git a/test/api/test-subset-gpos.c b/test/api/test-subset-gpos.c new file mode 100644 index 0000000000000000000000000000000000000000..e1b3d0091f0ae33f3134bc89dc9e70137a42559b --- /dev/null +++ b/test/api/test-subset-gpos.c @@ -0,0 +1,91 @@ +/* + * Copyright © 2020 Adobe Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for GPOS subsetting */ + +static void +test_subset_gpos_lookup_subtable (void) +{ + hb_face_t *face_pwa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-.aw.ttf"); + hb_face_t *face_wa = hb_test_open_font_file ("fonts/Roboto-Regular-gpos-aw.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_pwa_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'w'); + + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + + hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'P', 'O', 'S')); + + face_pwa_subset = hb_subset_test_create_subset (face_pwa, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_wa, face_pwa_subset, HB_TAG ('G','P','O','S')); + + hb_face_destroy (face_pwa_subset); + hb_face_destroy (face_pwa); + hb_face_destroy (face_wa); +} + +static void +test_subset_gpos_pairpos1_vf (void) +{ + hb_face_t *face_wav = hb_test_open_font_file ("fonts/AdobeVFPrototype.WAV.gpos.otf"); + hb_face_t *face_wa = hb_test_open_font_file ("fonts/AdobeVFPrototype.WA.gpos.otf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_wav_subset; + hb_set_add (codepoints, 'W'); + hb_set_add (codepoints, 'A'); + + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + + hb_set_del (hb_subset_input_drop_tables_set (input), HB_TAG ('G', 'P', 'O', 'S')); + + face_wav_subset = hb_subset_test_create_subset (face_wav, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_wa, face_wav_subset, HB_TAG ('G','P','O','S')); + + hb_face_destroy (face_wav_subset); + hb_face_destroy (face_wav); + hb_face_destroy (face_wa); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_gpos_lookup_subtable); + hb_test_add (test_subset_gpos_pairpos1_vf); + + return hb_test_run (); +} diff --git a/test/api/test-subset-gvar.c b/test/api/test-subset-gvar.c new file mode 100644 index 0000000000000000000000000000000000000000..991be8f83c6311f14abf5632a488c49ca59be681 --- /dev/null +++ b/test/api/test-subset-gvar.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2019 Adobe Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for gvar subsetting */ + +static void +test_subset_gvar_noop (void) +{ + hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansVariable-Roman.abc.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','v','a','r')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); +} + +static void +test_subset_gvar (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','v','a','r')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +static void +test_subset_gvar_retaingids (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.retaingids.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + hb_subset_input_set_retain_gids (input, true); + face_abc_subset = hb_subset_test_create_subset (face_abc, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','v','a','r')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_gvar_noop); + hb_test_add (test_subset_gvar); + hb_test_add (test_subset_gvar_retaingids); + + return hb_test_run (); +} diff --git a/test/api/test-subset-hvar.c b/test/api/test-subset-hvar.c new file mode 100644 index 0000000000000000000000000000000000000000..2a6c2a9772090d0b3471c241bbc8635d88b2a0d2 --- /dev/null +++ b/test/api/test-subset-hvar.c @@ -0,0 +1,189 @@ +/* + * Copyright © 2019 Adobe Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for HVAR subsetting */ + +static void +test_subset_map_HVAR_noop (void) +{ + hb_face_t *face_abc = hb_test_open_font_file("fonts/AdobeVFPrototype.abc.otf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); +} + +static void +test_subset_map_HVAR (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.otf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +static void +test_subset_map_HVAR_retaingids (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/AdobeVFPrototype.ac.retaingids.otf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + hb_subset_input_set_retain_gids (input, true); + face_abc_subset = hb_subset_test_create_subset (face_abc, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +static void +test_subset_map_modHVAR (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-modHVAR.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman-modHVAR.ac.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +static void +test_subset_identity_HVAR_noop (void) +{ + hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSansVariable-Roman.abc.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); +} + +static void +test_subset_identity_HVAR (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +static void +test_subset_identity_HVAR_retaingids (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.ac.retaingids.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + hb_subset_input_set_retain_gids (input, true); + face_abc_subset = hb_subset_test_create_subset (face_abc, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('H','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_map_HVAR_noop); + hb_test_add (test_subset_map_HVAR); + hb_test_add (test_subset_map_HVAR_retaingids); + hb_test_add (test_subset_map_modHVAR); + hb_test_add (test_subset_identity_HVAR_noop); + hb_test_add (test_subset_identity_HVAR); + hb_test_add (test_subset_identity_HVAR_retaingids); + + return hb_test_run (); +} diff --git a/test/api/test-subset-sbix.c b/test/api/test-subset-sbix.c new file mode 100644 index 0000000000000000000000000000000000000000..16ac66632e42bba855c672f565313a145d8e4c52 --- /dev/null +++ b/test/api/test-subset-sbix.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2020 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for sbix subsetting */ + +static void +test_subset_sbix_noop (void) +{ + hb_face_t *face_XY = hb_test_open_font_file ("fonts/sbix.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_XY_subset; + hb_set_add (codepoints, 88); + hb_set_add (codepoints, 89); + face_XY_subset = hb_subset_test_create_subset (face_XY, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_XY, face_XY_subset, HB_TAG ('s','b','i','x')); + + hb_face_destroy (face_XY_subset); + hb_face_destroy (face_XY); +} + +static void +test_subset_sbix_keep_one (void) +{ + hb_face_t *face_XY = hb_test_open_font_file ("fonts/sbix.ttf"); + hb_face_t *face_X = hb_test_open_font_file ("fonts/sbix_X.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_X_subset; + hb_set_add (codepoints, 88); + face_X_subset = hb_subset_test_create_subset (face_XY, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_X, face_X_subset, HB_TAG ('s','b','i','x')); + + hb_face_destroy (face_X_subset); + hb_face_destroy (face_XY); + hb_face_destroy (face_X); +} + +// TODO: add a test that doesn't use contiguous codepoints. +// TODO: add a test that keeps no codepoints. + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_sbix_noop); + hb_test_add (test_subset_sbix_keep_one); + + return hb_test_run(); +} diff --git a/test/api/test-subset-vvar.c b/test/api/test-subset-vvar.c new file mode 100644 index 0000000000000000000000000000000000000000..2b829a33f42947fbac88244627e07df96e13a202 --- /dev/null +++ b/test/api/test-subset-vvar.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2019 Adobe Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-test.h" +#include "hb-subset-test.h" + +/* Unit tests for VVAR subsetting */ + +static void +test_subset_VVAR_noop (void) +{ + hb_face_t *face_abc = hb_test_open_font_file("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'b'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('V','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); +} + +static void +test_subset_VVAR (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.ac.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('V','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +static void +test_subset_VVAR_retaingids (void) +{ + hb_face_t *face_abc = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf"); + hb_face_t *face_ac = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.ac.retaingids.ttf"); + + hb_set_t *codepoints = hb_set_create (); + hb_face_t *face_abc_subset; + hb_set_add (codepoints, 'a'); + hb_set_add (codepoints, 'c'); + hb_subset_input_t *input = hb_subset_test_create_input (codepoints); + hb_subset_input_set_retain_gids (input, true); + face_abc_subset = hb_subset_test_create_subset (face_abc, input); + hb_set_destroy (codepoints); + + hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('V','V','A','R')); + + hb_face_destroy (face_abc_subset); + hb_face_destroy (face_abc); + hb_face_destroy (face_ac); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + + hb_test_add (test_subset_VVAR_noop); + hb_test_add (test_subset_VVAR); + hb_test_add (test_subset_VVAR_retaingids); + + return hb_test_run (); +} diff --git a/test/api/test-unicode.c b/test/api/test-unicode.c index 4376fd05fb4ea49669d7776617d5c92d7eed18ce..6037408aaa91ee31a316b5bcac8a7696377d0321 100644 --- a/test/api/test-unicode.c +++ b/test/api/test-unicode.c @@ -62,8 +62,8 @@ static void free_up (void *p) static hb_script_t simple_get_script (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t codepoint, - void *user_data) + hb_codepoint_t codepoint, + void *user_data) { data_t *data = (data_t *) user_data; @@ -79,8 +79,8 @@ simple_get_script (hb_unicode_funcs_t *ufuncs, static hb_script_t a_is_for_arabic_get_script (hb_unicode_funcs_t *ufuncs, - hb_codepoint_t codepoint, - void *user_data) + hb_codepoint_t codepoint, + void *user_data) { data_t *data = (data_t *) user_data; @@ -178,6 +178,9 @@ static const test_pair_t combining_class_tests_more[] = /* Unicode-12.0 character additions */ { 0x0EBA, 9 }, + /* Unicode-13.0 character additions */ + { 0x1ABF, 220 }, + { 0x111111, 0 } }; @@ -255,6 +258,9 @@ static const test_pair_t general_category_tests_more[] = /* Unicode-12.1 character additions */ { 0x32FF, HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL }, + /* Unicode-13.0 character additions */ + { 0x08BE, HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER }, + { 0x111111, HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED } }; @@ -499,6 +505,12 @@ static const test_pair_t script_tests_more[] = /* Unicode-12.1 additions */ { 0x32FF, HB_SCRIPT_COMMON }, + /* Unicode-13.0 additions */ + { 0x10E80, HB_SCRIPT_YEZIDI }, + { 0x10FB0, HB_SCRIPT_CHORASMIAN }, + { 0x11900, HB_SCRIPT_DIVES_AKURU }, + { 0x18B00, HB_SCRIPT_KHITAN_SMALL_SCRIPT }, + { 0x111111, HB_SCRIPT_UNKNOWN } }; @@ -537,6 +549,8 @@ typedef struct { G_N_ELEMENTS (name##_tests_more), \ DEFAULT \ } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" static const property_t properties[] = { PROPERTY (combining_class, 0), @@ -544,6 +558,7 @@ static const property_t properties[] = PROPERTY (mirroring, RETURNS_UNICODE_ITSELF), PROPERTY (script, (unsigned int) HB_SCRIPT_UNKNOWN) }; +#pragma GCC diagnostic pop #undef PROPERTY static void @@ -751,7 +766,7 @@ test_unicode_subclassing_nil (data_fixture_t *f, gconstpointer user_data HB_UNUS hb_unicode_funcs_destroy (uf); hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script, - &f->data[1], free_up); + &f->data[1], free_up); g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC); g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_UNKNOWN); @@ -770,7 +785,7 @@ test_unicode_subclassing_default (data_fixture_t *f, gconstpointer user_data HB_ aa = hb_unicode_funcs_create (uf); hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script, - &f->data[1], free_up); + &f->data[1], free_up); g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC); g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN); @@ -788,7 +803,7 @@ test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data HB_UNU uf = hb_unicode_funcs_create (NULL); hb_unicode_funcs_set_script_func (uf, simple_get_script, - &f->data[0], free_up); + &f->data[0], free_up); aa = hb_unicode_funcs_create (uf); @@ -798,7 +813,7 @@ test_unicode_subclassing_deep (data_fixture_t *f, gconstpointer user_data HB_UNU g_assert (!f->data[0].freed); hb_unicode_funcs_set_script_func (aa, a_is_for_arabic_get_script, - &f->data[1], free_up); + &f->data[1], free_up); g_assert_cmphex (hb_unicode_script (aa, 'a'), ==, HB_SCRIPT_ARABIC); g_assert_cmphex (hb_unicode_script (aa, 'b'), ==, HB_SCRIPT_LATIN); diff --git a/test/api/test-var-coords.c b/test/api/test-var-coords.c new file mode 100644 index 0000000000000000000000000000000000000000..aa152e3ed6d44264f59b5c456b763078e73cde2c --- /dev/null +++ b/test/api/test-var-coords.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb-test.h" + +#include + +/* Unit tests for hb_font_[gs]et_var_coords_ */ + +static void +test_get_var_coords (void) +{ +#ifdef HB_EXPERIMENTAL_API +#ifndef G_APPROX_VALUE +#define G_APPROX_VALUE(a, b, epsilon) \ + (((a) > (b) ? (a) - (b) : (b) - (a)) < (epsilon)) +#endif + +#define EPSILON 0.05f + + hb_face_t *face = hb_test_open_font_file ("fonts/TestCFF2VF.otf"); + hb_font_t *font = hb_font_create (face); + + /* Normalized coords as input */ + int normalized_coords[] = {100, 0}; + hb_font_set_var_coords_normalized (font, normalized_coords, 2); + g_assert_cmpint ((int) hb_font_get_var_coords_design (font, NULL)[0], ==, 403); + g_assert_cmpint ((int) hb_font_get_var_coords_normalized (font, NULL)[0], ==, 100); + + /* Design coords as input */ + float design_coords[] = {206.f, 0}; + hb_font_set_var_coords_design (font, design_coords, 2); + g_assert_cmpint ((int) hb_font_get_var_coords_normalized (font, NULL)[0], ==, -16117); + g_assert_cmpint ((int) hb_font_get_var_coords_design (font, NULL)[0], ==, 206); + + for (float weight = 200; weight < 901; ++weight) + { + int normalized; + hb_ot_var_normalize_coords (face, 1, &weight, &normalized); + hb_font_set_var_coords_normalized (font, &normalized, 1); + float converted_back = hb_font_get_var_coords_design (font, NULL)[0]; + // fprintf (stderr, "%f: %d => %f\n", weight, normalized, converted_back); + g_assert_true (G_APPROX_VALUE (converted_back, weight, EPSILON)); + } + + hb_font_destroy (font); + hb_face_destroy (face); +#endif +} + +static void +test_get_var_get_axis_infos (void) +{ + hb_face_t *face = hb_test_open_font_file ("fonts/Estedad-VF.ttf"); + + g_assert_cmpint (hb_ot_var_get_axis_count (face), ==, 2); + + hb_ot_var_axis_info_t info; + unsigned c = 1; + + g_assert_cmpint (hb_ot_var_get_axis_infos (face, 0, &c, &info), ==, 2); + g_assert (info.tag == HB_TAG ('w','g','h','t')); + g_assert_cmpint (c, ==, 1); + + hb_ot_var_get_axis_infos (face, 1, &c, &info); + g_assert (info.tag == HB_TAG ('w','d','t','h')); + g_assert_cmpint (c, ==, 1); + + hb_ot_var_get_axis_infos (face, 2, &c, &info); + g_assert_cmpint (c, ==, 0); + + hb_face_destroy (face); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + hb_test_add (test_get_var_coords); + hb_test_add (test_get_var_get_axis_infos); + return hb_test_run (); +} diff --git a/test/fuzzing/CMakeLists.txt b/test/fuzzing/CMakeLists.txt deleted file mode 100644 index 577d13ceaa0312bd05bdaeab9184fec92385b6d4..0000000000000000000000000000000000000000 --- a/test/fuzzing/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -if (HB_CHECK) - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.am" MAKEFILEAM) - extract_make_variable (hb_shape_fuzzer_SOURCES ${MAKEFILEAM}) - extract_make_variable (hb_subset_fuzzer_SOURCES ${MAKEFILEAM}) - - # TODO: enable these two - #extract_make_variable (FUZZING_CPPFLAGS ${MAKEFILEAM}) # extracting regex fail - #add_executable (hb-shape-fuzzer # it should be run only after ragel execution - # ${project_sources} ${project_extra_sources} ${project_headers} - # ${hb_shape_fuzzer_SOURCES}) - - add_executable (hb-shape-fuzzer ${hb_shape_fuzzer_SOURCES}) - target_link_libraries (hb-shape-fuzzer harfbuzz) - - add_executable (hb-subset-fuzzer ${hb_subset_fuzzer_SOURCES}) - target_link_libraries (hb-subset-fuzzer harfbuzz-subset) - - target_compile_definitions(hb-shape-fuzzer PUBLIC ${FUZZING_CPPFLAGS}) - target_compile_definitions(hb-subset-fuzzer PUBLIC ${FUZZING_CPPFLAGS}) - - add_test (NAME hb-shape-fuzzer - COMMAND "${PYTHON_EXECUTABLE}" run-shape-fuzzer-tests.py $ - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - add_test (NAME hb-subset-fuzzer - COMMAND "${PYTHON_EXECUTABLE}" run-subset-fuzzer-tests.py $ - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -endif () diff --git a/test/fuzzing/Makefile.am b/test/fuzzing/Makefile.am index 5bd2d7e6d8766d061b58fe4176d0d512c4e54b5d..2e2b2c9ada683b7fb9d1018e98f1d449b777d7ab 100644 --- a/test/fuzzing/Makefile.am +++ b/test/fuzzing/Makefile.am @@ -19,13 +19,16 @@ EXTRA_DIST += \ README \ run-shape-fuzzer-tests.py \ run-subset-fuzzer-tests.py \ - CMakeLists.txt \ + run-draw-fuzzer-tests.py \ + meson.build \ fonts \ $(NULL) check_PROGRAMS = \ hb-shape-fuzzer \ hb-subset-fuzzer \ + hb-set-fuzzer \ + hb-draw-fuzzer \ $(NULL) AM_CPPFLAGS = \ @@ -54,9 +57,29 @@ hb_subset_fuzzer_LDADD = \ hb_subset_fuzzer_CPPFLAGS = $(AM_CPPFLAGS) hb_subset_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz-subset.la +hb_set_fuzzer_SOURCES = \ + hb-fuzzer.hh \ + hb-set-fuzzer.cc \ + main.cc \ + $(NULL) +hb_set_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la +hb_set_fuzzer_CPPFLAGS = $(AM_CPPFLAGS) +hb_set_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la + +hb_draw_fuzzer_SOURCES = \ + hb-fuzzer.hh \ + hb-draw-fuzzer.cc \ + main.cc \ + $(NULL) +hb_draw_fuzzer_LDADD = $(top_builddir)/src/libharfbuzz.la +hb_draw_fuzzer_CPPFLAGS = $(AM_CPPFLAGS) +hb_draw_fuzzer_DEPENDENCIES = $(top_builddir)/src/libharfbuzz.la + + check: EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-shape-fuzzer-tests.py EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-subset-fuzzer-tests.py + EXEEXT="$(EXEEXT)" srcdir="$(srcdir)" builddir="$(builddir)" LIBTOOL="$(LIBTOOL)" $(srcdir)/run-draw-fuzzer-tests.py check-valgrind: $(AM_V_at)RUN_VALGRIND=1 $(MAKE) $(AM_MAKEFLGS) check diff --git a/test/fuzzing/fonts/1746cad6bc3fb2b355db50a5af37c9b58d9ad376 b/test/fuzzing/fonts/1746cad6bc3fb2b355db50a5af37c9b58d9ad376 new file mode 100644 index 0000000000000000000000000000000000000000..8e58f0d671f4136665b0e2ebf220fd025bbe1b71 Binary files /dev/null and b/test/fuzzing/fonts/1746cad6bc3fb2b355db50a5af37c9b58d9ad376 differ diff --git a/test/fuzzing/fonts/NotoColorEmoji.subset.index_format3.ttf b/test/fuzzing/fonts/NotoColorEmoji.subset.index_format3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..df1ff9bb3c3a2e9dc64df51c171067b2ae933ae2 Binary files /dev/null and b/test/fuzzing/fonts/NotoColorEmoji.subset.index_format3.ttf differ diff --git a/test/fuzzing/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf b/test/fuzzing/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cdccdeda2b4458028ff7c7301584d11f79512a2f Binary files /dev/null and b/test/fuzzing/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf differ diff --git a/test/fuzzing/fonts/NotoColorEmoji.subset.ttf b/test/fuzzing/fonts/NotoColorEmoji.subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14a544ad5fbf4d31ef8339d7393d2aa071d41bac Binary files /dev/null and b/test/fuzzing/fonts/NotoColorEmoji.subset.ttf differ diff --git a/test/fuzzing/fonts/TwemojiMozilla.subset.ttf b/test/fuzzing/fonts/TwemojiMozilla.subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..357dda3b96d86c569e94f579d14a2c87bc4cfbce Binary files /dev/null and b/test/fuzzing/fonts/TwemojiMozilla.subset.ttf differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-4822416500195328 b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-4822416500195328 new file mode 100644 index 0000000000000000000000000000000000000000..d13a8389ce50963fdf4a74e6e316fb9b22037251 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-4822416500195328 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-5598263003840512 b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-5598263003840512 new file mode 100644 index 0000000000000000000000000000000000000000..2b3143d5de7d7ea883cc372ca85685fd20f7a3d5 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-5598263003840512 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-6327734241591296 b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-6327734241591296 new file mode 100644 index 0000000000000000000000000000000000000000..f476997e20e5dfdeef33bf533fb2e027270a71b4 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-harfbuzz_fuzzer-6327734241591296 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5072750494875648 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5072750494875648 new file mode 100644 index 0000000000000000000000000000000000000000..29ea9129909b730ef27be6ead04110f7d078ff11 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5072750494875648 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5638729035677696 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5638729035677696 new file mode 100644 index 0000000000000000000000000000000000000000..0aaed32f9e28b33ef7ea7cf6b453d6302ff778eb Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5638729035677696 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5643643755429888 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5643643755429888 new file mode 100644 index 0000000000000000000000000000000000000000..d18e3b5565f927bd32fbb69bc5f867e32da6d2ed Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5643643755429888 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5644258942386176 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5644258942386176 new file mode 100644 index 0000000000000000000000000000000000000000..5e0fe470ab3b060e9c47ac9ab3a44798e7cdb88f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5644258942386176 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5657878543728640 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5657878543728640 new file mode 100644 index 0000000000000000000000000000000000000000..897e4bce6b503b7c813902cd629dce4c5dfda79a Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5657878543728640 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5680362806575104 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5680362806575104 new file mode 100644 index 0000000000000000000000000000000000000000..51828e8bf1b56c8185695687a75bc16f9551b349 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5680362806575104 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5689920685867008 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5689920685867008 new file mode 100644 index 0000000000000000000000000000000000000000..4121e5abb73fc0ebaabc489345f37c7df09c1e4d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-shape-fuzzer-5689920685867008 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5641053680173056 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5641053680173056 new file mode 100644 index 0000000000000000000000000000000000000000..760167fc6992cada25b3c496160a2b9717afae84 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5641053680173056 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5686749313892352 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5686749313892352 new file mode 100644 index 0000000000000000000000000000000000000000..c6e33d245d71dc5c9b1ff5ff913e88f33205d241 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5686749313892352 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5717414645334016 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5717414645334016 new file mode 100644 index 0000000000000000000000000000000000000000..9cde3b970c1a905b28e9cad400833cc48f2b6870 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5717414645334016 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5756332481708032 b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5756332481708032 new file mode 100644 index 0000000000000000000000000000000000000000..99af4b9f3321fb7861289bd2825f1811b3eabe87 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-hb-subset-fuzzer-5756332481708032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4601449528688640 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4601449528688640 new file mode 100644 index 0000000000000000000000000000000000000000..922d2d5d6e49f623cc39ef2ad2af3bbb843b9640 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4601449528688640 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4684060812378112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4684060812378112 new file mode 100644 index 0000000000000000000000000000000000000000..dd9ce36a5566fb66b122e2463563c9a551cd9666 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4684060812378112 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4710179695493120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4710179695493120 new file mode 100644 index 0000000000000000000000000000000000000000..655cda525b7668011eb8bc1a3d8df87029e130dc Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4710179695493120 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4850271066914816 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4850271066914816 new file mode 100644 index 0000000000000000000000000000000000000000..458478e0270c66ec9902b48146da112242e3b26a Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4850271066914816 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4977194146988032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4977194146988032 new file mode 100644 index 0000000000000000000000000000000000000000..7f8275a1081b065cc625573742d9ccebcafd5b7c Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-4977194146988032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5012913062150144 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5012913062150144 new file mode 100644 index 0000000000000000000000000000000000000000..9fea686ed0afb8ccf1523723f99d5c859eb32734 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5012913062150144 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5017946948370432 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5017946948370432 new file mode 100644 index 0000000000000000000000000000000000000000..c1fb1d15fedca98c97b844ed70de3787e80150b0 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5017946948370432 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5103148350963712 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5103148350963712 new file mode 100644 index 0000000000000000000000000000000000000000..f40b66be0b785ea37c1b447f0c588d42cdba3815 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5103148350963712 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5151890782027776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5151890782027776 new file mode 100644 index 0000000000000000000000000000000000000000..f1fd18a785284512094cd453d377705d6b5128ed Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5151890782027776 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5157039562162176 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5157039562162176 new file mode 100644 index 0000000000000000000000000000000000000000..54fbd3b10134f617752d3ecc2d70f259a329f55b Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5157039562162176 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5163560220753920 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5163560220753920 new file mode 100644 index 0000000000000000000000000000000000000000..b0adc5dbba2a5ea77f9688eb37520c26681273f1 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5163560220753920 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5170405903695872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5170405903695872 new file mode 100644 index 0000000000000000000000000000000000000000..33fda477c592115c7627f13d87d64c6e157ef411 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5170405903695872 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5180622648770560 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5180622648770560 new file mode 100644 index 0000000000000000000000000000000000000000..f6ce7c0fe0ea26c9e434367fabc31136b27bf5a5 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5180622648770560 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5221177988743168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5221177988743168 new file mode 100644 index 0000000000000000000000000000000000000000..cffd8ac8e3010801f5f57bfebd170aca3b9ad4b3 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5221177988743168 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5334300410773504 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5334300410773504 new file mode 100644 index 0000000000000000000000000000000000000000..3ae21cdb804a83b2c807245f035f8fcd3923bc3c Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5334300410773504 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5644474732249088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5644474732249088 new file mode 100644 index 0000000000000000000000000000000000000000..7ee1efabcde47ac17b7df7a0aaca40a152dce468 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5644474732249088 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5677289226108928 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5677289226108928 new file mode 100644 index 0000000000000000000000000000000000000000..ecb527e9df0e945763498f6e3b67ee7e552a9cc6 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5677289226108928 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5719356528656384 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5719356528656384 new file mode 100644 index 0000000000000000000000000000000000000000..490e843146a8a62b1b874f32158fc92448250cd1 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5719356528656384 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5740518101090304 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5740518101090304 new file mode 100644 index 0000000000000000000000000000000000000000..951bc6c1cf72c70f189b89907978642fb7df5f63 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5740518101090304 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5754958982021120 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5754958982021120 new file mode 100644 index 0000000000000000000000000000000000000000..bc9a1c4655c542db5b0bb64b5fc4d382eb9436a8 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5754958982021120 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5952939792531456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-5952939792531456 new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6107935408390144 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6107935408390144 new file mode 100644 index 0000000000000000000000000000000000000000..4c81a86608189eb7a0b21b205d36116b833aafcf Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6107935408390144 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6120104833843200 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6120104833843200 new file mode 100644 index 0000000000000000000000000000000000000000..f002d27f4d4b74f3dc1f7233b3b742cf1621301d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6120104833843200 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6128803416637440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6128803416637440 new file mode 100644 index 0000000000000000000000000000000000000000..a27a9c18566f1f3ef2f401f179482346cbcd9d86 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6128803416637440 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6142466903506944 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6142466903506944 new file mode 100644 index 0000000000000000000000000000000000000000..3ab62307d0d91f6a2239bc4093520ae302151b93 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6142466903506944 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6198448785981440 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6198448785981440 new file mode 100644 index 0000000000000000000000000000000000000000..c243a78cbcb7295e7a0ec351aea68397330360f0 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6198448785981440 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6223034666713088 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6223034666713088 new file mode 100644 index 0000000000000000000000000000000000000000..0e72493b38189a0beb5c3e2a86adfd2d801616e7 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6223034666713088 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6462232674959360 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6462232674959360 new file mode 100644 index 0000000000000000000000000000000000000000..33603bb110f3ceda7df6ec79b9e23484ae5d5739 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6462232674959360 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6600932143136768 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6600932143136768 new file mode 100644 index 0000000000000000000000000000000000000000..78a27095ce2d85b1b5289cdbf11db4cce7b7e5cf Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6600932143136768 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6603291950841856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6603291950841856 new file mode 100644 index 0000000000000000000000000000000000000000..12b91a09f9325bdb1c0c1935e35e5cd4892b04c3 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6603291950841856 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6712347260092416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6712347260092416 new file mode 100644 index 0000000000000000000000000000000000000000..37e5368ec01414c78c0f4345cf3a6b8bd60a7e0a Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer-6712347260092416 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer.exe-5470269447340032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer.exe-5470269447340032 new file mode 100644 index 0000000000000000000000000000000000000000..f5c27ee603851972ffd8fa51e51b47965984f0b3 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-harfbuzz_fuzzer.exe-5470269447340032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5088336521986048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5088336521986048 new file mode 100644 index 0000000000000000000000000000000000000000..5c23559c2c6227a019cc5ebd02cdc266afbe2790 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5088336521986048 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5103082208493568 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5103082208493568 new file mode 100644 index 0000000000000000000000000000000000000000..dc419f0aa0f5cc25aa2fbeb41d9bfa9dfa1f2fe8 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5103082208493568 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5641612227772416 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5641612227772416 new file mode 100644 index 0000000000000000000000000000000000000000..094f7d3ba006b49e2b5eb48904ddaf0939ff4cb1 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5641612227772416 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5668491560747008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5668491560747008 new file mode 100644 index 0000000000000000000000000000000000000000..cf9814a132d193cca1689f81d3aef39c2593e75c Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5668491560747008 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5681465586352128 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5681465586352128 new file mode 100644 index 0000000000000000000000000000000000000000..cc6708af375ebdd5c6e00151e2b6273b2da2af6a Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5681465586352128 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5686960406659072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5686960406659072 new file mode 100644 index 0000000000000000000000000000000000000000..f6e1461cb890cd43dfaeb98fd2fb7e4b28c6e8d6 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5686960406659072 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5703524300357632 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5703524300357632 new file mode 100644 index 0000000000000000000000000000000000000000..baff79fd1d109c892d03b76b164d6106b70d36ea Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5703524300357632 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5712313459146752 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5712313459146752 new file mode 100644 index 0000000000000000000000000000000000000000..319a56cdbba387f88eabef19d643aa7ebf054de8 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5712313459146752 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5750654771658752 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5750654771658752 new file mode 100644 index 0000000000000000000000000000000000000000..1ba504dd047004e477af3f8abf51bc64b71a6d20 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-5750654771658752 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-6231698648596480 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-6231698648596480 new file mode 100644 index 0000000000000000000000000000000000000000..f27e9956c1aafea1bee81afdf4d9cde076befec0 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-draw-fuzzer-6231698648596480 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 new file mode 100644 index 0000000000000000000000000000000000000000..d8a39898e4bd3860ce5865fd005e51c83e37cea5 --- /dev/null +++ b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5138182937772032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5138182937772032 new file mode 100644 index 0000000000000000000000000000000000000000..2f2f7b89ed96009c836c65f86e62a7c56a322e18 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5138182937772032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5154718402215936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5154718402215936 new file mode 100644 index 0000000000000000000000000000000000000000..3dbf5a5ac77c3449fa21d0a98a685789f0bbbf6e Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5154718402215936 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5158673602314240 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5158673602314240 new file mode 100644 index 0000000000000000000000000000000000000000..9add16d6db805800b35a302f9950c5a0187ba1b8 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5158673602314240 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5196560812474368 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5196560812474368 new file mode 100644 index 0000000000000000000000000000000000000000..cc37c6e4f096b4afde3846a5ba2cba0f342067d0 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5196560812474368 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5632586529898496 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5632586529898496 new file mode 100644 index 0000000000000000000000000000000000000000..6b0a192e81d50d816fc8e1967ff5b9ac4089a10f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5632586529898496 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642666339991552 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642666339991552 new file mode 100644 index 0000000000000000000000000000000000000000..a9d66af3df090921ead6f711c2672e64edaf418c Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642666339991552 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642899625082880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642899625082880 new file mode 100644 index 0000000000000000000000000000000000000000..ad451297c6994d956f4ef63e38514551ea327639 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5642899625082880 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5648999235715072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5648999235715072 new file mode 100644 index 0000000000000000000000000000000000000000..bf1cd3215f0a4fe08929b88dc8b9c7c834608753 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5648999235715072 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652700541222912 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652700541222912 new file mode 100644 index 0000000000000000000000000000000000000000..1650649d448a9af4fb2fd7538066d52329c7000d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5652700541222912 differ diff --git a/test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 similarity index 100% rename from test/api/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 rename to test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5658272078495744 diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5666162551029760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5666162551029760 new file mode 100644 index 0000000000000000000000000000000000000000..fb27d423ab480a542ab4d2673ffb95a8438f70c9 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5666162551029760 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711096049041408 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711096049041408 new file mode 100644 index 0000000000000000000000000000000000000000..310fabb8ded5cf6efdb809342970af093fcd59f4 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711096049041408 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711472756260864 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711472756260864 new file mode 100644 index 0000000000000000000000000000000000000000..726470920d08812147cd5ce5471ce7c8e9f31c92 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5711472756260864 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5712050577211392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5712050577211392 new file mode 100644 index 0000000000000000000000000000000000000000..9b31fedb5c4f90426d386aa19134601a91764e84 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5712050577211392 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5742079188140032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5742079188140032 new file mode 100644 index 0000000000000000000000000000000000000000..d9892345433b910000c36cfb18db077473a26545 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5742079188140032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5749627240841216 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5749627240841216 new file mode 100644 index 0000000000000000000000000000000000000000..360938a0d798b7547d6c69df78e3b893b65a8e21 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5749627240841216 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5769590820044800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5769590820044800 new file mode 100644 index 0000000000000000000000000000000000000000..f6368c6d99ccd750e0f0c36290f1a4ebbbc23e56 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-5769590820044800 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6306977171374080 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6306977171374080 new file mode 100644 index 0000000000000000000000000000000000000000..95f02d748572c1b9c8e0ddf166576c2666efd9af Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-shape-fuzzer-6306977171374080 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4880059756969984 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4880059756969984 new file mode 100644 index 0000000000000000000000000000000000000000..0a0f649ca4182e461bea21447e9cce45829a09bf Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4880059756969984 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4901143794810880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4901143794810880 new file mode 100644 index 0000000000000000000000000000000000000000..d6624f380c2780cba405b857e59510822cdc1bbf Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4901143794810880 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4961171477233664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4961171477233664 new file mode 100644 index 0000000000000000000000000000000000000000..013a859434926b5bc0606ebb4a5c43c256177715 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-4961171477233664 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5121706490593280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5121706490593280 new file mode 100644 index 0000000000000000000000000000000000000000..d94f5a7180b74e9e54a85b67074c7fe283f6ea09 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5121706490593280 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5137462782066688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5137462782066688 new file mode 100644 index 0000000000000000000000000000000000000000..7b049bac2cc8d3c8f6f39b75942111569f412062 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5137462782066688 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5148388450631680 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5148388450631680 new file mode 100644 index 0000000000000000000000000000000000000000..16213e4811d4e542ae44ecb310c38488753d657f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5148388450631680 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5160311461511168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5160311461511168 new file mode 100644 index 0000000000000000000000000000000000000000..50db8d4ff2ba62275bd3ff1c902423420671f6aa Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5160311461511168 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5167653459329024 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5167653459329024 new file mode 100644 index 0000000000000000000000000000000000000000..fe83d24a9b4e841d0b19d2f99108348ab26e3c4d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5167653459329024 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5169035432165376 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5169035432165376 new file mode 100644 index 0000000000000000000000000000000000000000..74958bff13a4d264fd91f08fdb111348ce515f34 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5169035432165376 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5179935334465536 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5179935334465536 new file mode 100644 index 0000000000000000000000000000000000000000..61e7fa1797e37ea487246849be171a1ef0b10075 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5179935334465536 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5181909018345472 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5181909018345472 new file mode 100644 index 0000000000000000000000000000000000000000..250710b40bf48523dd97acebd7dc25ae3da92cbb Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5181909018345472 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5206191479455744 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5206191479455744 new file mode 100644 index 0000000000000000000000000000000000000000..e82995e532ff165aee7fd01eb64286dccc900655 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5206191479455744 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5229304507138048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5229304507138048 new file mode 100644 index 0000000000000000000000000000000000000000..d04f7d8955a6ce558f16ae95ace30c08e33dff7c Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5229304507138048 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5250795600740352 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5250795600740352 new file mode 100644 index 0000000000000000000000000000000000000000..1c1919f5fd91a6a893734c37094959e0b7208764 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5250795600740352 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5345734743031808 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5345734743031808 new file mode 100644 index 0000000000000000000000000000000000000000..193cf8958b98f570c5693f7636363c2e97151d5e Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5345734743031808 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5363902507515904 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5363902507515904 new file mode 100644 index 0000000000000000000000000000000000000000..1ad79713759deca28c7f2bd7dcd68d1cbe4d5305 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5363902507515904 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5416421032067072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5416421032067072 new file mode 100644 index 0000000000000000000000000000000000000000..6b245f3a76880b80c18aa2ce6d28647d2b19b108 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5416421032067072 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609112151916544 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609112151916544 new file mode 100644 index 0000000000000000000000000000000000000000..0a9ce89d9b001e24a38e75f7e40d671b8e96bf62 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5609112151916544 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5616763250278400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5616763250278400 new file mode 100644 index 0000000000000000000000000000000000000000..d58d3f6cb6d92e9012638eacf4fc89c97dc8b51f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5616763250278400 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5617065093365760 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5617065093365760 new file mode 100644 index 0000000000000000000000000000000000000000..590e6fc39842251b5ab20b02dfea7e70954a72e8 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5617065093365760 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640452927127552 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640452927127552 new file mode 100644 index 0000000000000000000000000000000000000000..f9cf239e3f6fd8fb46f9b31d7e587f2bb09b84ec Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640452927127552 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640889218629632 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640889218629632 new file mode 100644 index 0000000000000000000000000000000000000000..a83df5224af5d444c0ff0af2b3d9c693811bd889 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5640889218629632 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641053680173056 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641053680173056 new file mode 100644 index 0000000000000000000000000000000000000000..f639f1793f8b71aa0b859481d16925dc06cd12ab Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641053680173056 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641370503217152 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641370503217152 new file mode 100644 index 0000000000000000000000000000000000000000..22827d670a8b66beb13f1437ad65d25b3801e2c1 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641370503217152 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641892164009984 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641892164009984 new file mode 100644 index 0000000000000000000000000000000000000000..dbf5f8cf4d10fae9b09b59402e5e32e660c86367 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5641892164009984 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5642531954229248 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5642531954229248 new file mode 100644 index 0000000000000000000000000000000000000000..8631cd645ee1b1632977d448f8297cb5329836d1 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5642531954229248 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5643107869917184 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5643107869917184 new file mode 100644 index 0000000000000000000000000000000000000000..b11bd878451d7c85af7d17667b30fb78fbf1a681 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5643107869917184 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5650879734874112 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5650879734874112 new file mode 100644 index 0000000000000000000000000000000000000000..24da16e0ad9f604083da6a0de0fc3ff40e56c589 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5650879734874112 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5659903036751872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5659903036751872 new file mode 100644 index 0000000000000000000000000000000000000000..51ab2fe43733fb17298003507cd5cd0305ac7135 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5659903036751872 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5661567174311936 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5661567174311936 new file mode 100644 index 0000000000000000000000000000000000000000..fbc3f52717d3f4952826054a01a86f96b76647d5 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5661567174311936 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5662792105590784 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5662792105590784 new file mode 100644 index 0000000000000000000000000000000000000000..d283d14fdc50afbf60330fc73eac85dd1ffe2423 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5662792105590784 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5667673584697344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5667673584697344 new file mode 100644 index 0000000000000000000000000000000000000000..e08ab56ed3053a29fdcaba23579744ca1769fa19 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5667673584697344 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5674228796358656 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5674228796358656 new file mode 100644 index 0000000000000000000000000000000000000000..323f5c54f76ce4101942418926b2a2abb1ba19ca Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5674228796358656 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776 new file mode 100644 index 0000000000000000000000000000000000000000..11a236727a0c011a11171e9cc0f41703ee9251ea Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5675720390475776 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5677906231033856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5677906231033856 new file mode 100644 index 0000000000000000000000000000000000000000..72147f60bb6ae40bde18ecf23d653890db495d4e Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5677906231033856 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5678476148867072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5678476148867072 new file mode 100644 index 0000000000000000000000000000000000000000..f1af962abc5824a7c80cb56c3657bb2fdc6556ee Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5678476148867072 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684014636859392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684014636859392 new file mode 100644 index 0000000000000000000000000000000000000000..f7d3c0d21dcc166f4da5e5304d77b1121936e809 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684014636859392 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684542900535296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684542900535296 new file mode 100644 index 0000000000000000000000000000000000000000..fc238c2fec47107663c93f12cff093e6d21f53ff Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5684542900535296 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5685097303375872 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5685097303375872 new file mode 100644 index 0000000000000000000000000000000000000000..cc9e421cf9707ea4147a3646f3994466a3c96392 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5685097303375872 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5689082504806400 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5689082504806400 new file mode 100644 index 0000000000000000000000000000000000000000..9df69220abf6f9fcfb5c3d712dad7974a173dcab Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5689082504806400 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695865298092032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695865298092032 new file mode 100644 index 0000000000000000000000000000000000000000..ac1571cde594009c4e2640059530692cedf8aa42 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695865298092032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695925913911296 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695925913911296 new file mode 100644 index 0000000000000000000000000000000000000000..42296e5d55bfe56df879b12ffca1b1da032a8b24 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5695925913911296 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5697351339999232 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5697351339999232 new file mode 100644 index 0000000000000000000000000000000000000000..c72812e9208c18b9df2fe488354340b01f14209d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5697351339999232 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5704307501694976 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5704307501694976 new file mode 100644 index 0000000000000000000000000000000000000000..f2f0ec9c9ecbcbbde49378457f1e92deec130123 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5704307501694976 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5707809174585344 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5707809174585344 new file mode 100644 index 0000000000000000000000000000000000000000..fba50e50ee554ab2bb01191cd9e5b7df08846c88 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5707809174585344 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708063625969664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708063625969664 new file mode 100644 index 0000000000000000000000000000000000000000..01973d59f886eef1e14a19176f952c1365812b26 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708063625969664 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708623339323392 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708623339323392 new file mode 100644 index 0000000000000000000000000000000000000000..4356547dd4207d5658c12c0097bbddd12c57f12f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708623339323392 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708764082864128 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708764082864128 new file mode 100644 index 0000000000000000000000000000000000000000..96cfb00651506ba8dc3daa430b1799b57a373030 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5708764082864128 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711849555755008 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711849555755008 new file mode 100644 index 0000000000000000000000000000000000000000..c464afa6bd7c93c97c615f3bd4fed90b12e589ba Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5711849555755008 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5713850117914624 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5713850117914624 new file mode 100644 index 0000000000000000000000000000000000000000..51cf483dcf5630bcf5b20315f9a5cd51f15f9b21 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5713850117914624 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715299773186048 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715299773186048 new file mode 100644 index 0000000000000000000000000000000000000000..b7a37214a8c1ab2a0d17898d71f1002c15170165 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5715299773186048 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5719588814979072 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5719588814979072 new file mode 100644 index 0000000000000000000000000000000000000000..383e61a213c9dc1f8188748d1e119e41d4d9e8a0 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5719588814979072 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5721073428987904 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5721073428987904 new file mode 100644 index 0000000000000000000000000000000000000000..683ef99f7eb474ccbc3807ce7849cef5ed75f801 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5721073428987904 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5728664968232960 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5728664968232960 new file mode 100644 index 0000000000000000000000000000000000000000..e099413bdc8e3e3227c5ee40fef0a46db91accea Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5728664968232960 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5733203291144192 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5733203291144192 new file mode 100644 index 0000000000000000000000000000000000000000..1e396133fd39468c12c9b0951468ebed676ff98e Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5733203291144192 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5735719311507456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5735719311507456 new file mode 100644 index 0000000000000000000000000000000000000000..83314a18c729b595e1c1a9d9bd3b34d5c7c7149b Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5735719311507456 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5741735372914688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5741735372914688 new file mode 100644 index 0000000000000000000000000000000000000000..31ea527fbc3b40f36f3806815a2972c8350c2aab Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5741735372914688 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5745268385906688 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5745268385906688 new file mode 100644 index 0000000000000000000000000000000000000000..b69d8115bc92cee31ec3b8f1b4dcd10dde81d85c Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5745268385906688 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747028458209280 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747028458209280 new file mode 100644 index 0000000000000000000000000000000000000000..557c823b5ff016da664f1e6b5bef0c6ce51d8d36 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747028458209280 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747280156295168 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747280156295168 new file mode 100644 index 0000000000000000000000000000000000000000..57611513cfbd361814c8262e957a18274d7567b9 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5747280156295168 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5753173985984512 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5753173985984512 new file mode 100644 index 0000000000000000000000000000000000000000..46ec9296dac1c254bc237fdf22cedf483fca337f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5753173985984512 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5754526379802624 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5754526379802624 new file mode 100644 index 0000000000000000000000000000000000000000..3a7cc9d99a2897a00801b395da8fec771fe049c2 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5754526379802624 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5756658848890880 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5756658848890880 new file mode 100644 index 0000000000000000000000000000000000000000..871744204c987b23ac5e1dfe8839b98889c87f25 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5756658848890880 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758358618898432 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758358618898432 new file mode 100644 index 0000000000000000000000000000000000000000..b93e1b184b18ad2351bbff5b2994c66731a9fc6a Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5758358618898432 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759725666041856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759725666041856 new file mode 100644 index 0000000000000000000000000000000000000000..b23c11afb01dc2861fb41c60ca7bc6fde5b59668 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759725666041856 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759783999635456 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759783999635456 new file mode 100644 index 0000000000000000000000000000000000000000..96775e9dda8d026d99654920df2dd435a669b74b Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5759783999635456 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5763024094232576 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5763024094232576 new file mode 100644 index 0000000000000000000000000000000000000000..da1b718a5c7523ed822f9b00781b0e2b23827aec Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5763024094232576 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764020596899840 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764020596899840 new file mode 100644 index 0000000000000000000000000000000000000000..af2a62a255bd48c5ea2d18c755c2f54be09d70df Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5764020596899840 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5858518134554624 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5858518134554624 new file mode 100644 index 0000000000000000000000000000000000000000..90a743b9fe0eb7307338292d2c55cb0e05a4f25f Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5858518134554624 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5887968763052032 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5887968763052032 new file mode 100644 index 0000000000000000000000000000000000000000..028e4b26ee87da19021aabf82e65e331d3e71ae1 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5887968763052032 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5927551890096128 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5927551890096128 new file mode 100644 index 0000000000000000000000000000000000000000..a5f5af8c8a3009910e7d68b28d15a824852e9562 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-5927551890096128 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6173520787800064 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6173520787800064 new file mode 100644 index 0000000000000000000000000000000000000000..035dd72f15453a20607063c63472db3010fa9e77 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6173520787800064 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6231212713312256 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6231212713312256 new file mode 100644 index 0000000000000000000000000000000000000000..3f0f045a0af48475e9f7af6d348cf72236cb1771 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6231212713312256 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6241118484955136 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6241118484955136 new file mode 100644 index 0000000000000000000000000000000000000000..6419459ea1a7c3180a135ee16024939963c90111 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6241118484955136 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6246465148813312 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6246465148813312 new file mode 100644 index 0000000000000000000000000000000000000000..750700fcf1676cf93b70f928ce934ed6ed42db92 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6246465148813312 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6276691949518848 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6276691949518848 new file mode 100644 index 0000000000000000000000000000000000000000..5465069956d452ca7fc3a5d5e36ac114f3e766f2 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6276691949518848 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6316256152780800 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6316256152780800 new file mode 100644 index 0000000000000000000000000000000000000000..b01eb8d96cff6300b9b44e87a21c834fe5ed29f0 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6316256152780800 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6372147008241664 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6372147008241664 new file mode 100644 index 0000000000000000000000000000000000000000..696bd6e748101868db8b86c880d95c17057f29e2 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6372147008241664 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6382598554255360 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6382598554255360 new file mode 100644 index 0000000000000000000000000000000000000000..b6aab7b5a2c6916e61b058060b781771349cad92 Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6382598554255360 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6421315436281856 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6421315436281856 new file mode 100644 index 0000000000000000000000000000000000000000..3d883bd577be17de01490c158059b33b316b839d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb-subset-fuzzer-6421315436281856 differ diff --git a/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb_shape_fuzzer-5633785895911424 b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb_shape_fuzzer-5633785895911424 new file mode 100644 index 0000000000000000000000000000000000000000..0bbeb5c90f523586d5f7850da095e3e83b351e5d Binary files /dev/null and b/test/fuzzing/fonts/clusterfuzz-testcase-minimized-hb_shape_fuzzer-5633785895911424 differ diff --git a/test/fuzzing/fonts/fuzz-0-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-0-harfbuzz_fuzzer new file mode 100644 index 0000000000000000000000000000000000000000..0f6503d4ce4588516da58fb7b33fb8ce4306dfa9 Binary files /dev/null and b/test/fuzzing/fonts/fuzz-0-harfbuzz_fuzzer differ diff --git a/test/fuzzing/fonts/fuzz-0-harfbuzz_hb-fuzzer b/test/fuzzing/fonts/fuzz-0-harfbuzz_hb-fuzzer new file mode 100644 index 0000000000000000000000000000000000000000..8b1c29305efe150c235a1070a737ab2b4bad82f1 Binary files /dev/null and b/test/fuzzing/fonts/fuzz-0-harfbuzz_hb-fuzzer differ diff --git a/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer new file mode 100644 index 0000000000000000000000000000000000000000..eac0b7dfcb38d24d3b428e21596ed3afa9399e2a Binary files /dev/null and b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer differ diff --git a/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer(1) b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer(1) new file mode 100644 index 0000000000000000000000000000000000000000..d508980e3fd903ebe2c3dc09e91cc7367a056a1c Binary files /dev/null and b/test/fuzzing/fonts/fuzz-1-harfbuzz_fuzzer(1) differ diff --git a/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer new file mode 100644 index 0000000000000000000000000000000000000000..a358833c2fdcac4574cfcda9e1ea2b663b403573 Binary files /dev/null and b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer differ diff --git a/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer(1) b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer(1) new file mode 100644 index 0000000000000000000000000000000000000000..a358833c2fdcac4574cfcda9e1ea2b663b403573 Binary files /dev/null and b/test/fuzzing/fonts/fuzz-2-harfbuzz_fuzzer(1) differ diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer new file mode 100644 index 0000000000000000000000000000000000000000..f467471e92c09bf74a9dd9f68829583a2776ddfd Binary files /dev/null and b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer differ diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(1) b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(1) new file mode 100644 index 0000000000000000000000000000000000000000..d53fcff024b4b7929e311d6f6fe0c61d4d58783a Binary files /dev/null and b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(1) differ diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(2) b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(2) new file mode 100644 index 0000000000000000000000000000000000000000..bab475ef4f4a26a84fa18a1a57a1691678f4d08a Binary files /dev/null and b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(2) differ diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(3) b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(3) new file mode 100644 index 0000000000000000000000000000000000000000..81045cf3f37f47de028679f7afadf004d6aea875 Binary files /dev/null and b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(3) differ diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(4) b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(4) new file mode 100644 index 0000000000000000000000000000000000000000..ee584361b47367d21adf0c0906613d4f31df1855 Binary files /dev/null and b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(4) differ diff --git a/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(5) b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(5) new file mode 100644 index 0000000000000000000000000000000000000000..f467471e92c09bf74a9dd9f68829583a2776ddfd Binary files /dev/null and b/test/fuzzing/fonts/fuzz-3-harfbuzz_fuzzer(5) differ diff --git a/test/fuzzing/fonts/kanit.ttf b/test/fuzzing/fonts/kanit.ttf new file mode 100644 index 0000000000000000000000000000000000000000..03dc644bdeb3f9da536375fea1d01e859b7319f8 Binary files /dev/null and b/test/fuzzing/fonts/kanit.ttf differ diff --git a/test/fuzzing/fonts/sbix.ttf b/test/fuzzing/fonts/sbix.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e3da30a2e44ded71e3626b2c5715cfdca988179d Binary files /dev/null and b/test/fuzzing/fonts/sbix.ttf differ diff --git a/test/fuzzing/hb-draw-fuzzer.cc b/test/fuzzing/hb-draw-fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..772a358314820b6839a43effeb946d92285e98a0 --- /dev/null +++ b/test/fuzzing/hb-draw-fuzzer.cc @@ -0,0 +1,177 @@ +#include +#include + +#include + +#include "hb-fuzzer.hh" + +#ifdef HB_EXPERIMENTAL_API +struct _user_data_t +{ + bool is_open; + unsigned path_len; + hb_position_t path_start_x; + hb_position_t path_start_y; + hb_position_t path_last_x; + hb_position_t path_last_y; +}; + +static void +_move_to (hb_position_t to_x, hb_position_t to_y, void *user_data_) +{ + _user_data_t *user_data = (_user_data_t *) user_data_; + assert (!user_data->is_open); + user_data->is_open = true; + user_data->path_start_x = user_data->path_last_x = to_x; + user_data->path_start_y = user_data->path_last_y = to_y; +} + +static void +_line_to (hb_position_t to_x, hb_position_t to_y, void *user_data_) +{ + _user_data_t *user_data = (_user_data_t *) user_data_; + assert (user_data->is_open); + assert (user_data->path_last_x != to_x || user_data->path_last_y != to_y); + ++user_data->path_len; + user_data->path_last_x = to_x; + user_data->path_last_y = to_y; +} + +static void +_quadratic_to (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y, void *user_data_) +{ + _user_data_t *user_data = (_user_data_t *) user_data_; + assert (user_data->is_open); + assert (user_data->path_last_x != control_x || user_data->path_last_y != control_y || + user_data->path_last_x != to_x || user_data->path_last_y != to_y); + ++user_data->path_len; + user_data->path_last_x = to_x; + user_data->path_last_y = to_y; +} + +static void +_cubic_to (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y, void *user_data_) +{ + _user_data_t *user_data = (_user_data_t *) user_data_; + assert (user_data->is_open); + assert (user_data->path_last_x != control1_x || user_data->path_last_y != control1_y || + user_data->path_last_x != control2_x || user_data->path_last_y != control2_y || + user_data->path_last_x != to_x || user_data->path_last_y != to_y); + ++user_data->path_len; + user_data->path_last_x = to_x; + user_data->path_last_y = to_y; +} + +static void +_close_path (void *user_data_) +{ + _user_data_t *user_data = (_user_data_t *) user_data_; + assert (user_data->is_open && user_data->path_len != 0); + user_data->path_len = 0; + user_data->is_open = false; + assert (user_data->path_start_x == user_data->path_last_x && + user_data->path_start_y == user_data->path_last_y); +} +#endif + +/* Similar to test-ot-face.c's #test_font() */ +static void misc_calls_for_gid (hb_face_t *face, hb_font_t *font, hb_set_t *set, hb_codepoint_t cp) +{ + /* Other gid specific misc calls */ + hb_face_collect_variation_unicodes (face, cp, set); + + hb_codepoint_t g; + hb_font_get_nominal_glyph (font, cp, &g); + hb_font_get_variation_glyph (font, cp, cp, &g); + hb_font_get_glyph_h_advance (font, cp); + hb_font_get_glyph_v_advance (font, cp); + hb_position_t x, y; + hb_font_get_glyph_h_origin (font, cp, &x, &y); + hb_font_get_glyph_v_origin (font, cp, &x, &y); + hb_font_get_glyph_contour_point (font, cp, 0, &x, &y); + char buf[64]; + hb_font_get_glyph_name (font, cp, buf, sizeof (buf)); + + hb_ot_color_palette_get_name_id (face, cp); + hb_ot_color_palette_color_get_name_id (face, cp); + hb_ot_color_palette_get_flags (face, cp); + hb_ot_color_palette_get_colors (face, cp, 0, nullptr, nullptr); + hb_ot_color_glyph_get_layers (face, cp, 0, nullptr, nullptr); + hb_blob_destroy (hb_ot_color_glyph_reference_svg (face, cp)); + hb_blob_destroy (hb_ot_color_glyph_reference_png (font, cp)); + + hb_ot_layout_get_ligature_carets (font, HB_DIRECTION_LTR, cp, 0, nullptr, nullptr); + + hb_ot_math_get_glyph_italics_correction (font, cp); + hb_ot_math_get_glyph_top_accent_attachment (font, cp); + hb_ot_math_is_glyph_extended_shape (face, cp); + hb_ot_math_get_glyph_kerning (font, cp, HB_OT_MATH_KERN_BOTTOM_RIGHT, 0); + hb_ot_math_get_glyph_variants (font, cp, HB_DIRECTION_TTB, 0, nullptr, nullptr); + hb_ot_math_get_glyph_assembly (font, cp, HB_DIRECTION_BTT, 0, nullptr, nullptr, nullptr); +} + +extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) +{ + alloc_state = size; /* see src/failing-alloc.c */ + + hb_blob_t *blob = hb_blob_create ((const char *) data, size, + HB_MEMORY_MODE_READONLY, nullptr, nullptr); + hb_face_t *face = hb_face_create (blob, 0); + hb_font_t *font = hb_font_create (face); + + unsigned num_coords = 0; + if (size) num_coords = data[size - 1]; + num_coords = hb_ot_var_get_axis_count (face) > num_coords ? num_coords : hb_ot_var_get_axis_count (face); + int *coords = (int *) calloc (num_coords, sizeof (int)); + if (size > num_coords + 1) + for (unsigned i = 0; i < num_coords; ++i) + coords[i] = ((int) data[size - num_coords + i - 1] - 128) * 10; + hb_font_set_var_coords_normalized (font, coords, num_coords); + free (coords); + + unsigned glyph_count = hb_face_get_glyph_count (face); + glyph_count = glyph_count > 16 ? 16 : glyph_count; + +#ifdef HB_EXPERIMENTAL_API + _user_data_t user_data = {false, 0, 0, 0, 0, 0}; + + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) _move_to); + hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) _line_to); + hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) _quadratic_to); + hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) _cubic_to); + hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) _close_path); +#endif + volatile unsigned counter = !glyph_count; + hb_set_t *set = hb_set_create (); + for (unsigned gid = 0; gid < glyph_count; ++gid) + { +#ifdef HB_EXPERIMENTAL_API + hb_font_draw_glyph (font, gid, funcs, &user_data); + assert (!user_data.is_open); +#endif + + /* Glyph extents also may practices the similar path, call it now that is related */ + hb_glyph_extents_t extents; + if (hb_font_get_glyph_extents (font, gid, &extents)) + counter += !!extents.width + !!extents.height + !!extents.x_bearing + !!extents.y_bearing; + + if (!counter) counter += 1; + + /* other misc calls */ + misc_calls_for_gid (face, font, set, gid); + } + hb_set_destroy (set); + assert (counter); +#ifdef HB_EXPERIMENTAL_API + hb_draw_funcs_destroy (funcs); +#endif + + hb_font_destroy (font); + hb_face_destroy (face); + hb_blob_destroy (blob); + return 0; +} diff --git a/test/fuzzing/hb-fuzzer.hh b/test/fuzzing/hb-fuzzer.hh index d0c617e09f740640dc75d2c6f053e3e5b6711899..52e00dd0e499a3d27dcdaa854ad176d12298f50e 100644 --- a/test/fuzzing/hb-fuzzer.hh +++ b/test/fuzzing/hb-fuzzer.hh @@ -1,4 +1,18 @@ #include #include -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size); + +#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__) +#define HB_UNUSED __attribute__((unused)) +#else +#define HB_UNUSED +#endif + +#ifdef HB_IS_IN_FUZZER +/* See src/failing-alloc.c */ +extern "C" int alloc_state; +#else +/* Just a dummy global variable */ +static int HB_UNUSED alloc_state = 0; +#endif diff --git a/test/fuzzing/hb-set-fuzzer.cc b/test/fuzzing/hb-set-fuzzer.cc new file mode 100644 index 0000000000000000000000000000000000000000..0a547f3a0378a41ed6cd53138ce9ccf1769bd866 --- /dev/null +++ b/test/fuzzing/hb-set-fuzzer.cc @@ -0,0 +1,90 @@ +#include "hb-fuzzer.hh" + +#include +#include +#include +#include + +#include "hb.h" + +// Only allow ~5,000 set values between the two input sets. +// Arbitarily long input sets do not trigger any meaningful +// differences in behaviour so there's no benefit from allowing +// the fuzzer to create super large sets. +#define MAX_INPUT_SIZE 20000 + +enum set_operation_t : uint8_t +{ + INTERSECT = 0, + UNION = 1, + SUBTRACT = 2, + SYMMETRIC_DIFFERENCE = 3 +}; + +struct instructions_t +{ + set_operation_t operation; + uint32_t first_set_size; +}; + +static hb_set_t *create_set (const uint32_t *value_array, int count) +{ + hb_set_t *set = hb_set_create (); + for (int i = 0; i < count; i++) + hb_set_add (set, value_array[i]); + return set; +} + + +extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) +{ + alloc_state = size; /* see src/failing-alloc.c */ + + if (size < sizeof (instructions_t)) + return 0; + + if (size > MAX_INPUT_SIZE) + return 0; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" + const instructions_t &instructions = reinterpret_cast (data); +#pragma GCC diagnostic pop + data += sizeof (instructions_t); + size -= sizeof (instructions_t); + + const uint32_t *values = reinterpret_cast (data); + size = size / sizeof (uint32_t); + + if (size < instructions.first_set_size) + return 0; + + hb_set_t *set_a = create_set (values, instructions.first_set_size); + + values += instructions.first_set_size; + size -= instructions.first_set_size; + hb_set_t *set_b = create_set (values, size); + + switch (instructions.operation) + { + case INTERSECT: + hb_set_intersect (set_a, set_b); + break; + case UNION: + hb_set_union (set_a, set_b); + break; + case SUBTRACT: + hb_set_subtract (set_a, set_b); + break; + case SYMMETRIC_DIFFERENCE: + hb_set_symmetric_difference (set_a, set_b); + break; + default: + break; + } + + hb_set_destroy (set_a); + hb_set_destroy (set_b); + + return 0; +} diff --git a/test/fuzzing/hb-shape-fuzzer.cc b/test/fuzzing/hb-shape-fuzzer.cc index 64a6b12df8f2787e48b5bd813400bf752e25c9c2..661ea9ffa659ec5c649e7dbf472edc363db853b4 100644 --- a/test/fuzzing/hb-shape-fuzzer.cc +++ b/test/fuzzing/hb-shape-fuzzer.cc @@ -3,12 +3,16 @@ #include #include +#include + #define TEST_OT_FACE_NO_MAIN 1 #include "../api/test-ot-face.c" #undef TEST_OT_FACE_NO_MAIN -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) { + alloc_state = size; /* see src/failing-alloc.c */ + hb_blob_t *blob = hb_blob_create ((const char *)data, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr); hb_face_t *face = hb_face_create (blob, 0); @@ -16,6 +20,16 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) hb_ot_font_set_funcs (font); hb_font_set_scale (font, 12, 12); + unsigned num_coords = 0; + if (size) num_coords = data[size - 1]; + num_coords = hb_ot_var_get_axis_count (face) > num_coords ? num_coords : hb_ot_var_get_axis_count (face); + int *coords = (int *) calloc (num_coords, sizeof (int)); + if (size > num_coords + 1) + for (unsigned i = 0; i < num_coords; ++i) + coords[i] = ((int) data[size - num_coords + i - 1] - 128) * 10; + hb_font_set_var_coords_normalized (font, coords, num_coords); + free (coords); + { const char text[] = "ABCDEXYZ123@_%&)*$!"; hb_buffer_t *buffer = hb_buffer_create (); @@ -29,7 +43,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) unsigned int len = sizeof (text32); if (size < len) len = size; - memcpy(text32, data + size - len, len); + if (len) + memcpy (text32, data + size - len, len); + + /* Misc calls on font. */ + text32[10] = test_font (font, text32[15]) % 256; hb_buffer_t *buffer = hb_buffer_create (); hb_buffer_add_utf32 (buffer, text32, sizeof (text32) / sizeof (text32[0]), 0, -1); @@ -37,9 +55,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) hb_shape (font, buffer, nullptr, 0); hb_buffer_destroy (buffer); - /* Misc calls on face. */ - test_face (face, text32[15]); - hb_font_destroy (font); hb_face_destroy (face); hb_blob_destroy (blob); diff --git a/test/fuzzing/hb-subset-fuzzer.cc b/test/fuzzing/hb-subset-fuzzer.cc index 428765ea32055fff1ed898bc0b1688e1bc0ff2b5..f89d2f49b68b8f594a86a585e19158b3880deb6e 100644 --- a/test/fuzzing/hb-subset-fuzzer.cc +++ b/test/fuzzing/hb-subset-fuzzer.cc @@ -16,6 +16,7 @@ trySubset (hb_face_t *face, bool retain_gids) { hb_subset_input_t *input = hb_subset_input_create_or_fail (); + if (!input) return; hb_subset_input_set_drop_hints (input, drop_hints); hb_subset_input_set_retain_gids (input, retain_gids); hb_set_t *codepoints = hb_subset_input_unicode_set (input); @@ -28,9 +29,7 @@ trySubset (hb_face_t *face, } for (int i = 0; i < text_length; i++) - { hb_set_add (codepoints, text[i]); - } hb_face_t *result = hb_subset (face, input); { @@ -64,14 +63,16 @@ trySubset (hb_face_t *face, drop_hints, drop_layout, retain_gids); } -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size) { - hb_blob_t *blob = hb_blob_create ((const char *)data, size, + alloc_state = size; /* see src/failing-alloc.c */ + + hb_blob_t *blob = hb_blob_create ((const char *) data, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr); hb_face_t *face = hb_face_create (blob, 0); /* Just test this API here quickly. */ - hb_set_t *output = hb_set_create(); + hb_set_t *output = hb_set_create (); hb_face_collect_unicodes (face, output); hb_set_destroy (output); @@ -85,14 +86,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) trySubset (face, text, sizeof (text) / sizeof (hb_codepoint_t), flags); hb_codepoint_t text_from_data[16]; - if (size > sizeof(text_from_data) + sizeof(flags)) { + if (size > sizeof (text_from_data) + sizeof (flags)) { memcpy (text_from_data, - data + size - sizeof(text_from_data), - sizeof(text_from_data)); + data + size - sizeof (text_from_data), + sizeof (text_from_data)); memcpy (flags, - data + size - sizeof(text_from_data) - sizeof(flags), - sizeof(flags)); + data + size - sizeof (text_from_data) - sizeof (flags), + sizeof (flags)); unsigned int text_size = sizeof (text_from_data) / sizeof (hb_codepoint_t); trySubset (face, text_from_data, text_size, flags); diff --git a/test/fuzzing/main.cc b/test/fuzzing/main.cc index 5318f64eae2aad1abdb9d94f8c5d17de1d7cb3a6..9e892ebe1755647e469572123731b7ed389e49e0 100644 --- a/test/fuzzing/main.cc +++ b/test/fuzzing/main.cc @@ -1,28 +1,20 @@ #include "hb-fuzzer.hh" #include -#include -#include int main (int argc, char **argv) { - hb_blob_t *blob = hb_blob_create_from_file (argv[1]); - - unsigned int len; - const char *font_data = hb_blob_get_data (blob, &len); - if (len == 0) - { - printf ("Font not found.\n"); - exit (1); - } - for (int i = 1; i < argc; i++) { - printf ("%s\n", argv[i]); - LLVMFuzzerTestOneInput ((const uint8_t *) font_data, len); - } + hb_blob_t *blob = hb_blob_create_from_file (argv[i]); + + unsigned int len; + const char *font_data = hb_blob_get_data (blob, &len); + printf ("%s%s\n", argv[i], len ? "" : " (note: not found or was empty)"); - hb_blob_destroy (blob); + LLVMFuzzerTestOneInput ((const uint8_t *) font_data, len); + hb_blob_destroy (blob); + } return 0; } diff --git a/test/fuzzing/meson.build b/test/fuzzing/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..9ddb4b2c7a0cc493cffe5db9ef7b9d863bf5da64 --- /dev/null +++ b/test/fuzzing/meson.build @@ -0,0 +1,65 @@ +tests = [ + 'hb-shape-fuzzer.cc', + 'hb-subset-fuzzer.cc', + 'hb-set-fuzzer.cc', + 'hb-draw-fuzzer.cc', +] + +foreach file_name : tests + test_name = file_name.split('.')[0] + + sources = [file_name] + fuzzer_ldflags = [] + extra_cpp_args = [] + + if get_option('fuzzer_ldflags') == '' + sources += 'main.cc' + else + fuzzer_ldflags += get_option('fuzzer_ldflags').split() + extra_cpp_args += '-DHB_IS_IN_FUZZER' + endif + + exe = executable(test_name, sources, + cpp_args: cpp_args + extra_cpp_args, + include_directories: [incconfig, incsrc], + link_args: fuzzer_ldflags, + link_with: [libharfbuzz, libharfbuzz_subset], + install: false, + ) + set_variable('@0@_exe'.format(test_name.underscorify()), exe) +endforeach + +env = environment() +env.set('srcdir', meson.current_source_dir()) + +test('shape_fuzzer', find_program('run-shape-fuzzer-tests.py'), + args: [ + hb_shape_fuzzer_exe, + ], + timeout: 300, + depends: [hb_shape_fuzzer_exe, libharfbuzz, libharfbuzz_subset], + workdir: join_paths(meson.current_build_dir(), '..', '..'), + env: env, + suite: ['fuzzing', 'slow'], +) + +test('subset_fuzzer', find_program('run-subset-fuzzer-tests.py'), + args: [ + hb_subset_fuzzer_exe, + ], + # as the tests are ran concurrently let's raise acceptable time here + # ideally better to break and let meson handles them in parallel + timeout: 300, + workdir: join_paths(meson.current_build_dir(), '..', '..'), + env: env, + suite: ['fuzzing', 'slow'], +) + +test('draw_fuzzer', find_program('run-draw-fuzzer-tests.py'), + args: [ + hb_draw_fuzzer_exe, + ], + workdir: join_paths(meson.current_build_dir(), '..', '..'), + env: env, + suite: ['fuzzing'], +) diff --git a/test/fuzzing/run-draw-fuzzer-tests.py b/test/fuzzing/run-draw-fuzzer-tests.py new file mode 100644 index 0000000000000000000000000000000000000000..8b5a2e82d4e4e703189041f7fb0ce40c73d4a71a --- /dev/null +++ b/test/fuzzing/run-draw-fuzzer-tests.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +import sys, os, subprocess, tempfile, shutil + + +def cmd (command): + # https://stackoverflow.com/a/4408409 as we might have huge output sometimes + with tempfile.TemporaryFile () as tempf: + p = subprocess.Popen (command, stderr=tempf) + + try: + p.wait () + tempf.seek (0) + text = tempf.read () + + #TODO: Detect debug mode with a better way + is_debug_mode = b"SANITIZE" in text + + return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode + except subprocess.TimeoutExpired: + return 'error: timeout, ' + ' '.join (command), 1 + + +srcdir = os.getenv ("srcdir", ".") +EXEEXT = os.getenv ("EXEEXT", "") +top_builddir = os.getenv ("top_builddir", ".") +hb_draw_fuzzer = os.path.join (top_builddir, "hb-draw-fuzzer" + EXEEXT) + +if not os.path.exists (hb_draw_fuzzer): + if len (sys.argv) == 1 or not os.path.exists (sys.argv[1]): + sys.exit ("""Failed to find hb-draw-fuzzer binary automatically, +please provide it as the first argument to the tool""") + + hb_draw_fuzzer = sys.argv[1] + +print ('hb_draw_fuzzer:', hb_draw_fuzzer) +fails = 0 + +valgrind = None +if os.getenv ('RUN_VALGRIND', ''): + valgrind = shutil.which ('valgrind') + if valgrind is None: + sys.exit ("""Valgrind requested but not found.""") + +parent_path = os.path.join (srcdir, "fonts") +for file in os.listdir (parent_path): + if "draw" not in file: continue + path = os.path.join (parent_path, file) + + if valgrind: + text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_draw_fuzzer, path]) + else: + text, returncode = cmd ([hb_draw_fuzzer, path]) + if 'error' in text: + returncode = 1 + + if (not valgrind or returncode) and text.strip (): + print (text) + + if returncode != 0: + print ('failure on %s' % file) + fails = fails + 1 + + +if fails: + sys.exit ("%d draw fuzzer related tests failed." % fails) diff --git a/test/fuzzing/run-shape-fuzzer-tests.py b/test/fuzzing/run-shape-fuzzer-tests.py index 6d36c2cfe99041cd7d22f6ed4bf824e9c13fe219..382f60929c8bb374c7173bc7165259e64ebdf421 100755 --- a/test/fuzzing/run-shape-fuzzer-tests.py +++ b/test/fuzzing/run-shape-fuzzer-tests.py @@ -1,89 +1,53 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import - -import sys, os, subprocess, tempfile, threading - - -def which (program): - # https://stackoverflow.com/a/377028 - def is_exe (fpath): - return os.path.isfile (fpath) and os.access (fpath, os.X_OK) - - fpath, _ = os.path.split (program) - if fpath: - if is_exe (program): - return program - else: - for path in os.environ["PATH"].split (os.pathsep): - exe_file = os.path.join (path, program) - if is_exe (exe_file): - return exe_file - - return None +import sys, os, subprocess, tempfile, shutil def cmd (command): - # https://stackoverflow.com/a/4408409 - # https://stackoverflow.com/a/10012262 + # https://stackoverflow.com/a/4408409 as we might have huge output sometimes with tempfile.TemporaryFile () as tempf: p = subprocess.Popen (command, stderr=tempf) - is_killed = {'value': False} - - def timeout (p, is_killed): - is_killed['value'] = True - p.kill () - timer = threading.Timer (2, timeout, [p, is_killed]) try: - timer.start() p.wait () tempf.seek (0) - text = tempf.read ().decode ("utf-8").strip () - returncode = p.returncode - finally: - timer.cancel() + text = tempf.read () - if is_killed['value']: - text = 'error: timeout, ' + text - returncode = 1 + #TODO: Detect debug mode with a better way + is_debug_mode = b"SANITIZE" in text - return text, returncode + return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode + except subprocess.TimeoutExpired: + return 'error: timeout, ' + ' '.join (command), 1 -srcdir = os.environ.get ("srcdir", ".") -EXEEXT = os.environ.get ("EXEEXT", "") -top_builddir = os.environ.get ("top_builddir", ".") +srcdir = os.getenv ("srcdir", ".") +EXEEXT = os.getenv ("EXEEXT", "") +top_builddir = os.getenv ("top_builddir", ".") hb_shape_fuzzer = os.path.join (top_builddir, "hb-shape-fuzzer" + EXEEXT) if not os.path.exists (hb_shape_fuzzer): if len (sys.argv) == 1 or not os.path.exists (sys.argv[1]): - print ("""Failed to find hb-shape-fuzzer binary automatically, + sys.exit ("""Failed to find hb-shape-fuzzer binary automatically, please provide it as the first argument to the tool""") - sys.exit (1) hb_shape_fuzzer = sys.argv[1] print ('hb_shape_fuzzer:', hb_shape_fuzzer) fails = 0 -libtool = os.environ.get ('LIBTOOL') valgrind = None -if os.environ.get ('RUN_VALGRIND', ''): - valgrind = which ('valgrind') +if os.getenv ('RUN_VALGRIND', ''): + valgrind = shutil.which ('valgrind') if valgrind is None: - print ("""Valgrind requested but not found.""") - sys.exit (1) - if libtool is None: - print ("""Valgrind support is currently autotools only and needs libtool but not found.""") - + sys.exit ("""Valgrind requested but not found.""") parent_path = os.path.join (srcdir, "fonts") for file in os.listdir (parent_path): path = os.path.join (parent_path, file) if valgrind: - text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --error-exitcode=1', '--', hb_shape_fuzzer, path]) + text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_shape_fuzzer, path]) else: text, returncode = cmd ([hb_shape_fuzzer, path]) if 'error' in text: @@ -98,5 +62,4 @@ for file in os.listdir (parent_path): if fails: - print ("%i shape fuzzer related tests failed." % fails) - sys.exit (1) + sys.exit ("%d shape fuzzer related tests failed." % fails) diff --git a/test/fuzzing/run-subset-fuzzer-tests.py b/test/fuzzing/run-subset-fuzzer-tests.py index 820519f091a5cb076ac7be8d36eb091d9ce87b0e..da7d1e570b45fef48e1c6f08b1e1c2619306738b 100755 --- a/test/fuzzing/run-subset-fuzzer-tests.py +++ b/test/fuzzing/run-subset-fuzzer-tests.py @@ -1,82 +1,46 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import +import sys, os, subprocess, tempfile, shutil -import sys, os, subprocess, tempfile, threading - -def which(program): - # https://stackoverflow.com/a/377028 - def is_exe(fpath): - return os.path.isfile(fpath) and os.access(fpath, os.X_OK) - - fpath, _ = os.path.split(program) - if fpath: - if is_exe(program): - return program - else: - for path in os.environ["PATH"].split(os.pathsep): - exe_file = os.path.join(path, program) - if is_exe(exe_file): - return exe_file - - return None - - -def cmd(command): - # https://stackoverflow.com/a/4408409 - # https://stackoverflow.com/a/10012262 - with tempfile.TemporaryFile() as tempf: +def cmd (command): + # https://stackoverflow.com/a/4408409 as we might have huge output sometimes + with tempfile.TemporaryFile () as tempf: p = subprocess.Popen (command, stderr=tempf) - is_killed = {'value': False} - - def timeout(p, is_killed): - is_killed['value'] = True - p.kill() - timer = threading.Timer (16, timeout, [p, is_killed]) try: - timer.start() p.wait () tempf.seek (0) - text = tempf.read().decode ("utf-8").strip () - returncode = p.returncode - finally: - timer.cancel() + text = tempf.read () - if is_killed['value']: - text = 'error: timeout, ' + text - returncode = 1 + #TODO: Detect debug mode with a better way + is_debug_mode = b"SANITIZE" in text - return text, returncode + return ("" if is_debug_mode else text.decode ("utf-8").strip ()), p.returncode + except subprocess.TimeoutExpired: + return 'error: timeout, ' + ' '.join (command), 1 -srcdir = os.environ.get ("srcdir", ".") -EXEEXT = os.environ.get ("EXEEXT", "") -top_builddir = os.environ.get ("top_builddir", ".") +srcdir = os.getenv ("srcdir", ".") +EXEEXT = os.getenv ("EXEEXT", "") +top_builddir = os.getenv ("top_builddir", ".") hb_subset_fuzzer = os.path.join (top_builddir, "hb-subset-fuzzer" + EXEEXT) if not os.path.exists (hb_subset_fuzzer): if len (sys.argv) < 2 or not os.path.exists (sys.argv[1]): - print ("""Failed to find hb-subset-fuzzer binary automatically, + sys.exit ("""Failed to find hb-subset-fuzzer binary automatically, please provide it as the first argument to the tool""") - sys.exit (1) hb_subset_fuzzer = sys.argv[1] print ('hb_subset_fuzzer:', hb_subset_fuzzer) fails = 0 -libtool = os.environ.get('LIBTOOL') valgrind = None -if os.environ.get('RUN_VALGRIND', ''): - valgrind = which ('valgrind') +if os.getenv ('RUN_VALGRIND', ''): + valgrind = shutil.which ('valgrind') if valgrind is None: - print ("""Valgrind requested but not found.""") - sys.exit (1) - if libtool is None: - print ("""Valgrind support is currently autotools only and needs libtool but not found.""") - + sys.exit ("""Valgrind requested but not found.""") def run_dir (parent_path): global fails @@ -87,7 +51,7 @@ def run_dir (parent_path): print ("running subset fuzzer against %s" % path) if valgrind: - text, returncode = cmd (libtool.split(' ') + ['--mode=execute', valgrind + ' --leak-check=full --show-leak-kinds=all --error-exitcode=1', '--', hb_subset_fuzzer, path]) + text, returncode = cmd ([valgrind, '--leak-check=full', '--error-exitcode=1', hb_subset_fuzzer, path]) else: text, returncode = cmd ([hb_subset_fuzzer, path]) if 'error' in text: @@ -105,5 +69,4 @@ run_dir (os.path.join (srcdir, "..", "subset", "data", "fonts")) run_dir (os.path.join (srcdir, "fonts")) if fails: - print ("%i subset fuzzer related tests failed." % fails) - sys.exit (1) + sys.exit ("%d subset fuzzer related tests failed." % fails) diff --git a/test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 b/test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 new file mode 100644 index 0000000000000000000000000000000000000000..d8a39898e4bd3860ce5865fd005e51c83e37cea5 --- /dev/null +++ b/test/fuzzing/sets/clusterfuzz-testcase-minimized-hb-set-fuzzer-6255224052514816 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/fuzzing/sets/intersect_01 b/test/fuzzing/sets/intersect_01 new file mode 100644 index 0000000000000000000000000000000000000000..5b1e7e310c44b89847397517b5a374dd780dcccc Binary files /dev/null and b/test/fuzzing/sets/intersect_01 differ diff --git a/test/fuzzing/sets/subtract_01 b/test/fuzzing/sets/subtract_01 new file mode 100644 index 0000000000000000000000000000000000000000..1c60ac67f46c263ef6f909a595d7786e1e0a230e Binary files /dev/null and b/test/fuzzing/sets/subtract_01 differ diff --git a/test/fuzzing/sets/symmetric_diff_01 b/test/fuzzing/sets/symmetric_diff_01 new file mode 100644 index 0000000000000000000000000000000000000000..70801a7f67685406e02f467d7840c6b8c9061704 Binary files /dev/null and b/test/fuzzing/sets/symmetric_diff_01 differ diff --git a/test/fuzzing/sets/union_01 b/test/fuzzing/sets/union_01 new file mode 100644 index 0000000000000000000000000000000000000000..5a13eb0d68ffed1a31a79108b8fab95956e1ab52 Binary files /dev/null and b/test/fuzzing/sets/union_01 differ diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..c3a2002fd35a56d5f721ab0bf3cab4803a9f6ea8 --- /dev/null +++ b/test/meson.build @@ -0,0 +1,4 @@ +subdir('api') +subdir('fuzzing') +subdir('shaping') +subdir('subset') diff --git a/test/shaping/CMakeLists.txt b/test/shaping/CMakeLists.txt deleted file mode 100644 index 8e33edeec0e3655127a16b9511e7881c19c9338b..0000000000000000000000000000000000000000 --- a/test/shaping/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -if (HB_BUILD_UTILS) - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/in-house/Makefile.sources" INHOUSE) - extract_make_variable (TESTS ${INHOUSE}) - foreach (test IN ITEMS ${TESTS}) - add_test (NAME ${test} - COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $ "data/in-house/${test}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set_property (TEST ${test} PROPERTY SKIP_RETURN_CODE 77) - endforeach () - - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/aots/Makefile.sources" INHOUSE) - extract_make_variable (TESTS ${INHOUSE}) - foreach (test IN ITEMS ${TESTS}) - add_test (NAME ${test} - COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $ "data/aots/${test}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set_property (TEST ${test} PROPERTY SKIP_RETURN_CODE 77) - endforeach () - - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/text-rendering-tests/Makefile.sources" TEXTRENDERING) - extract_make_variable (TESTS ${TEXTRENDERING}) - foreach (test IN ITEMS ${TESTS}) - add_test (NAME ${test} - COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $ "data/text-rendering-tests/${test}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set_property (TEST ${test} PROPERTY SKIP_RETURN_CODE 77) - endforeach () -endif () diff --git a/test/shaping/Makefile.am b/test/shaping/Makefile.am index 66272da8e0fda76bc566aa2ae0a0a6f3b9f69eb1..316b173c8c211cc556807b7ae5151cc689bd4d4b 100644 --- a/test/shaping/Makefile.am +++ b/test/shaping/Makefile.am @@ -15,7 +15,7 @@ libs: EXTRA_DIST += \ README.md \ - CMakeLists.txt \ + meson.build \ hb-diff \ hb-diff-colorize \ hb-diff-filter-failures \ diff --git a/test/shaping/data/aots/Makefile.am b/test/shaping/data/aots/Makefile.am index 3b1faee5f885f5f1fdb6b2ca0a5e3a91dd6229ec..6b71d893bfea53bf83bf34b9b766ced19256ae8c 100644 --- a/test/shaping/data/aots/Makefile.am +++ b/test/shaping/data/aots/Makefile.am @@ -9,29 +9,19 @@ lib: EXTRA_DIST = \ COPYING \ fonts \ + update.py \ + meson.build \ $(TESTS) \ $(NULL) TEST_EXTENSIONS = .tests +if HAVE_FREETYPE +TESTS_ENVIRONMENT = HAVE_FREETYPE=1 +else +TESTS_ENVIRONMENT = HAVE_FREETYPE=0 +endif TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT) -init-aots: - git clone https://github.com/adobe-type-tools/aots $(srcdir)/aots - make -C$(srcdir)/aots - make -C$(srcdir)/aots/harfbuzz - touch $(srcdir)/init-aots - -update-tests: init-aots lib - cp $(srcdir)/hb-aots-tester.cpp $(srcdir)/aots/harfbuzz/hb-aots-tester.cpp - $(CXX) -Wno-narrowing $(srcdir)/aots/harfbuzz/hb-aots-tester.cpp \ - -I$(top_srcdir)/src/ -o $(srcdir)/aots/harfbuzz/aots \ - -L$(top_builddir)/src/.libs -lharfbuzz - rm -rf $(srcdir)/tests/ - mkdir $(srcdir)/tests/ - export LD_LIBRARY_PATH=$(realpath $(top_builddir)/src/.libs); cd $(srcdir)/aots/harfbuzz; ./aots - -.PHONY: update-tests - include Makefile.sources -include $(top_srcdir)/git.mk diff --git a/test/shaping/data/aots/hb-aots-tester.cpp b/test/shaping/data/aots/hb-aots-tester.cpp index bd46dec3641e5f3a4e34aeb6c0972574cda644d5..37079abc008bc2df4daa57dcf3e3a78633f0b29e 100644 --- a/test/shaping/data/aots/hb-aots-tester.cpp +++ b/test/shaping/data/aots/hb-aots-tester.cpp @@ -74,8 +74,8 @@ int gNbFeatures; features = (hb_feature_t *) malloc (sizeof (*features)); features[0].tag = HB_TAG('t', 'e', 's', 't'); features[0].value = 1; - features[0].start = 0; - features[0].end = 0xffffffff; + features[0].start = HB_FEATURE_GLOBAL_START; + features[0].end = HB_FEATURE_GLOBAL_END; } else { diff --git a/test/shaping/data/aots/meson.build b/test/shaping/data/aots/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..7e3c64b77d2c60fee2258414eff43d1b3e22e1e8 --- /dev/null +++ b/test/shaping/data/aots/meson.build @@ -0,0 +1,123 @@ +aots_tests = [ + 'classdef1_empty.tests', + 'classdef1_multiple.tests', + 'classdef1_single.tests', + 'classdef1.tests', + 'classdef2_empty.tests', + 'classdef2_multiple.tests', + 'classdef2_single.tests', + 'classdef2.tests', + 'gpos_chaining1_boundary.tests', + 'gpos_chaining1_lookupflag.tests', + 'gpos_chaining1_multiple_subrules.tests', + 'gpos_chaining1_next_glyph.tests', + 'gpos_chaining1_simple.tests', + 'gpos_chaining1_successive.tests', + 'gpos_chaining2_boundary.tests', + 'gpos_chaining2_lookupflag.tests', + 'gpos_chaining2_multiple_subrules.tests', + 'gpos_chaining2_next_glyph.tests', + 'gpos_chaining2_simple.tests', + 'gpos_chaining2_successive.tests', + 'gpos_chaining3_boundary.tests', + 'gpos_chaining3_lookupflag.tests', + 'gpos_chaining3_next_glyph.tests', + 'gpos_chaining3_simple.tests', + 'gpos_chaining3_successive.tests', + 'gpos_context1_boundary.tests', + 'gpos_context1_expansion.tests', + 'gpos_context1_lookupflag.tests', + 'gpos_context1_multiple_subrules.tests', + 'gpos_context1_next_glyph.tests', + 'gpos_context1_simple.tests', + 'gpos_context1_successive.tests', + 'gpos_context2_boundary.tests', + 'gpos_context2_classes.tests', + 'gpos_context2_expansion.tests', + 'gpos_context2_lookupflag.tests', + 'gpos_context2_multiple_subrules.tests', + 'gpos_context2_next_glyph.tests', + 'gpos_context2_simple.tests', + 'gpos_context2_successive.tests', + 'gpos_context3_boundary.tests', + 'gpos_context3_lookupflag.tests', + 'gpos_context3_next_glyph.tests', + 'gpos_context3_simple.tests', + 'gpos_context3_successive.tests', + 'gpos1_1_lookupflag.tests', + 'gpos1_1_simple.tests', + 'gpos1_2_lookupflag.tests', + 'gpos1_2.tests', + 'gpos2_1_lookupflag.tests', + 'gpos2_1_next_glyph.tests', + 'gpos2_1_simple.tests', + 'gpos2_1.tests', + 'gpos2_2.tests', + 'gpos3_lookupflag.tests', + 'gpos3.tests', + 'gpos4_lookupflag.tests', + 'gpos4_multiple_anchors.tests', + 'gpos4_simple.tests', + 'gpos5.tests', + 'gpos6.tests', + 'gpos7_1.tests', + 'gpos9.tests', + 'gsub_chaining1_boundary.tests', + 'gsub_chaining1_lookupflag.tests', + 'gsub_chaining1_multiple_subrules.tests', + 'gsub_chaining1_next_glyph.tests', + 'gsub_chaining1_simple.tests', + 'gsub_chaining1_successive.tests', + 'gsub_chaining2_boundary.tests', + 'gsub_chaining2_lookupflag.tests', + 'gsub_chaining2_multiple_subrules.tests', + 'gsub_chaining2_next_glyph.tests', + 'gsub_chaining2_simple.tests', + 'gsub_chaining2_successive.tests', + 'gsub_chaining3_boundary.tests', + 'gsub_chaining3_lookupflag.tests', + 'gsub_chaining3_next_glyph.tests', + 'gsub_chaining3_simple.tests', + 'gsub_chaining3_successive.tests', + 'gsub_context1_boundary.tests', + 'gsub_context1_expansion.tests', + 'gsub_context1_lookupflag.tests', + 'gsub_context1_multiple_subrules.tests', + 'gsub_context1_next_glyph.tests', + 'gsub_context1_simple.tests', + 'gsub_context1_successive.tests', + 'gsub_context2_boundary.tests', + 'gsub_context2_classes.tests', + 'gsub_context2_expansion.tests', + 'gsub_context2_lookupflag.tests', + 'gsub_context2_multiple_subrules.tests', + 'gsub_context2_next_glyph.tests', + 'gsub_context2_simple.tests', + 'gsub_context2_successive.tests', + 'gsub_context3_boundary.tests', + 'gsub_context3_lookupflag.tests', + 'gsub_context3_next_glyph.tests', + 'gsub_context3_simple.tests', + 'gsub_context3_successive.tests', + 'gsub1_1_lookupflag.tests', + 'gsub1_1_modulo.tests', + 'gsub1_1_simple.tests', + 'gsub1_2_lookupflag.tests', + 'gsub1_2_simple.tests', + 'gsub2_1_lookupflag.tests', + 'gsub2_1_multiple_sequences.tests', + 'gsub2_1_simple.tests', + 'gsub3_1_lookupflag.tests', + 'gsub3_1_multiple.tests', + 'gsub3_1_simple.tests', + 'gsub4_1_lookupflag.tests', + 'gsub4_1_multiple_ligatures.tests', + 'gsub4_1_multiple_ligsets.tests', + 'gsub4_1_simple.tests', + 'gsub7.tests', + 'lookupflag_ignore_attach.tests', + 'lookupflag_ignore_base.tests', + 'lookupflag_ignore_combination.tests', + 'lookupflag_ignore_ligatures.tests', + 'lookupflag_ignore_marks.tests', +] diff --git a/test/shaping/data/aots/update.py b/test/shaping/data/aots/update.py new file mode 100644 index 0000000000000000000000000000000000000000..870c9d1f6f6d20f2d8af098f3bcbb5149aedc874 --- /dev/null +++ b/test/shaping/data/aots/update.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +import sys, os, subprocess, shutil + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +git = shutil.which ('git'); assert git +make = shutil.which ('make'); assert make +java = shutil.which ('java'); assert java +gcc = shutil.which ('gcc'); assert gcc + +pull = False +if not os.path.exists ('aots'): + subprocess.run ([git, 'clone', 'https://github.com/adobe-type-tools/aots'], check=True) + pull = True + +if pull or 'pull' in sys.argv: + subprocess.run ([git, 'pull'], cwd='aots', check=True) + subprocess.run ([make, '-C', 'aots'], check=True) + subprocess.run ([make, '-C', 'aots/harfbuzz'], check=True) + +shutil.copy ('hb-aots-tester.cpp', 'aots/harfbuzz') +# TODO: remove *nix assumptions +subprocess.run ([gcc, '-Wno-narrowing', 'aots/harfbuzz/hb-aots-tester.cpp', + '../../../../src/harfbuzz.cc', '-DHB_NO_MT', '-fno-exceptions', '-lm', + '-I../../../../src', '-o', 'aots/harfbuzz/aots'], check=True) +shutil.rmtree ('tests') +os.mkdir ('tests') +subprocess.run (['./aots'], cwd='aots/harfbuzz', check=True) diff --git a/test/shaping/data/in-house/Makefile.am b/test/shaping/data/in-house/Makefile.am index 8a2a07657115d05f3422e5e770ad31ac9b805523..a2845785e683a7956e78ce3a069f5fe1410ff7dc 100644 --- a/test/shaping/data/in-house/Makefile.am +++ b/test/shaping/data/in-house/Makefile.am @@ -9,10 +9,16 @@ lib: EXTRA_DIST = \ COPYING \ fonts \ + meson.build \ $(TESTS) \ $(NULL) TEST_EXTENSIONS = .tests +if HAVE_FREETYPE +TESTS_ENVIRONMENT = HAVE_FREETYPE=1 +else +TESTS_ENVIRONMENT = HAVE_FREETYPE=0 +endif TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT) include Makefile.sources diff --git a/test/shaping/data/in-house/Makefile.sources b/test/shaping/data/in-house/Makefile.sources index bf14a98c6679af4d422bd1ff71fca8dc3b7fb369..b3fdca274841d6439ba003ee7534b00c10529727 100644 --- a/test/shaping/data/in-house/Makefile.sources +++ b/test/shaping/data/in-house/Makefile.sources @@ -1,6 +1,6 @@ TESTS = \ - tests/aat-trak.tests \ tests/aat-morx.tests \ + tests/aat-trak.tests \ tests/arabic-fallback-shaping.tests \ tests/arabic-feature-order.tests \ tests/arabic-like-joining.tests \ @@ -38,22 +38,27 @@ TESTS = \ tests/mark-attachment.tests \ tests/mark-filtering-sets.tests \ tests/mongolian-variation-selector.tests \ + tests/myanmar-misc.tests \ tests/myanmar-syllable.tests \ tests/myanmar-zawgyi.tests \ tests/none-directional.tests \ tests/positioning-features.tests \ tests/rand.tests \ - tests/spaces.tests \ + tests/reverse-sub.tests \ + tests/rotation.tests \ tests/simple.tests \ tests/sinhala.tests \ + tests/spaces.tests \ tests/tibetan-contractions-1.tests \ tests/tibetan-contractions-2.tests \ tests/tibetan-vowels.tests \ - tests/use.tests \ tests/use-indic3.tests \ tests/use-marchen.tests \ tests/use-syllable.tests \ + tests/use.tests \ + tests/variations-rounding.tests \ tests/variations-rvrn.tests \ + tests/variations-space.tests \ tests/vertical.tests \ tests/zero-width-marks.tests \ $(NULL) diff --git a/test/shaping/data/in-house/fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf b/test/shaping/data/in-house/fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf new file mode 100644 index 0000000000000000000000000000000000000000..46ebee86f35911bb9efbccc4dc714e0141dedb48 Binary files /dev/null and b/test/shaping/data/in-house/fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf differ diff --git a/test/shaping/data/in-house/fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf b/test/shaping/data/in-house/fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4d0f52adc0b69e97c534e545db95885f9c7d245d Binary files /dev/null and b/test/shaping/data/in-house/fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf differ diff --git a/test/shaping/data/in-house/fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf b/test/shaping/data/in-house/fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf new file mode 100644 index 0000000000000000000000000000000000000000..952d40a44839db3ff414b7060d4713130e12a623 Binary files /dev/null and b/test/shaping/data/in-house/fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf differ diff --git a/test/shaping/data/in-house/fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf b/test/shaping/data/in-house/fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f1e07f2c80056459fc08099cfc16984a2d4ee937 Binary files /dev/null and b/test/shaping/data/in-house/fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf differ diff --git a/test/shaping/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf b/test/shaping/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf new file mode 100644 index 0000000000000000000000000000000000000000..395f423691eabc744fe7cb5a351d5ee850bb529b Binary files /dev/null and b/test/shaping/data/in-house/fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf differ diff --git a/test/shaping/data/in-house/fonts/HBTest-VF.ttf b/test/shaping/data/in-house/fonts/HBTest-VF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..01c223088a422c4f274467ffa12fe228fac8b23c Binary files /dev/null and b/test/shaping/data/in-house/fonts/HBTest-VF.ttf differ diff --git a/test/shaping/data/in-house/fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf b/test/shaping/data/in-house/fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d217bad0edb5f961932ac4c3a7adc87a9cbb8e6 Binary files /dev/null and b/test/shaping/data/in-house/fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf differ diff --git a/test/shaping/data/in-house/fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf b/test/shaping/data/in-house/fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a82aa21654766e4aaa42cb18168939d525336317 Binary files /dev/null and b/test/shaping/data/in-house/fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf differ diff --git a/test/shaping/data/in-house/fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf b/test/shaping/data/in-house/fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4d0b3cdea9dd7011ec56376cc138244cf38c178d Binary files /dev/null and b/test/shaping/data/in-house/fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf differ diff --git a/test/shaping/data/in-house/fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf b/test/shaping/data/in-house/fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c86787776e90ffde661db110702cc1199df58cdb Binary files /dev/null and b/test/shaping/data/in-house/fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf differ diff --git a/test/shaping/data/in-house/meson.build b/test/shaping/data/in-house/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..0bd1a9dcdaa2870a07404a43e843c3b71dbb2fcf --- /dev/null +++ b/test/shaping/data/in-house/meson.build @@ -0,0 +1,64 @@ +in_house_tests = [ + 'aat-morx.tests', + 'aat-trak.tests', + 'arabic-fallback-shaping.tests', + 'arabic-feature-order.tests', + 'arabic-like-joining.tests', + 'arabic-mark-attach.tests', + 'arabic-mark-order.tests', + 'arabic-stch.tests', + 'automatic-fractions.tests', + 'cluster.tests', + 'collections.tests', + 'color-fonts.tests', + 'context-matching.tests', + 'cursive-positioning.tests', + 'default-ignorables.tests', + 'emoji.tests', + 'fallback-positioning.tests', + 'hangul-jamo.tests', + 'hyphens.tests', + 'indic-consonant-with-stacker.tests', + 'indic-decompose.tests', + 'indic-init.tests', + 'indic-joiner-candrabindu.tests', + 'indic-joiners.tests', + 'indic-old-spec.tests', + 'indic-pref-blocking.tests', + 'indic-script-extensions.tests', + 'indic-special-cases.tests', + 'indic-syllable.tests', + 'indic-vowel-letter-spoofing.tests', + 'kern-format2.tests', + 'khmer-mark-order.tests', + 'khmer-misc.tests', + 'language-tags.tests', + 'ligature-id.tests', + 'macos.tests', + 'mark-attachment.tests', + 'mark-filtering-sets.tests', + 'mongolian-variation-selector.tests', + 'myanmar-misc.tests', + 'myanmar-syllable.tests', + 'myanmar-zawgyi.tests', + 'none-directional.tests', + 'positioning-features.tests', + 'rand.tests', + 'reverse-sub.tests', + 'rotation.tests', + 'simple.tests', + 'sinhala.tests', + 'spaces.tests', + 'tibetan-contractions-1.tests', + 'tibetan-contractions-2.tests', + 'tibetan-vowels.tests', + 'use-indic3.tests', + 'use-marchen.tests', + 'use-syllable.tests', + 'use.tests', + 'variations-rounding.tests', + 'variations-rvrn.tests', + 'variations-space.tests', + 'vertical.tests', + 'zero-width-marks.tests', +] diff --git a/test/shaping/data/in-house/tests/cluster.tests b/test/shaping/data/in-house/tests/cluster.tests index 928843f0fc37bfdeda34d8c6abbe95d2768ee260..f1889900b0574ce3c855a4c3ff8cbd1105e35d83 100644 --- a/test/shaping/data/in-house/tests/cluster.tests +++ b/test/shaping/data/in-house/tests/cluster.tests @@ -1,2 +1,3 @@ ../fonts/4fac3929fc3332834e93673780ec0fe94342d193.ttf:--cluster-level=2:U+0078,U+030A,U+0058,U+030A:[gid2=0+1083|gid3=1@-1132,-8+0|gid1=2+1200|gid3=3@-1190,349+0] ../fonts/43ef465752be9af900745f72fe29cb853a1401a5.ttf:--cluster-level=1:U+05D4,U+05B7,U+05E9,U+05BC,U+05C1,U+05B8,U+05DE,U+05B4,U+05DD:[uni05DD=8+1359|uni05B4=7@111,0+0|uni05DE=6+1391|uni05B8=5+0|uni05BC=3+0|uni05C1=3+0|uni05E9=2+1451|uni05B7=1@28,0+0|uni05D4=0+1338] +../fonts/6f36d056bad6d478fc0bf7397bd52dc3bd197d5f.ttf:--cluster-level=1:U+099B,U+09CB,U+09C8,U+09C2,U+09CB,U+098C:[evowelsigninibeng=0+346|aivowelsignbeng=0+346|evowelsignbeng=0+346|chabeng=0+687|uuvowelsignlongbeng=0@-96,0+0|aavowelsignbeng=0+266|aavowelsignbeng=4+266|lvocalicbeng=5+639] diff --git a/test/shaping/data/in-house/tests/default-ignorables.tests b/test/shaping/data/in-house/tests/default-ignorables.tests index a27b67a68412af352063c8f64c79ae016365003c..69e549a12b3701019d5225095d7c226e2f99da26 100644 --- a/test/shaping/data/in-house/tests/default-ignorables.tests +++ b/test/shaping/data/in-house/tests/default-ignorables.tests @@ -1,2 +1,5 @@ ../fonts/051d92f8bc6ff724511b296c27623f824de256e9.ttf::U+0075,U+0361,U+034F,U+0301,U+0069:[gid2=0+1266|gid7=0@-617,442+0|gid5=0@-7,0+0|gid1=4+528] ../fonts/bf962d3202883a820aed019d9b5c1838c2ff69c6.ttf::U+0020,U+06CC,U+064E,U+034F,U+0651:[uni0651=1+0|space=1+0|uni064E=1@236,-432+0|uni06CC=1+1266|space=0+452] +../fonts/6677074106f94a2644da6aaaacd5bbd48cbdc7de.ttf::U+0647,U+200D:[terminal=0+0|uni0647.init=0+702] +../fonts/fcea341ba6489536390384d8403ce5287ba71a4a.ttf::U+0647,U+200D:[uni0647200D=0+702] +../fonts/08b4b136f418add748dc641eb4a83033476f1170.ttf::U+0647,U+200D:[terminal=0+0|terminal=0+0|uni0647.init=0+702] diff --git a/test/shaping/data/in-house/tests/indic-joiners.tests b/test/shaping/data/in-house/tests/indic-joiners.tests index 80e392cfc789cd7d456eb96d1a3e6dd9c12427d6..455742d1ed977c5db8e1c937f8349f2088dc3151 100644 --- a/test/shaping/data/in-house/tests/indic-joiners.tests +++ b/test/shaping/data/in-house/tests/indic-joiners.tests @@ -1,6 +1,6 @@ ../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+200C,U+17CA,U+17B8,U+0020:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|space=4+0|uni17ca=4+0|uni17b8=4@0,300+0|space=7+600] ../fonts/f443753e8ffe8e8aae606cfba158e00334b6efb1.ttf::U+179A,U+1784,U+17D2,U+179F,U+17CA,U+17B8:[uni179a=0+775|uni1784=1+1550|uni179f.sub=1+775|uni17bb=1@-75,-700+0|uni17b8=1+0] -../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=2+0|uni093F.750=3+397|uni092F=3+924] -../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924] -../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=5+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924] -../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf:--font-funcs=ft:U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924] +../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf::U+091F,U+094D,U+200C,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=2+0|uni093F.750=3+397|uni092F=3+924] +../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf::U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924] +../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf::U+091F,U+094D,U+200D,U+091F,U+094D,U+200C,U+091F,U+094D,U+200D,U+092F,U+093F:[uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=3+876|uni094D=3@4,0+0|space=5+0|uni093F=6+398|uni091F=6+876|uni094D=6@4,0+0|space=6+0|uni092F=6+924] +../fonts/8116e5d8fedfbec74e45dc350d2416d810bed8c4.ttf::U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+091F,U+094D,U+200D,U+092F,U+093F:[uni093F=0+398|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni091F=0+876|uni094D=0@4,0+0|space=0+0|uni092F=0+924] diff --git a/test/shaping/data/in-house/tests/indic-syllable.tests b/test/shaping/data/in-house/tests/indic-syllable.tests index 264983bf0e7e4d4e55aa2c2cc22f1e408e3bda08..ff80aaf46529d6b030f7be4bc83671d5f5144d6a 100644 --- a/test/shaping/data/in-house/tests/indic-syllable.tests +++ b/test/shaping/data/in-house/tests/indic-syllable.tests @@ -8,3 +8,5 @@ ../fonts/81c368a33816fb20e9f647e8f24e2180f4720263.ttf:--no-glyph-names:U+0C80,U+0C82:[1=0+502|2=0+502] ../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf::U+0A20,U+0A75,U+0A47:[tthaguru=0+1352|yakashguru=0@-90,0+0|eematraguru=0@-411,0+0] ../fonts/f75c4b05a0a4d67c1a808081ae3d74a9c66509e8.ttf::U+0A20,U+0A75,U+0A42:[tthaguru=0+1352|yakashuuguru=0+0] +../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf::U+0B2C,U+0B55,U+0B3E:[uni0B2C=0+641|uni0B55=0+0|uni0B3E=0+253] +../fonts/b3075ca42b27dde7341c2d0ae16703c5b6640df0.ttf::U+0B2C,U+0B3E,U+0B55:[uni0B2C=0+641|uni0B3E=0+253|uni0B55=0+0] diff --git a/test/shaping/data/in-house/tests/macos.tests b/test/shaping/data/in-house/tests/macos.tests index 434e0a5bf444f953c6a6610a2d4bb23561d7380c..ffd533e8f01cd970e7d86767c3daeace66a21409 100644 --- a/test/shaping/data/in-house/tests/macos.tests +++ b/test/shaping/data/in-house/tests/macos.tests @@ -1,3 +1,6 @@ +# https://github.com/harfbuzz/harfbuzz/pull/2871 +/System/Library/Fonts/LucidaGrande.ttc:--font-funcs ot --show-flags:U+0041,U+0042,U+0043,U+0044:[A=0+1413|B=1+1178|C=2+1417|D=3+1534] + # 10.12.6 https://gist.github.com/ebraminio/1704341fa16b06979e605aafd88198cf /System/Library/Fonts/Helvetica.dfont@c7bec2785a4c402b7809b5e35337c3d24c18e281:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0] /System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+006D,U+0300:[mgrave=0+1912] @@ -8,14 +11,28 @@ /System/Library/Fonts/LucidaGrande.ttc@d89a9d7e57767bfe3b5a4cfd22bb1e9dbe03a062:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361] /Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098] /Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006] -/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] +/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656] /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700] /System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165] +/System/Library/Fonts/GeezaPro.ttc@f43ee7151c2e9f1dddfbc26cfc148609eb5c5820:--font-funcs ot:U+0644,U+064E,U+0645,U+064E,U+0651,U+0627:[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415] /System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0+1105|gid584=1@-105,0+979|gid3=2+490|gid4=3+1227|gid265=4@-65,0+1227|gid3=5+490|gid225=6+1130|gid728=7@-80,0+569|gid3=8+490|gid265=9+1227|gid505=10@-65,0+997|gid3=11+490|gid728=12+609|gid225=13@-40,0+1170|gid3=14+490|gid584=15+1004|gid225=16@-80,0+1130|gid3=17+490|gid225=18+1105|gid576=19@-105,0+1068] /System/Library/Fonts/SFNSDisplay.ttf@92787c30716672737e9059bc367c15d04fbc1ced:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid225=0@65,0+1235|gid584=1@-40,0+1109|gid3=2@65,0+620|gid4=3@65,0+1357|gid265=4+1357|gid3=5@65,0+620|gid225=6@65,0+1260|gid728=7@-15,0+699|gid3=8@65,0+620|gid265=9@65,0+1357|gid505=10+1127|gid3=11@65,0+620|gid728=12@65,0+739|gid225=13@25,0+1300|gid3=14@65,0+620|gid584=15@65,0+1134|gid225=16@-15,0+1260|gid3=17@65,0+620|gid225=18@65,0+1235|gid576=19@-40,0+1198] /System/Library/Fonts/Apple Color Emoji.ttc@d2fe8a134483aa48a43a9d1e4b7204d37a4abdf5:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800] /Library/Fonts/Zapfino.ttf@9ee799ffb09516ead6b0cf6f2ca807276e150748:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333] +# https://github.com/harfbuzz/harfbuzz/pull/2130 +/System/Library/Fonts/ヒラギノ明朝 ProN W3.ttc@e3bd65c7209ceab2c70ef22d3ebe0967ab319ed3:--font-funcs ot --direction=ttb:U+005B,U+0048,U+0065,U+006C,U+006C,U+006F,U+0034,U+005D:[gid60=0@-157,-880+0,-1000|gid41=1@-398,-880+0,-1000|gid70=2@-267,-880+0,-1000|gid77=3@-148,-880+0,-1000|gid77=4@-148,-880+0,-1000|gid80=5@-291,-880+0,-1000|gid21=6@-294,-880+0,-1000|gid62=7@-157,-880+0,-1000] +/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot:U+0066,U+0069,U+006e,U+0065:[fi=0+1139|n=2+1024|e=3+909] +/System/Library/Fonts/Times.dfont@39c954614d3f3317b28564db06d5b7b7a6ff0e39:--font-funcs ot --features liga=0:U+0066,U+0069,U+006e,U+0065:[f=0+682|i=1+569|n=2+1024|e=3+909] +/Library/Fonts/Kokonor.ttf@fe9d518bb4e20e77f7a0444c82f4d41467dd714d:--font-funcs ot:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/Library/Fonts/Kokonor.ttf@fe9d518bb4e20e77f7a0444c82f4d41467dd714d:--font-funcs ot --features liga=0:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot --features dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot --features liga=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot --features dlig=1,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot --features liga=0,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot --features smcp=1:U+0066,U+0069,U+0072,U+0073,U+0074:[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075] +/Library/Fonts/Apple Chancery.ttf@5fc49ae9bce39e2105864323183b68ea34c9e562:--font-funcs ot --features liga=0,dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s_t=3+1438] # 10.13.6 https://gist.github.com/ebraminio/d432e831b3f7ebe30245dde5775e1c7e /System/Library/Fonts/Helvetica.ttc@8a928f9866299d2455f41360202b7a3b48503a5e:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0] @@ -27,14 +44,27 @@ /System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361] /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098] /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006] -/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656] /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700] /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0644,U+064E,U+0645,U+064E,U+0651,U+0627:[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415] /System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0+1055|gid658=1@-135,0+914|gid3=2+420|gid4=3+1227|gid332=4@-65,0+1227|gid3=5+420|gid282=6+1075|gid813=7@-115,0+516|gid3=8+420|gid332=9+1217|gid572=10@-75,0+953|gid3=11+420|gid813=12+546|gid282=13@-85,0+1105|gid3=14+420|gid658=15+914|gid282=16@-135,0+1055|gid3=17+420|gid282=18+1055|gid649=19@-135,0+999] /System/Library/Fonts/SFNSDisplay.ttf@c8948f464ff822a5f9bbf2e12d0e4e32268815aa:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid282=0@65,0+1185|gid658=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid332=4+1357|gid3=5@65,0+550|gid282=6@65,0+1205|gid813=7@-50,0+646|gid3=8@65,0+550|gid332=9@65,0+1347|gid572=10@-10,0+1083|gid3=11@65,0+550|gid813=12@65,0+676|gid282=13@-20,0+1235|gid3=14@65,0+550|gid658=15@65,0+1044|gid282=16@-70,0+1185|gid3=17@65,0+550|gid282=18@65,0+1185|gid649=19@-70,0+1129] /System/Library/Fonts/Apple Color Emoji.ttc@2e09b1f3d42c3821cc6c4ac5b6ce16237ab0d496:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800] /Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333] +/System/Library/Fonts/Thonburi.ttc@bb080e01e45f7f6699d2df09a03b3b6d13804897:--font-funcs ot:U+0E17,U+0E35,U+0E48,U+0E4A:[thothahanthai_saraiithai_maiekthai=0+1616|maitrithai.key=0+1300] +/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot:U+0066,U+0069,U+006e,U+0065:[fi=0+1139|n=2+1024|e=3+909] +/System/Library/Fonts/Times.ttc@896098b6979306ad84355025459f7c68b029139c:--font-funcs ot --features liga=0:U+0066,U+0069,U+006e,U+0065:[f=0+682|i=1+569|n=2+1024|e=3+909] +/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4:--font-funcs ot:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4:--font-funcs ot --features liga=0:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features dlig=1,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features smcp=1:U+0066,U+0069,U+0072,U+0073,U+0074:[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0,dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s_t=3+1438] # 10.14.2 https://gist.github.com/ebraminio/4b731a82f11a662b2164622ebb93086a /System/Library/Fonts/Helvetica.ttc@992d29a0fa4ed91773457c29b661e94843619cde:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0] @@ -46,11 +76,59 @@ /System/Library/Fonts/LucidaGrande.ttc@63ba1b1de4709bd832ca76bd62368dd99fc34269:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361] /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098] /Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006] -/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-252,120+-252|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656] /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700] /System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0644,U+064E,U+0645,U+064E,U+0651,U+0627:[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415] /System/Library/Fonts/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid283=0+1055|gid659=1@-135,0+914|gid3=2+420|gid4=3+1227|gid333=4@-65,0+1227|gid3=5+420|gid283=6+1075|gid815=7@-115,0+516|gid3=8+420|gid333=9+1217|gid573=10@-75,0+953|gid3=11+420|gid815=12+546|gid283=13@-85,0+1105|gid3=14+420|gid659=15+914|gid283=16@-135,0+1055|gid3=17+420|gid283=18+1055|gid650=19@-135,0+999] /System/Library/Fonts/SFNSDisplay.ttf@6e9677c443f6583228a63fd147663cfc635924d9:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[gid283=0@65,0+1185|gid659=1@-70,0+1044|gid3=2@65,0+550|gid4=3@65,0+1357|gid333=4+1357|gid3=5@65,0+550|gid283=6@65,0+1205|gid815=7@-50,0+646|gid3=8@65,0+550|gid333=9@65,0+1347|gid573=10@-10,0+1083|gid3=11@65,0+550|gid815=12@65,0+676|gid283=13@-20,0+1235|gid3=14@65,0+550|gid659=15@65,0+1044|gid283=16@-70,0+1185|gid3=17@65,0+550|gid283=18@65,0+1185|gid650=19@-70,0+1129] /System/Library/Fonts/Apple Color Emoji.ttc@60f77161021b1b87e99c3690e1a9b56341cf8792:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800] /Library/Fonts/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333] +/System/Library/Fonts/Thonburi.ttc@bb080e01e45f7f6699d2df09a03b3b6d13804897:--font-funcs ot:U+0E17,U+0E35,U+0E48,U+0E4A:[thothahanthai_saraiithai_maiekthai=0+1616|maitrithai.key=0+1300] +/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518:--font-funcs ot:U+0066,U+0069,U+006e,U+0065:[fi=0+1139|n=2+1024|e=3+909] +/System/Library/Fonts/Times.ttc@ebb050e4fcaaebe9992efbc7b5660b60ba18b518:--font-funcs ot --features liga=0:U+0066,U+0069,U+006e,U+0065:[f=0+682|i=1+569|n=2+1024|e=3+909] +/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4:--font-funcs ot:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/Library/Fonts/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4:--font-funcs ot --features liga=0:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features dlig=1,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features smcp=1:U+0066,U+0069,U+0072,U+0073,U+0074:[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075] +/Library/Fonts/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0,dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s_t=3+1438] + +# 10.15 https://gist.github.com/ebraminio/d52dd780fec59f8e2dfffe8e1a841823 +/System/Library/Fonts/Helvetica.ttc@98c12f0d63168b20635fb51d638929753b4e6aed:--font-funcs ot:U+006D,U+0300:[m=0+1706|gravecmb=0@-284,10+0] +/System/Library/Fonts/LucidaGrande.ttc@b2b9aa73d0d9ddabbe73549949fc7444b8528cc2:--font-funcs ot:U+006D,U+0300:[mgrave=0+1912] +/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb:--font-funcs ot:U+0066,U+0069:[fi=0+1139] +/System/Library/Fonts/Supplemental/Khmer MN.ttc@37687fe0bd2548e08e29c92a30e476367ae6356b:--font-funcs ot:U+17A2,U+1780,U+17D2,U+179F,U+179A,U+1781,U+17D2,U+1798,U+17C2,U+179A:[km_qa=0+1230|km_ka=1+1230|km_sa.sub=1+620|km_ro=4+712|km_vs_ae=5+726|km_kha=5+1230|km_mo.sub=5+0|km_ro=9+712] +/System/Library/Fonts/Supplemental/Tamil MN.ttc@e1df5e056be08937fd65990efbafff0814c03677:--font-funcs ot:U+0BA4,U+0BCA,U+0B95,U+0BC1,U+0B95,U+0BCD,U+0B95,U+0BAA,U+0BCD,U+0BAA,U+0B9F,U+0BCD,U+0B9F,U+0BC1:[tgm_e=0+1702|tgc_ta=0+1598|tgm_aa=0+1149|tgc_ku=2+1962|tgc_k=4+1592|tgc_ka=6+1592|tgc_p=7+1370|tgc_pa=9+1370|tgc_tt=10+1596|tgc_ttu=12+1833] +/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb:--font-funcs ot:U+0041,U+0066,U+0300,U+0066,U+0069,U+005A:[A=0+1479|f=1+682|gravecmb=1@-551,588+0|fi=3+1139|Z=5+1251] +/System/Library/Fonts/LucidaGrande.ttc@b2b9aa73d0d9ddabbe73549949fc7444b8528cc2:--font-funcs ot:U+05E1,U+05B0:[shevahebrew=0@51,0+0|samekhhebrew=0+1361] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0068,U+0020,U+0074,U+0068,U+0020,U+006C,U+006C,U+0020,U+0074,U+0065,U+0020,U+0074,U+006F,U+0020,U+0074,U+0072,U+0020,U+0066,U+0072,U+0020,U+0066,U+0075,U+0020,U+0066,U+006A:[T_h=0+2308|space=2+569|t_h=3+1687|space=5+569|l_l=6+1108|space=8+569|t_e=9+1408|space=11+569|t_o=12+1531|space=14+569|t_r=15+1385|space=17+569|f_r=18+1432|space=20+569|f_u=21+1733|space=23+569|f_j=24+1098] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+1497|e=1@-62,0+699|space=2+569|A=3+1431|V=4@-37,0+1377|space=5+569|T=6+1510|r=7@-50,0+803|space=8+569|V=9+1376|a=10@-37,0+1014|space=11+569|r=12+853|T=13+1560|space=14+569|e=15+761|T=16+1560|space=17+569|T=18+1515|d=19@-45,0+1006] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0627,U+0644,U+0623,U+064E,U+0628,U+0652,U+062C,U+064E,U+062F,U+0650,U+064A,U+064E,U+0651,U+0629,U+0640,U+0627,U+0644,U+0639,U+064E,U+0631,U+064E,U+0628,U+0650,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=26+713|u064e_u0651.shaddaFatha=23@0,-200+0|u064a.medial.yeh=23+656|u0650.kasra=21@80,290+80|u0628.initial.beh=21@-80,0+576|u064e.fatha=19@200,-570+200|u0631.final.reh=19@-200,0+702|u064e.fatha=17@200,-200+200|u0639.medial.ain=17@-200,0+738|u0644.initial.lam=16+515|u0627.final.alef=15+647|u0640.tatweel=14+449|u0629.final.tehMarbuta=13+713|u064e_u0651.shaddaFatha=10@0,-200+0|u064a.initial.yeh=10+656|u0650.kasra=8@80,570+80|u062f.final.dal=8@-80,0+822|u064e.fatha=6@290,-160+290|u062c.medial.jeem=6@-290,0+1069|u0652.sukun=4@0,-200+0|u0628.initial.beh=4+656|u064e.fatha=1@-372,120+-372|u0644_u0623.isolated.lamHamzaOnAlef=1@120,0+1282|u0627.alef=0+647] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064A,U+064E,U+0651,U+0629:[u0629.final.tehMarbuta=4+713|u064e_u0651.shaddaFatha=1@0,-200+0|u064a.medial.yeh=1+656|u0628.initial.beh=0+656] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0631,U+0628:[u0628.beh=1+1415|u0631.reh=0@-202,0+700] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0628,U+064F:[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165] +/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334:--font-funcs ot:U+0644,U+064E,U+0645,U+064E,U+0651,U+0627:[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415] +# SFNS uses opsz variation axis which isn't invoked here, see https://crbug.com/1005969#c37 +/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c:--font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0+920|e=1+1049|space=2+420|A=3+1162|V=4+1292|space=5+420|T=6+960|r=7+631|space=8+420|V=9+1142|a=10+1028|space=11+420|r=12+461|T=13+1190|space=14+420|e=15+779|T=16+1190|space=17+420|T=18+920|d=19+1134] +/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c:--font-ptem 9 --font-funcs ot:U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064:[T=0@19,0+958|e=1@19,0+1087|space=2@19,0+458|A=3@19,0+1200|V=4@19,0+1330|space=5@19,0+458|T=6@19,0+998|r=7@19,0+669|space=8@19,0+458|V=9@19,0+1180|a=10@19,0+1066|space=11@19,0+458|r=12@19,0+499|T=13@19,0+1228|space=14@19,0+458|e=15@19,0+817|T=16@19,0+1228|space=17@19,0+458|T=18@19,0+958|d=19@19,0+1172] +/System/Library/Fonts/Apple Color Emoji.ttc@ef22d55c551e2af0193d75105346c6e7e21af389:--remove-default-ignorables --font-funcs ot:U+1F468,U+200D,U+1F469,U+200D,U+1F467,U+200D,U+1F466:[u1F46A.MWGB=0+800] +/System/Library/Fonts/Supplemental/Zapfino.ttf@99a1e15163c3e9567d5b1019c45e9254dae63b08:--font-funcs ot:U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+005A,U+0061,U+0070,U+0066,U+0069,U+006E,U+006F:[Z=0+416|a=1@-21,0+264|p_f=2+433|i=4+181|n=5+261|Z=6+416|a=7@-21,0+264|p_f=8+433|i=10+181|n=11+261|Z=12+416|a=13@-21,0+264|p_f=14+433|i=16+181|n=17+261|Z=18+416|a=19@-21,0+264|p_f=20+433|i=22+181|n=23+261|Z=24+416|a=25@-21,0+264|p_f=26+433|i=28+181|n=29+261|Z=30+416|a=31@-21,0+264|p_f=32+433|i=34+181|n=35+261|Z=36+416|a=37@-21,0+264|p_f=38+433|i=40+181|n=41+261|Z=42+416|a=43@-21,0+264|p_f=44+433|i=46+181|n=47+261|Z=48+416|a=49@-21,0+264|p_f=50+433|i=52+181|n=53+261|Z=54+416|a=55@-21,0+264|p_f=56+433|i=58+181|n=59+261|Z=60+416|a=61@-21,0+264|p_f=62+433|i=64+181|n=65+261|Z_a_p_f_i_n_o=66+2333] +/System/Library/Fonts/Thonburi.ttc@bb080e01e45f7f6699d2df09a03b3b6d13804897:--font-funcs ot:U+0E17,U+0E35,U+0E48,U+0E4A:[thothahanthai_saraiithai_maiekthai=0+1616|maitrithai.key=0+1300] +/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb:--font-funcs ot:U+0066,U+0069,U+006e,U+0065:[fi=0+1139|n=2+1024|e=3+909] +/System/Library/Fonts/Times.ttc@e9b4f626133de3b22787ee025218c6c799cc3ceb:--font-funcs ot --features liga=0:U+0066,U+0069,U+006e,U+0065:[f=0+682|i=1+569|n=2+1024|e=3+909] +/System/Library/Fonts/Supplemental/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4:--font-funcs ot:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/System/Library/Fonts/Supplemental/Kokonor.ttf@14a5c850ba917d9ec9f6bb9b1fc59b1d95512da4:--font-funcs ot --features liga=0:U+0F62,U+0F92,U+0FB1,U+0F74:[r_g_y_u=0+1579] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s=3+728|t=4+725] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features dlig=1,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f_i=0+1097|r=2+853|s_t=3+1438] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0,sups=0,tnum=0:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s=3+728|t=4+725] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features smcp=1:U+0066,U+0069,U+0072,U+0073,U+0074:[F.small=0+903|I.small=1+634|R.small=2+1113|S.small=3+911|T.small=4+1075] +/System/Library/Fonts/Supplemental/Apple Chancery.ttf@4ec49cba0d4e68d025ada0498c4df1b2f9fd57ac:--font-funcs ot --features liga=0,dlig=1:U+0066,U+0069,U+0072,U+0073,U+0074:[f=0+639|i=1+606|r=2+853|s_t=3+1438] +/System/Library/Fonts/Supplemental/Skia.ttf@caee56fc4085009c1a29a863500908050ea6248f:--font-funcs ot:U+0041,U+0056:[A=0+1345|V=1@-12,0+1346] +/System/Library/Fonts/Supplemental/Devanagari Sangam MN.ttc@214b7ffa672bc936745df5a72644f2b705b24b4b:--font-funcs ot:U+092D,U+0941:[dn_bha=0+1339|dn_u_matra.mrk=0@-296,11+0] diff --git a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests index c5e35c89058ced4453f00e30992131dde2157c57..f624a295f26031d7a7aee4ed391e38ea92ecc1b8 100644 --- a/test/shaping/data/in-house/tests/mongolian-variation-selector.tests +++ b/test/shaping/data/in-house/tests/mongolian-variation-selector.tests @@ -16,4 +16,4 @@ ../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1820,U+200C,U+182D,U+1820,U+1837:[uni1820.E820_a.isol=0+1550|space=1+0|uni182D.E8E2_g.init=2+1000|uni1820.E823_a.medi=3+400|uni1837.E931_r.fina=4+750] ../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+1830,U+1824,U+1837,U+200D,U+200D,U+182D,U+1820,U+200D:[uni1830.E90B_s.init=0+850|uni1824.E844_u.medi=1+600|uni1837.E930_r.medi=2+600|space=2+0|space=2+0|uni182D.E8E5_g.medi1=5+800|uni1820.E823_a.medi=6+400|space=6+0] ../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+200D,U+182D,U+1824,U+182F,U+1822:[space=0+0|uni182D.E8E5_g.medi1=1+800|uni1824.E844_u.medi=2+600|uni182F.E908_l.medi=3+400|uni1822.E837_i.fina=4+600] -../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni182A1820.E875_ba.init=0+1000|uni1822.E836_i.medi2=2+1000|uni182D.E8E8_g.fina1=3+1250|space=4+0|uni1820.E827_a.fina2=5+600|uni202F.nobreak=6+500|uni1836.E92B_y.init1=7+500|uni1822.E834_i.medi=8+500|uni1828.E866_n.fina=9+850] +../fonts/4d4206e30b2dbf1c1ef492a8eae1c9e7829ebad8.ttf::U+182A,U+1820,U+1822,U+182D,U+180E,U+1820,U+202F,U+1836,U+1822,U+1828:[uni182A1820.E875_ba.init=0+1000|uni1822.E836_i.medi2=2+1000|uni182D.E8E8_g.fina1=3+1250|uni180E.E80E_mvs=4+0|uni1820.E827_a.fina2=5+600|uni202F.nobreak=6+500|uni1836.E92B_y.init1=7+500|uni1822.E834_i.medi=8+500|uni1828.E866_n.fina=9+850] diff --git a/test/shaping/data/in-house/tests/myanmar-misc.tests b/test/shaping/data/in-house/tests/myanmar-misc.tests new file mode 100644 index 0000000000000000000000000000000000000000..eb903c92bbcb54a4094721a66558fe1098e01286 --- /dev/null +++ b/test/shaping/data/in-house/tests/myanmar-misc.tests @@ -0,0 +1 @@ +../fonts/065b01e54f35f0d849fd43bd5b936212739a50cb.ttf::U+101A,U+1035:[ya_e_above=0+1000] diff --git a/test/shaping/data/in-house/tests/reverse-sub.tests b/test/shaping/data/in-house/tests/reverse-sub.tests new file mode 100644 index 0000000000000000000000000000000000000000..0164024219e0116d8bfb0b7f53380a43caf935ca --- /dev/null +++ b/test/shaping/data/in-house/tests/reverse-sub.tests @@ -0,0 +1 @@ +../fonts/a706511c65fb278fda87eaf2180ca6684a80f423.ttf::U+0041,U+0020,U+0041,U+0042:[A.alt1=0+1000|space=1+1000|A.alt1=2+1000|B=3+1000] diff --git a/test/shaping/data/in-house/tests/rotation.tests b/test/shaping/data/in-house/tests/rotation.tests new file mode 100644 index 0000000000000000000000000000000000000000..6ecad2666bbeb93846f34037e6b49ea36df246ad --- /dev/null +++ b/test/shaping/data/in-house/tests/rotation.tests @@ -0,0 +1,4 @@ +../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf:--no-clusters --no-positions --direction=l:U+3008:[uni3008] +../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf:--no-clusters --no-positions --direction=r:U+3008:[uni3009] +../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf:--no-clusters --no-positions --direction=t:U+3008:[uniFE3F] +../fonts/2681c1c72d6484ed3410417f521b1b819b4e2392.ttf:--no-clusters --no-positions --direction=b:U+3008:[uniFE40] diff --git a/test/shaping/data/in-house/tests/use-syllable.tests b/test/shaping/data/in-house/tests/use-syllable.tests index 905600891d4becfadfa04294d369d031b7d38fa8..10f9e0659e842475ea29762826755ae9eb4f6ced 100644 --- a/test/shaping/data/in-house/tests/use-syllable.tests +++ b/test/shaping/data/in-house/tests/use-syllable.tests @@ -14,3 +14,9 @@ ../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A59:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A59=5+0] ../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A5A:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni25CC=5+250|uni1A5A=5+0] ../fonts/3cc01fede4debd4b7794ccb1b16cdb9987ea7571.ttf::U+1A3D,U+1A60,U+1A3D,U+1A63,U+1A60,U+1A3D,U+1A60:[uni1A3D=0+250|uni1A60=0+0|uni1A3D=2+250|uni1A63=2+250|uni1A60=2+0|uni1A3D=5+250|uni1A60=5+0] +../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+11442,U+200C,U+11411:[Ga=0+576|Virama=0@70,70+0|Gha=3+566] +../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+11442,U+200C,U+034F,U+11411:[Ga=0+576|Virama=0@70,70+0|Gha=4+566] +../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+200C,U+11442,U+034F,U+11411:[Ga.icd=0+367|Gha.diag=1@100,0+386] +../fonts/e68a88939e0f06e34d2bc911f09b70890289c8fd.ttf::U+AA00,U+200C,U+AA34:[raMedial_cham_pre=0+400|a_cham=0+1121] +../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+200D,U+11127:[u11124=0+514|u11127=0+0] +../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+2060,U+11127:[u11124=0+514|u11127=1+0] diff --git a/test/shaping/data/in-house/tests/use.tests b/test/shaping/data/in-house/tests/use.tests index dd2a3a27f70acf8f44e16188def438d4faa873c4..6328d3c5f784946338b0a7757dd68280456c9e7f 100644 --- a/test/shaping/data/in-house/tests/use.tests +++ b/test/shaping/data/in-house/tests/use.tests @@ -7,8 +7,9 @@ ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11127,U+11131:[u11124=0+514|u11127=0+0|uni25CC=0+547|u11131=0+0] ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11134,U+11131:[u11124=0+514|u11134=0+0|u11131=0+0] ../fonts/2a670df15b73a5dc75a5cc491bde5ac93c5077dc.ttf::U+11124,U+11131,U+11134:[u11124=0+514|u11131=0+0|uni25CC=0+547|u11134=0+0] -../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf:--font-funcs=ft:U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443:[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0] +../fonts/573d3a3177c9a8646e94c8a0d7b224334340946a.ttf::U+11410,U+11442,U+11411,U+11440,U+11443,U+11410,U+11442,U+11411,U+11441,U+11443:[E_dv.alt=0+275|Ga.icd=0+367|Gha.diag=0@100,0+386|AA_dv.alt=0+208|Candrabindu=0@17,-8+0|E_dv.alt=5+275|Ga.icd=5+367|Gha.diag=5@100,0+386|AU_dv_part.alt=5+213|Candrabindu.sm=5@-52,179+0] ../fonts/dcf774ca21062e7439f98658b18974ea8b956d0c.ttf::U+11328,U+1134D,U+1CF4:[gid1=0+793|gid2=0+0|gid3=0+0] ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf::U+1C00,U+1C27,U+1C28,U+1C34,U+1C35:[uni1C35=0+500|uni1C34=0+500|uni1C28=0+500|uni1C27=0+500|uni1C00=0+500] ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf::U+0D4E,U+0D15,U+0D4D,U+0D15,U+0D46:[uni0D15=0+500|uni0D4E=0+500|uni0D4D=0+500|uni0D46=3+500|uni0D15=3+500] ../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf::U+1102D,U+11046,U+11013,U+11046,U+11013,U+11046:[u11013=0+500|u11046_u11013=0+500|u1102D_u11046=0+500|u11046=0+500] +../fonts/4afb0e8b9a86bb9bd73a1247de4e33fbe3c1fd93.ttf::U+11083:[.notdef=0+500] diff --git a/test/shaping/data/in-house/tests/variations-rounding.tests b/test/shaping/data/in-house/tests/variations-rounding.tests new file mode 100644 index 0000000000000000000000000000000000000000..9a03e4fe661d1e6d3220d8583b0b4f7d265bcd65 --- /dev/null +++ b/test/shaping/data/in-house/tests/variations-rounding.tests @@ -0,0 +1,2 @@ +../fonts/HBTest-VF.ttf:--variations=TEST=491:U+0041:[A=0+496] +../fonts/HBTest-VF.ttf:--variations=TEST=509:U+0041:[A=0+505] diff --git a/test/shaping/data/in-house/tests/variations-space.tests b/test/shaping/data/in-house/tests/variations-space.tests new file mode 100644 index 0000000000000000000000000000000000000000..b5b5deb2810fe91bfb61fa4d53fc61ff1147327e --- /dev/null +++ b/test/shaping/data/in-house/tests/variations-space.tests @@ -0,0 +1,2 @@ +../fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf:--variations=wdth=60:U+0020:[space=0+266] +../fonts/ab40c89624a6104e5d0a2308e448a989302f515b.ttf:--variations=wdth=402:U+0020:[space=0+639] diff --git a/test/shaping/data/text-rendering-tests/DISABLED b/test/shaping/data/text-rendering-tests/DISABLED index 8539c0ee113cae9e28d8a826084821365cc14d42..2728522603b0dbaaeb5109520c5de09f5d3e3a70 100644 --- a/test/shaping/data/text-rendering-tests/DISABLED +++ b/test/shaping/data/text-rendering-tests/DISABLED @@ -7,3 +7,15 @@ tests/SHBALI-1.tests tests/SHBALI-2.tests tests/SHKNDA-2.tests tests/SHKNDA-3.tests + +# TODO: Needs investigation +tests/SHLANA-1.tests +tests/SHLANA-2.tests +tests/SHLANA-3.tests +tests/SHLANA-4.tests +tests/SHLANA-5.tests +tests/SHLANA-6.tests +tests/SHLANA-7.tests +tests/SHLANA-8.tests +tests/SHLANA-9.tests +tests/SHLANA-10.tests diff --git a/test/shaping/data/text-rendering-tests/Makefile.am b/test/shaping/data/text-rendering-tests/Makefile.am index cad03580f940673c923aa2c56c598d000c57674f..19ac3b3a0e5cd7bb68b87f6a576fbec28f2a17ac 100644 --- a/test/shaping/data/text-rendering-tests/Makefile.am +++ b/test/shaping/data/text-rendering-tests/Makefile.am @@ -12,13 +12,19 @@ update: EXTRA_DIST = \ README \ COPYING \ - update.sh \ - extract-tests.py \ + DISABLED \ + update.py \ + meson.build \ fonts \ $(TESTS) \ $(NULL) TEST_EXTENSIONS = .tests +if HAVE_FREETYPE +TESTS_ENVIRONMENT = HAVE_FREETYPE=1 +else +TESTS_ENVIRONMENT = HAVE_FREETYPE=0 +endif TESTS_LOG_COMPILER = $(srcdir)/../../run-tests.py $(top_builddir)/util/hb-shape$(EXEEXT) include Makefile.sources diff --git a/test/shaping/data/text-rendering-tests/Makefile.sources b/test/shaping/data/text-rendering-tests/Makefile.sources index ccbbb37f8de248ee765adfc7013aedd8c2644e8a..78d48ebe92470ad66bb86d3be4d54a909151c281 100644 --- a/test/shaping/data/text-rendering-tests/Makefile.sources +++ b/test/shaping/data/text-rendering-tests/Makefile.sources @@ -1,8 +1,8 @@ TESTS = \ tests/AVAR-1.tests \ tests/CFF-1.tests \ - tests/CFF2-1.tests \ tests/CFF-2.tests \ + tests/CFF2-1.tests \ tests/CMAP-1.tests \ tests/CMAP-2.tests \ tests/CVAR-1.tests \ @@ -29,6 +29,7 @@ TESTS = \ tests/HVAR-2.tests \ tests/KERN-1.tests \ tests/KERN-2.tests \ + tests/MORX-1.tests \ tests/MORX-10.tests \ tests/MORX-11.tests \ tests/MORX-12.tests \ @@ -38,7 +39,7 @@ TESTS = \ tests/MORX-17.tests \ tests/MORX-18.tests \ tests/MORX-19.tests \ - tests/MORX-1.tests \ + tests/MORX-2.tests \ tests/MORX-20.tests \ tests/MORX-21.tests \ tests/MORX-22.tests \ @@ -49,7 +50,7 @@ TESTS = \ tests/MORX-27.tests \ tests/MORX-28.tests \ tests/MORX-29.tests \ - tests/MORX-2.tests \ + tests/MORX-3.tests \ tests/MORX-30.tests \ tests/MORX-31.tests \ tests/MORX-32.tests \ @@ -60,26 +61,35 @@ TESTS = \ tests/MORX-37.tests \ tests/MORX-38.tests \ tests/MORX-39.tests \ - tests/MORX-3.tests \ + tests/MORX-4.tests \ tests/MORX-40.tests \ tests/MORX-41.tests \ - tests/MORX-4.tests \ tests/MORX-5.tests \ tests/MORX-6.tests \ tests/MORX-7.tests \ tests/MORX-8.tests \ tests/MORX-9.tests \ + tests/SFNT-1.tests \ + tests/SFNT-2.tests \ tests/SHBALI-3.tests \ tests/SHKNDA-1.tests \ $(NULL) DISBALED_TESTS = \ tests/CMAP-3.tests \ - tests/MORX-31.tests \ - tests/MORX-41.tests \ tests/SHARAN-1.tests \ tests/SHBALI-1.tests \ tests/SHBALI-2.tests \ tests/SHKNDA-2.tests \ tests/SHKNDA-3.tests \ + tests/SHLANA-1.tests \ + tests/SHLANA-10.tests \ + tests/SHLANA-2.tests \ + tests/SHLANA-3.tests \ + tests/SHLANA-4.tests \ + tests/SHLANA-5.tests \ + tests/SHLANA-6.tests \ + tests/SHLANA-7.tests \ + tests/SHLANA-8.tests \ + tests/SHLANA-9.tests \ $(NULL) diff --git a/test/shaping/data/text-rendering-tests/extract-tests.py b/test/shaping/data/text-rendering-tests/extract-tests.py deleted file mode 100755 index f1722b52d9bfb1541abaaf861517275f7c46607b..0000000000000000000000000000000000000000 --- a/test/shaping/data/text-rendering-tests/extract-tests.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function, division, absolute_import - -import sys -import xml.etree.ElementTree as ET - -# Can we extract this from HTML element itself? I couldn't. -namespaces = { - 'ft': 'https://github.com/OpenType/fonttest', - 'xlink': 'http://www.w3.org/1999/xlink', -} -def ns(s): - ns,s = s.split(':') - return '{%s}%s' % (namespaces[ns], s) - -def unistr(s): - return ','.join('U+%04X' % ord(c) for c in s) - -def glyphstr(glyphs): - out = [] - for glyphname,x,y in glyphs: - if x or y: - out.append('%s@%d,%d' % (glyphname, x, y)) - else: - out.append(glyphname) - return '['+'|'.join(out)+']' - -html = ET.fromstring(sys.stdin.read()) -found = False - -for elt in html.findall(".//*[@class='expected'][@ft:id]", namespaces): - found = True - name = elt.get(ns('ft:id')) - text = elt.get(ns('ft:render')) - font = elt.get(ns('ft:font')) - variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',') - glyphs = [] - for use in elt.findall(".//use"): - x = int(use.get('x')) - y = int(use.get('y')) - href = use.get(ns('xlink:href')) - assert href[0] == '#' - glyphname = '.'.join(href[1:].split('/')[1].split('.')[1:]) - glyphs.append((glyphname, x, y)) - opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft' - if variations: - opts = opts + ' --variations=%s' % variations - print ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs))) - -for elt in html.findall(".//*[@class='expected-no-crash'][@ft:id]", namespaces): - found = True - name = elt.get(ns('ft:id')) - text = elt.get(ns('ft:render')) - font = elt.get(ns('ft:font')) - variations = elt.get(ns('ft:var'), '').replace(':', '=').replace(';', ',') - opts = '' - if variations: - opts = '--variations=%s' % variations - print ("../fonts/%s:%s:%s:*" % (font, opts, unistr(text))) - -sys.exit(0 if found else 1) diff --git a/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf b/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf index 5df9867d83986df962267824c3a2e47463350ed7..4a16594e4049a8981f3b55bf09c76ca6881bb1ee 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestAVAR.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf b/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf index da485d9ecbb89cec05003f9bade758b14729d666..94b5ba96e2b446378f3058417df91d2e2cd0ab39 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf and b/test/shaping/data/text-rendering-tests/fonts/TestCMAP14.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf index 158a77aca3e48343a13906d4dd589571000cf2cb..1ed3df4206fe48a30fa9bffe157c12eac80f8182 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestGPOSThree.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf b/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf index 76d04ebc6cfb77f08dda3b80a526cfca2de41040..55cceb7abc22a1f3a47843975528fe67c612d22a 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf and b/test/shaping/data/text-rendering-tests/fonts/TestGPOSTwo.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf index 8fce4ac4dd893ef65fa6f504c69c77f616f7e146..ec27e032266e4198789dd8b3d9dc586076a906c4 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestGSUBThree.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf index 0ecd326bb070213dd870906450b41271687b2828..3dddf69f0933f0c8aa6eb58539449f4534638190 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestGVARNine.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf b/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf index a87395cafcd7ee94bafefaa28cd13e84bda4923b..07a3c5443bf716c5ae1778edf256508620d559af 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf and b/test/shaping/data/text-rendering-tests/fonts/TestHVAROne.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf b/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf index 35369d1319a5eaf134a58f68df0baabe4feb56e7..d3f7c0c932d4b3903687f04cb12b9883416dc41f 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf and b/test/shaping/data/text-rendering-tests/fonts/TestKERNOne.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf index 9255e996e3d94023a64866e376becef2187030e4..a53de2e6b975e3e2211e8bf02cd3264dd5adcfa3 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXEight.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf index 91c364f35e6c11ae4f11f8ad8d9765eeedcb72e5..c6e6343ae78c357cf6eb36e525bb40c7ebccebb4 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXEighteen.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf index 92b889cafde2ad4dd891ce6943fb78c030701ac0..b7e0f45493f1c415af2a0bd5276ed24e9248741b 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXEleven.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf index 37d0b637778833a1f9c3c16b21e3025e0bab48e0..1d348ddfce49bdf53c2e49a4d2f1f9a617a42dfa 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXForty.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf index 002897230ff255adb5c9cc15ba8937ab94feda47..07512ab5e5df8d515cdbd05d0ad5bd7d0a4e1a15 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXFour.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf index 31c30c042dc5fdca87e4391481fab089e47d33d7..fb961120a604b689779f3c508175aee2fa8721de 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourteen.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf index 98ebe3329f977d12eb3d87818253b715babd0194..be18c759254a4ba1d0f722c22741ff070248539d 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXFourtyone.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf index 4371df458dfc5c8efd4787bddfd14e9155c8d74e..edbf4b1a9e6c40b9d688d017b3d57c9a3184e502 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXNine.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf index 88b8decc63ba096a8e7b0a6af188c0dac16ba8b9..53d64662818380a8f5f8e8740b6cb22cab63bb52 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXOne.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf index 9dd3a844bc36145d469fdd7349acf217e1efb2f3..4fe4fc2bd1fc1840e62846e9e7df60b22b4f4a25 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXSeventeen.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf index e34e1fec158aba78a5be401894751d3faad2dcde..7cbc0ebcd36305f570d9380c76c77e2cc059b25a 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXSixteen.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf index 5827ec5a60c8d8e37762784997093da541cb64ef..1d4389785e011b6e32d3068d9c655caead02687d 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTen.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf index f3c6f0f7de4fa370746b1480321af2c9365d2c4a..48f81d1f36f99b8cf0a49b31a8376a00cd44e4ac 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirteen.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf index 29a41d0a30ee4334df03621c15cbb6d2b7a60eb0..096854434e2d3e84016ab5721df271598c763433 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyeight.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf index f15706317d0f697d27b22af6a6a8bb8df82c05f2..88d67efc18883d5e233d16ed65fa5da8d58f8aea 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfive.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf index a70dadccf471cb7799126548a82d5f72060acef3..94d064ff9e360576f6d683765f9e7b449583391f 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyfour.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf index c106ae945cc6f5d39cfcdfe105b269e46c6d4e92..189061ac7b593cecc5910efad230bc1844aaf778 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtynine.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf index c64c12c06957ef34e90ddeba7e18ad7b1acc0c84..39455eafe63c3b02491b4baa3dabf332fa151e0e 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyone.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf index 22057f18cc8c94699919107bf8d4e96db43744d6..9bdea1188a2f1a68d158dc4fc804a13777030e17 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtyseven.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf index 6676e52746cdb85766449ec98208853b0f38c96a..28a522e8210cd82e3fa7d1970b46c248d5c77bd7 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtysix.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf index 5cab73e5a59088653a171dea221450a4159f540d..af887d9633cab849f36f15959c0a53aec81d0a42 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtythree.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf index 07ed76c1b7738ddf0f841cbe2bf4a633c8829ce0..e8314c748913b5559889558886e9cd46c107f88f 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThirtytwo.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf index 56984f2e68f6a0b16970bbdfe94db9d3f711c3fe..33cc72bd5c063037624028d711ef9c065cb3bc57 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXThree.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf index b1e4bc447adba6c2b14f2f60c205f39174563de0..b660833a8ee7f09af820209517bcdda509cf5bd2 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwelve.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf index 769e29bc63f9ba259ac76959570bea2f72219adc..9d7d9eca007e2cef9688e699e22d9b84346c33e5 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwenty.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf index edabb439cdc63fa958a8d2dee7ed44fa96ebfc22..e02d3541123a3343e9a042e256b2fb727c096e06 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyeight.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf index e3fadf519148b310ef27ab9f8ad758f8980df442..88c08665046aebd39a5910145e5c5b7ef2312713 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfive.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf index 271dddb011258059afe0bbe457fe32e19e164417..3706325822df585405e08da7454135a118958c76 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyfour.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf index 9f015ca59c3d4fa5b8c8ae0a18c29f4f697a9c29..10368bc2a0745e2fc7c533928d386242476a9243 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentynine.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf index 410168046b5d3d94abc519950c011f854ef9eda7..e9e8413c9d4f4ad0f5d0506b8f20a0a3189287f8 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyone.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf index 960b4cff5f4e9f410191fd1a9dbaa0e78dee8536..a459cb35193e8c96e6cd12901ab397675d2497c8 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentyseven.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf index 603b1c62321fcd45e25dd16ab4b386c3c944ab06..040fd874e5975c5cbb1d7f90f46fdaecd1e39bf4 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentysix.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf index df34912d476c160172c6877ac725d19fe0670c37..18a90fd462ca65477d84012c6c02351ba0f410b8 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentythree.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf index 4459e8a777655e4d8de99d3f2da11ba8a17f23c3..f2b6f6ce15c5353b1d4930945efefcf68be62b0a 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwentytwo.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf index 39f2db5497bb4bc9d17f32cfc15763fbb151dee2..365a6350d89efb1658687733554127b0ec90ae99 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestMORXTwo.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestSFNTOne.otf b/test/shaping/data/text-rendering-tests/fonts/TestSFNTOne.otf new file mode 100644 index 0000000000000000000000000000000000000000..974e2863dc3251541ce5c9dc7164f363bd0c1263 Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestSFNTOne.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestSFNTTwo.ttf b/test/shaping/data/text-rendering-tests/fonts/TestSFNTTwo.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1d62cf7a18510058118b61ff5a3a9043f2a38a3 Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestSFNTTwo.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestSVGgradientTransform.otf b/test/shaping/data/text-rendering-tests/fonts/TestSVGgradientTransform.otf new file mode 100644 index 0000000000000000000000000000000000000000..59cfc5a1027a25b754065fab8daf6239c405401f Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestSVGgradientTransform.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestSVGgzip.otf b/test/shaping/data/text-rendering-tests/fonts/TestSVGgzip.otf new file mode 100644 index 0000000000000000000000000000000000000000..69d976f153080b2edd32f217d329142f49e00651 Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestSVGgzip.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestSVGmultiGlyphs.otf b/test/shaping/data/text-rendering-tests/fonts/TestSVGmultiGlyphs.otf new file mode 100644 index 0000000000000000000000000000000000000000..50fdc1990a7f56a3ac495652d201bef73f385175 Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestSVGmultiGlyphs.otf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestShapeLana.ttf b/test/shaping/data/text-rendering-tests/fonts/TestShapeLana.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f7c3f81869a8ea512338fa93970907b828658fd8 Binary files /dev/null and b/test/shaping/data/text-rendering-tests/fonts/TestShapeLana.ttf differ diff --git a/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf b/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf index 425bce6fceeadb7104800759b1faa6422a8c59a6..85f1d9726f27cdc2622beed732b26c36f56acc5d 100644 Binary files a/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf and b/test/shaping/data/text-rendering-tests/fonts/TestTRAKOne.ttf differ diff --git a/test/shaping/data/text-rendering-tests/meson.build b/test/shaping/data/text-rendering-tests/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..0d950f5e6ce2eba37f707f052ea1dcf9e5007025 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/meson.build @@ -0,0 +1,95 @@ +text_rendering_tests = [ + 'AVAR-1.tests', + 'CFF-1.tests', + 'CFF-2.tests', + 'CFF2-1.tests', + 'CMAP-1.tests', + 'CMAP-2.tests', + 'CVAR-1.tests', + 'CVAR-2.tests', + 'GLYF-1.tests', + 'GPOS-1.tests', + 'GPOS-2.tests', + 'GPOS-3.tests', + 'GPOS-4.tests', + 'GPOS-5.tests', + 'GSUB-1.tests', + 'GSUB-2.tests', + 'GSUB-3.tests', + 'GVAR-1.tests', + 'GVAR-2.tests', + 'GVAR-3.tests', + 'GVAR-4.tests', + 'GVAR-5.tests', + 'GVAR-6.tests', + 'GVAR-7.tests', + 'GVAR-8.tests', + 'GVAR-9.tests', + 'HVAR-1.tests', + 'HVAR-2.tests', + 'KERN-1.tests', + 'KERN-2.tests', + 'MORX-1.tests', + 'MORX-10.tests', + 'MORX-11.tests', + 'MORX-12.tests', + 'MORX-13.tests', + 'MORX-14.tests', + 'MORX-16.tests', + 'MORX-17.tests', + 'MORX-18.tests', + 'MORX-19.tests', + 'MORX-2.tests', + 'MORX-20.tests', + 'MORX-21.tests', + 'MORX-22.tests', + 'MORX-23.tests', + 'MORX-24.tests', + 'MORX-25.tests', + 'MORX-26.tests', + 'MORX-27.tests', + 'MORX-28.tests', + 'MORX-29.tests', + 'MORX-3.tests', + 'MORX-30.tests', + 'MORX-31.tests', + 'MORX-32.tests', + 'MORX-33.tests', + 'MORX-34.tests', + 'MORX-35.tests', + 'MORX-36.tests', + 'MORX-37.tests', + 'MORX-38.tests', + 'MORX-39.tests', + 'MORX-4.tests', + 'MORX-40.tests', + 'MORX-41.tests', + 'MORX-5.tests', + 'MORX-6.tests', + 'MORX-7.tests', + 'MORX-8.tests', + 'MORX-9.tests', + 'SFNT-1.tests', + 'SFNT-2.tests', + 'SHBALI-3.tests', + 'SHKNDA-1.tests', +] + +disabled_text_rendering_tests = [ + 'CMAP-3.tests', + 'SHARAN-1.tests', + 'SHBALI-1.tests', + 'SHBALI-2.tests', + 'SHKNDA-2.tests', + 'SHKNDA-3.tests', + 'SHLANA-1.tests', + 'SHLANA-10.tests', + 'SHLANA-2.tests', + 'SHLANA-3.tests', + 'SHLANA-4.tests', + 'SHLANA-5.tests', + 'SHLANA-6.tests', + 'SHLANA-7.tests', + 'SHLANA-8.tests', + 'SHLANA-9.tests', +] diff --git a/test/shaping/data/text-rendering-tests/tests/SFNT-1.tests b/test/shaping/data/text-rendering-tests/tests/SFNT-1.tests new file mode 100644 index 0000000000000000000000000000000000000000..7a6feeb70b4b4911a54f78ba260a265626ded4bd --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SFNT-1.tests @@ -0,0 +1,2 @@ +../fonts/TestSFNTOne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A] +../fonts/TestSFNTOne.otf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B] diff --git a/test/shaping/data/text-rendering-tests/tests/SFNT-2.tests b/test/shaping/data/text-rendering-tests/tests/SFNT-2.tests new file mode 100644 index 0000000000000000000000000000000000000000..2c952b5fc70c569b276a10ad17d0d1952e8574bf --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SFNT-2.tests @@ -0,0 +1,2 @@ +../fonts/TestSFNTTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0041:[A] +../fonts/TestSFNTTwo.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+0042:[B] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-1.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-1.tests new file mode 100644 index 0000000000000000000000000000000000000000..870e421d40b9ae879c50c1659f9164b5ff681427 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-1.tests @@ -0,0 +1,52 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6B:[uni1A20|uni1A6B@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A74:[uni1A23|uni1A74@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A27,U+1A62:[uni1A27|uni1A62@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A60,U+1A45,U+1A6B,U+1A61:[uni1A32|uni1A601A45@762,0|uni1A6B@762,0|uni1A61@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A37,U+1A60,U+1A45,U+1A6B:[uni1A37|uni1A601A45@592,0|uni1A6B@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A60,U+1A45:[uni1A20|uni1A601A45@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A21,U+1A6C,U+1A74:[uni1A21|uni1A6C@592,-98|uni1A74@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6C:[uni1A20|uni1A6C.wide@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A26,U+1A61:[uni1A26|uni1A61@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A63:[uni1A20|uni1A63@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A64:[uni1A34|uni1A64@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4C,U+1A63,U+1A74:[uni1A4C|uni1A74@762,0|uni1A63@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A64,U+1A74:[uni1A23|uni1A74@592,0|uni1A64@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A33,U+1A65:[uni1A33|uni1A65@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3A,U+1A66,U+0020:[uni1A3A|uni1A66@738,0|space@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A29,U+1A67:[uni1A29|uni1A67@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A68:[uni1A3E.v2|uni1A68@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A35,U+1A69:[uni1A35|uni1A69@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A26,U+1A6A:[uni1A26|uni1A6A@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A6E,U+1A61:[uni1A6E|uni1A32@592,0|uni1A61@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3D,U+1A6E:[uni1A6E|uni1A3D@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A24,U+1A6F,U+1A61:[uni1A6F|uni1A24@1096,0|uni1A61@1688,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A27,U+1A6F:[uni1A6F|uni1A27@1096,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A38,U+1A6E,U+1A6C,U+1A65,U+1A61:[uni1A6E|uni1A38@592,0|uni1A6C@1184,0|uni1A65@1098,0|uni1A61@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A6E,U+1A6C,U+1A65:[uni1A6E|uni1A36@592,0|uni1A6C@1184,0|uni1A65@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6E,U+1A6C,U+1A68,U+1A61:[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0|uni1A61@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6E,U+1A6C,U+1A68:[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A6E,U+1A62,U+1A63:[uni1A6E|uni1A41@592,0|uni1A62@1184,0|uni1A63@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A73:[uni1A3E.v2|uni1A73@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6E,U+1A63:[uni1A6E|uni1A20@592,0|uni1A63@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A39,U+1A60,U+1A3F,U+1A6E,U+1A61:[uni1A6E|uni1A39@592,0|uni1A601A3F@1324,0|uni1A61@1551,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A60,U+1A3F,U+1A6E:[uni1A6E|uni1A3B@592,0|uni1A601A3F@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A60,U+1A3F:[uni1A20|uni1A601A3F@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A6E,U+1A6C,U+1A65,U+1A4B,U+1A61:[uni1A6E|uni1A3E.v2@592,0|uni1A6C@1184,0|uni1A65@1184,0|uni1A4B@1324,0|uni1A61@1916,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A56,U+1A6E,U+1A6C,U+1A65,U+1A4B:[uni1A6E|uni1A20@592,0|uni1A56.wide@1524,0|uni1A6C.wide@1524,-547|uni1A65@1524,0|uni1A4B@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A70,U+1A61:[uni1A70|uni1A48@592,0|uni1A61@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A70:[uni1A70|uni1A3E.v2@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2A,U+1A70,U+1A6C,U+1A61:[uni1A70|uni1A2A@592,0|uni1A6C@1184,0|uni1A61@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A29,U+1A62,U+1A60,U+1A3F:[uni1A29|uni1A62@592,0|uni1A601A3F@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A72:[uni1A72|uni1A36@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A22,U+1A71:[uni1A71|uni1A22@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A71,U+1A60,U+1A3F:[uni1A71|uni1A34@592,0|uni1A601A3F@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6E,U+1A6C,U+1A68,U+1A61:[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0|uni1A61@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6E,U+1A6C,U+1A68:[uni1A6E|uni1A20@592,0|uni1A6C.wide@1524,0|uni1A68@1354,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A70,U+1A62:[uni1A70|uni1A20@592,0|uni1A62@1354,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A58:[uni1A48|uni1A58@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A62,U+1A60,U+1A26:[uni1A34|uni1A62@592,0|uni1A601A26@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4C,U+1A65,U+1A74,U+0020:[uni1A4C|uni1A65@762,0|uni1A74@1211,0|space@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A65,U+1A60,U+1A26:[uni1A20|uni1A65@762,0|uni1A601A26@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A62,U+1A60,U+1A3E:[uni1A20|uni1A62@762,0|uni1A601A3E@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A62,U+1A3E:[uni1A20|uni1A62@762,0|uni1A3E.v2@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A6D:[uni1A2F|uni1A6D@592,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-10.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-10.tests new file mode 100644 index 0000000000000000000000000000000000000000..a6ade4b5824c807315ae2ffd9dfbbffe93511a19 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-10.tests @@ -0,0 +1,47 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A53,U+1A6F:[uni1A6F|uni1A53@1096,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A50,U+1A63:[uni1A50|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A50,U+1A75,U+1A63:[uni1A50|uni1A75@738,0|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A6A,U+1A55,U+1A63:[uni1A55|uni1A2F@227,0|uni1A6A@818,0|uni1A63@818,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A6E,U+1A6C,U+1A65,U+1A41,U+1A39,U+1A6B,U+1A56,U+1A23,U+1A69,U+1A31,U+1A7A:[uni1A6E|uni1A2F@592,0|uni1A6C@1184,-188|uni1A65@1184,0|uni1A41@1184,0|uni1A39@1775,0|uni1A6B@2367,0|uni1A56@2367,0|uni1A23@2508,0|uni1A69@3100,0|uni1A31@3100,0|uni1A7A@3861,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A63,U+1A37,U+1A70,U+1A56:[uni1A3B|uni1A63@933,0|uni1A70@1524,0|uni1A37@2116,0|uni1A56@2708,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A76,U+1A6D:[uni1A36|uni1A76@592,0|uni1A6D@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A39,U+1A65,U+1A56,U+1A69,U+1A75,U+1A7B:[uni1A39|uni1A65@592,0|uni1A56@592,0|uni1A69@592,-547|uni1A75@592,357|uni1A78@864,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A56,U+1A60,U+1A45,U+1A26:[uni1A49|uni1A56.wide@933,0|uni1A601A45@762,-547|uni1A26@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A56,U+1A60,U+1A45,U+1A63:[uni1A49|uni1A56.wide@933,0|uni1A601A45@762,-547|uni1A63@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A55,U+1A60,U+1A3F,U+1A6E,U+1A61:[uni1A6E|uni1A55@592,0|uni1A3B@818,0|uni1A601A3F@1751,0|uni1A61@1978,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A69,U+1A76,U+1A63,U+1A60,U+1A36,U+1A60,U+1A26:[uni1A20|uni1A69@762,0|uni1A76@762,0|uni1A63@933,0|uni1A601A36@1524,0|uni1A601A26@1524,-367] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4B,U+1A62,U+1A60,U+1A2D,U+1A5B:[uni1A4B|uni1A62@592,0|uni1A601A2D1A5B@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A46,U+1A62,U+1A20,U+1A60,U+1A2F,U+1A65,U+1A7A:[uni1A46|uni1A62@592,0|uni1A20@681,0|uni1A601A2F@1442,0|uni1A65@1442,0|uni1A7A@1442,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A46,U+1A62,U+1A20,U+1A60,U+1A2F,U+1A65,U+1A7C:[uni1A46|uni1A62@592,0|uni1A20@681,0|uni1A601A2F@1442,0|uni1A65@1442,0|uni1A7C@1442,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A49,U+1A63,U+1A49,U+1A65,U+1A26,U+1A60,U+1A23,U+1A69,U+1A7A:[uni1A3E.v2|uni1A49@732,0|uni1A63@1665,0|uni1A49@2257,0|uni1A65@3019,0|uni1A26@3189,0|uni1A601A23@3781,0|uni1A69@3781,-547|uni1A7A@3781,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A49,U+1A63,U+1A49,U+1A65,U+1A26,U+1A60,U+1A23,U+1A69,U+1A7C:[uni1A3E.v2|uni1A49@732,0|uni1A63@1665,0|uni1A49@2257,0|uni1A65@3019,0|uni1A26@3189,0|uni1A601A23@3781,0|uni1A69@3781,-547|uni1A7C@3781,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A46,U+1A63,U+1A48,U+1A60,U+1A32,U+1A55,U+1A7A:[uni1A46|uni1A63@681,0|uni1A55@1272,0|uni1A48@1499,0|uni1A601A32@2091,0|uni1A7A@2091,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A63,U+1A48,U+1A60,U+1A32,U+1A55,U+1A7C:[uni1A48|uni1A63@592,0|uni1A55@1184,0|uni1A48@1410,0|uni1A601A32@2002,0|uni1A7C@2002,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A6A,U+1A60,U+1A37:[uni1A41|uni1A601A37@592,0|uni1A6A@725,-367] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A66,U+1A75,U+1A60,U+1A36,U+1A6C,U+1A76,U+1A26:[uni1A3B|uni1A66@762,0|uni1A75@762,357|uni1A601A36@762,0|uni1A6C@762,-367|uni1A76@1087,357|uni1A26@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A38,U+1A62,U+1A63:[uni1A38|uni1A62@506,0|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A43,U+1A6A,U+1A62:[uni1A43|uni1A6A@762,0|uni1A62@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A6C,U+1A62:[uni1A2F|uni1A6C@592,-188|uni1A62@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A6C,U+1A62,U+1A61:[uni1A2F|uni1A6C@592,-188|uni1A62@592,0|uni1A61@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A60,U+1A45,U+1A62,U+1A61:[uni1A3B|uni1A601A45@762,0|uni1A62@762,0|uni1A61@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A6F,U+1A60,U+1A36,U+1A6C,U+1A74,U+1A75:[uni1A6F|uni1A32@1096,0|uni1A601A36@1857,0|uni1A6C@1857,-367|uni1A74@1857,0|uni1A75@1857,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A6C,U+1A74,U+1A75,U+034F,U+1A6F,U+1A60,U+1A36:[uni1A6F|uni1A32@1096,0|uni1A6C.wide@2028,0|uni1A74@2028,0|uni1A75@2028,357|uni1A601A36@1857,-367] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A6C,U+1A74,U+1A75,U+1A6F,U+1A60,U+1A36:[uni1A6F|uni1A32@1096,0|uni1A6C.wide@2028,0|uni1A74@2028,0|uni1A75@2028,357|uni1A601A36@1857,-367] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A60,U+1A36,U+1A6B,U+1A7B:[uni1A48|uni1A601A36@592,0|uni1A6B@592,0|uni1A78@592,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A3E,U+1A5B,U+1A66:[uni1A20|uni1A3E1A5B@933,0|uni1A66@1549,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A65,U+1A3B,U+1A5B,U+1A63,U+1A60,U+1A36:[uni1A36|uni1A65@592,0|uni1A3B1A5B@592,0|uni1A63@1524,0|uni1A601A36@2116,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A35,U+1A3E,U+1A5C,U+1A65,U+1A20:[uni1A35|uni1A3E.v2@592,0|uni1A5C@1184,0|uni1A65@1184,0|uni1A20@1324,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A35,U+1A69,U+1A60,U+1A37:[uni1A48|uni1A35@592,0|uni1A601A37@1184,0|uni1A69@1317,-367] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A45,U+1A65,U+1A48,U+1A6E,U+1A60,U+1A48:[uni1A45|uni1A65@592,0|uni1A6E@592,0|uni1A48@1184,0|uni1A601A48@1775,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A22,U+1A76,U+1A63:[uni1A22|uni1A76@738,0|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A63,U+1A48,U+1A36,U+1A63:[uni1A48|uni1A63@592,0|uni1A48@1184,0|uni1A361A63@1775,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A63,U+1A48,U+1A60,U+1A36,U+1A7B,U+1A63:[uni1A48|uni1A63@592,0|uni1A48@1184,0|uni1A601A36@1775,0|uni1A78@1775,0|uni1A63@1775,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A60,U+1A36,U+1A7B,U+1A6E,U+1A62,U+1A76,U+1A63:[uni1A6E|uni1A48@592,0|uni1A601A36@1184,0|uni1A78@1184,0|uni1A621A76@1599,0|uni1A63@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A60,U+1A36,U+1A7B,U+1A6E,U+1A62,U+1A62,U+1A76,U+1A63:[uni1A6E|uni1A48@592,0|uni1A601A36@1184,0|uni1A78@1184,0|uni1A621A621A76@1599,0|uni1A63@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A66,U+034F,U+1A63,U+1A60,U+1A3F:[uni1A32|uni1A66@762,0|uni1A63@933,0|uni1A601A3F@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A75,U+1A63,U+1A74,U+1A7B:[uni1A49|uni1A601A3E@762,0|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0|uni1A78@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A43,U+1A6E,U+1A5E:[uni1A6E|uni1A43@592,0|uni1A5E@1354,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4B,U+1A36,U+1A63,U+1A33,U+1A37,U+1A65,U+1A31,U+1A60,U+1A2F,U+1A65,U+1A20,U+1A48,U+1A5E:[uni1A4B|uni1A361A63@592,0|uni1A33@1184,0|uni1A37@1775,0|uni1A65@2367,0|uni1A31@2367,0|uni1A601A2F@3129,0|uni1A65@3129,0|uni1A20@3300,0|uni1A48@4232,0|uni1A5E@4824,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A63,U+1A74,U+1A7B:[uni1A2F|uni1A74@592,0|uni1A63@592,0|uni1A78@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A74,U+1A75,U+1A63,U+1A7B:[uni1A49|uni1A601A3E@762,0|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0|uni1A78@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A74,U+1A63,U+1A7B:[uni1A2F|uni1A74@592,0|uni1A63@592,0|uni1A78@1184,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-2.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-2.tests new file mode 100644 index 0000000000000000000000000000000000000000..eee5c99f144f4ab1879e9fbe4d70d235f34cca1d --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-2.tests @@ -0,0 +1,37 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A93,U+1A60,U+1A34:[uni1A93|uni1A601A34@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A75,U+1A63,U+1A60,U+1A26,U+1A7B:[uni1A32|uni1A75@762,0|uni1A63@933,0|uni1A601A26@1524,0|uni1A78@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A33,U+1A60,U+1A36,U+1A7B,U+1A6B,U+1A41:[uni1A33|uni1A601A36@592,0|uni1A78@592,0|uni1A6B@954,0|uni1A41@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A21,U+1A62,U+1A76,U+1A7B,U+1A6C,U+1A26:[uni1A21|uni1A621A76@592,0|uni1A78@1007,0|uni1A6C@592,-98|uni1A26@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1AAD,U+1A63:[uni1AAD|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A36,U+1A66:[uni1A49|uni1A601A36@762,0|uni1A66@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A24,U+1A60,U+1A45,U+1A6F,U+1A76,U+1A41:[uni1A6F|uni1A24@1096,0|uni1A601A45@1688,0|uni1A76@1688,0|uni1A41@1688,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A45,U+1A6B:[uni1A49|uni1A601A45@762,0|uni1A6B@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A62,U+1A75,U+1A26,U+1A60,U+1A36,U+1A66,U+1A76:[uni1A2F|uni1A621A75@592,0|uni1A26@592,0|uni1A601A36@1184,0|uni1A66@1184,0|uni1A76@1184,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A65,U+1A60,U+1A36:[uni1A49|uni1A65@762,0|uni1A601A36@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A63,U+1A60,U+1A3E:[uni1A32|uni1A63@933,0|uni1A601A3E@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A60,U+1A3F,U+1A63,U+1A60,U+1A35,U+1A65:[uni1A3B|uni1A601A3F@933,0|uni1A63@1159,0|uni1A601A35@1751,0|uni1A65@1751,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A38,U+1A60,U+1A43,U+1A60,U+1A3F,U+1A75,U+1A41:[uni1A38|uni1A601A43@592,0|uni1A601A3F@818,0|uni1A75@1049,0|uni1A41@1045,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A6F,U+1A76,U+1A60,U+1A36,U+1A60,U+1A45,U+1A75,U+1A63:[uni1A6F|uni1A3E.v2@1096,0|uni1A76@1688,0|uni1A601A36@1688,0|uni1A601A45@1688,-367|uni1A75@2013,0|uni1A63@1828,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A60,U+1A45,U+1A6F,U+1A75:[uni1A6F|uni1A48@1096,0|uni1A601A45@1688,0|uni1A75@1688,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A75,U+1A6F,U+1A60,U+1A45:[uni1A6F|uni1A48@1096,0|uni1A75@1688,0|uni1A601A45@1688,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3F,U+1A6A:[uni1A3F|uni1A6A@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A66:[uni1A3E.v2|uni1A66@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A6A:[uni1A49|uni1A601A3E@762,0|uni1A6A@762,-367] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A66:[uni1A49|uni1A601A3E@762,0|uni1A66@762,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A39,U+1A60,U+1A45,U+1A6B:[uni1A39|uni1A601A45@592,0|uni1A6B@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A43,U+1A6C,U+1A74,U+1A75:[uni1A49|uni1A601A43@933,0|uni1A6C@1060,-547|uni1A74@1164,0|uni1A75@1164,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A63:[uni1A3E.v2|uni1A63@732,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A71,U+1A75:[uni1A71|uni1A49@592,0|uni1A75@1354,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A45,U+1A60,U+1A3F,U+1A26:[uni1A45|uni1A601A3F@592,0|uni1A26@818,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A63,U+1A60,U+1A3E:[uni1A49|uni1A63@933,0|uni1A601A3E@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A63,U+1A74:[uni1A2F|uni1A74@592,0|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A63:[uni1A49|uni1A601A3E@762,0|uni1A63@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A55,U+1A63,U+1A60,U+1A38:[uni1A55|uni1A20@227,0|uni1A63@1159,0|uni1A601A37@1751,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A55,U+1A75,U+1A63,U+1A74:[uni1A55|uni1A3B@227,0|uni1A74@988,0|uni1A75@988,357|uni1A63@1159,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A55,U+1A6C,U+1A26:[uni1A55|uni1A20@227,0|uni1A6C.wide@1159,0|uni1A26@1159,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A55,U+1A6B,U+1A3E,U+1A60,U+1A31,U+1A7A:[uni1A55|uni1A48@227,0|uni1A6B@818,0|uni1A3E.v2@818,0|uni1A601A31.narrow@1410,0|uni1A7A@1410,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A55,U+1A60,U+1A45,U+1A6B,U+1A3E:[uni1A55|uni1A48@227,0|uni1A601A45@818,0|uni1A6B@818,0|uni1A3E.v2@818,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A75,U+1A63,U+1A74:[uni1A49|uni1A601A3E@762,0|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3E,U+1A6E,U+1A6C,U+1A68,U+1A26:[uni1A6E|uni1A49@592,0|uni1A601A3E@1524,0|uni1A6C@1524,-367|uni1A68@1524,0|uni1A26@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A3F,U+1A6E,U+1A6C,U+1A68,U+1A26:[uni1A6E|uni1A49@592,0|uni1A601A3F@1524,0|uni1A6C@1729,-367|uni1A68@1755,0|uni1A26@1751,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A43,U+1A63,U+1A60,U+1A3F:[uni1A49|uni1A601A43@933,0|uni1A63@1159,0|uni1A601A3F@1751,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-3.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-3.tests new file mode 100644 index 0000000000000000000000000000000000000000..f5cac56394d9756874e4cac87e72d3a9a6c46ede --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-3.tests @@ -0,0 +1,13 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6C,U+1A62,U+1A43,U+1A60,U+1A3C,U+1A7A:[uni1A20|uni1A6C.wide@933,0|uni1A62@762,0|uni1A43@933,0|antler@933,0|uni1A601A3C.wide@1865,0|uni1A7A@1964,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6C,U+1A62,U+1A43,U+1A7A,U+1A60,U+1A3C:[uni1A20|uni1A6C.wide@933,0|uni1A62@762,0|uni1A43@933,0|antler@933,0|uni1A7A@1964,0|uni1A601A3C.wide@1865,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6C,U+1A62,U+1A43,U+1A60,U+1A7A,U+1A3C:[uni1A20|uni1A6C.wide@933,0|uni1A62@762,0|uni1A43@933,0|antler@933,0|uni1A7A@1964,0|uni1A601A3C.wide@1865,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A55,U+1A63,U+1A60,U+1A3C:[uni1A55|uni1A20@227,0|uni1A63@1159,0|antler@1159,0|uni1A601A3C@1751,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A6C,U+1A3C,U+1A60,U+1A3C,U+1A66,U+1A75:[uni1A34|uni1A6C@592,0|uni1A3C@592,0|antler@771,0|uni1A601A3C.wide@1524,0|uni1A66@1558,0|uni1A75@1558,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A3D,U+1A5A:[uni1A20|uni1A3D@933,0|uni1A5A@1865,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A31,U+1A5B,U+1A63,U+1A60,U+1A36:[uni1A48|uni1A311A5B@592,0|uni1A63@1524,0|uni1A601A36@2116,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A2D,U+1A5B,U+1A37,U+1A63,U+1A60,U+1A43:[uni1A41|uni1A2D1A5B@592,0|uni1A37@1184,0|uni1A63@1775,0|uni1A601A43@2367,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A62,U+1A2D,U+1A5B,U+1A37,U+1A63,U+1A60,U+1A43:[uni1A41|uni1A62@592,0|uni1A2D1A5B@592,0|uni1A37@1184,0|uni1A63@1775,0|uni1A601A43@2367,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A3B,U+1A5B:[uni1A48|uni1A3B1A5B@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4B,U+1A3E,U+1A5B:[uni1A4B|uni1A3E1A5B@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A63,U+1A29,U+1A3D,U+1A62,U+1A60,U+1A2E:[uni1A41|uni1A63@592,0|uni1A29@1184,0|uni1A3D@1775,0|uni1A62@2537,0|uni1A601A2E@2537,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A37,U+1A62,U+1A31,U+1A60,U+1A3B,U+1A37,U+1A69,U+1A41,U+1A69,U+1A48:[uni1A37|uni1A62@592,0|uni1A31@592,0|uni1A601A3B.wide@1524,0|uni1A37@1524,0|uni1A69@2116,0|uni1A41@2116,0|uni1A69@2708,0|uni1A48@2708,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-4.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-4.tests new file mode 100644 index 0000000000000000000000000000000000000000..47f0ccf6b638e8093b1f041e0ea311d7eb214745 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-4.tests @@ -0,0 +1,3 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A58,U+1A60,U+1A43,U+1A63,U+1A60,U+1A3F:[uni1A34|uni1A58@592,0|uni1A601A43@592,0|uni1A63@818,0|uni1A601A3F@1410,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A58,U+1A25,U+1A6E,U+1A63:[uni1A48|uni1A6E@592,0|uni1A25@1184,0|uni1A58@1945,0|uni1A63@2117,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A58,U+1A48,U+1A66:[uni1A41|uni1A58@592,0|uni1A48@592,0|uni1A66@1184,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-5.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-5.tests new file mode 100644 index 0000000000000000000000000000000000000000..84fc8ec845fac10fec40c422cfc0fa5052b6f64d --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-5.tests @@ -0,0 +1,13 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A63,U+1A74:[uni1A361A63|uni1A74@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3E,U+1A36,U+1A6E,U+1A63:[uni1A3E.v2|uni1A6E@732,0|uni1A361A63@1324,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A6E,U+1A62,U+1A63:[uni1A6E|uni1A361A63@592,0|uni1A62@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A63,U+1A60,U+1A3F:[uni1A361A63|uni1A601A3F@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A75,U+1A63,U+1A60,U+1A36:[uni1A361A63|uni1A75@592,0|uni1A601A36@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4D,U+1A36,U+1A60,U+1A34,U+1A63:[uni1A4D|uni1A361A63@933,0|uni1A601A34@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A4B,U+1A6B,U+1A36,U+1A60,U+1A32,U+1A55,U+1A63,U+1A60,U+1A3F:[uni1A4B|uni1A6B@592,0|uni1A55@592,0|uni1A361A63@818,0|uni1A601A32@1410,0|uni1A601A3F@1410,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A76,U+1A63,U+1A74:[uni1A361A63|uni1A74@592,0|uni1A76@592,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A60,U+1A45,U+1A63,U+1A60,U+1A37:[uni1A361A63|uni1A601A45@592,0|uni1A601A37@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A64,U+1A74,U+1A36,U+1A60,U+1A45,U+200C,U+1A63,U+1A60,U+1A3F:[uni1A34|uni1A74@592,0|uni1A64@592,0|uni1A36@818,0|uni1A601A45@1410,0|uni1A63@1410,0|uni1A601A3F@2002,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A32,U+1A75,U+1A63,U+1A74,U+1A36,U+1A60,U+1A45,U+1A63,U+1A60,U+1A3F:[uni1A32|uni1A74@762,0|uni1A75@762,357|uni1A63@933,0|uni1A361A63@1524,0|uni1A601A45@2116,0|uni1A601A3F@2116,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+200C,U+1A63:[uni1A36|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A36,U+1A76,U+1A63:[uni1A49|uni1A601A36@762,0|uni1A76@762,0|uni1A63@933,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-6.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-6.tests new file mode 100644 index 0000000000000000000000000000000000000000..a143822de96c97ee6d0b6609e58e8b5c24c48066 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-6.tests @@ -0,0 +1,7 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6F,U+1A62,U+1A60,U+1A48:[uni1A6F|uni1A20@1096,0|uni1A62@1857,0|uni1A601A48@2028,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A55,U+1A6F,U+1A60,U+1A20,U+1A34,U+1A6E,U+1A6C,U+1A65,U+1A41,U+1A7A:[uni1A6F|uni1A55@1096,0|uni1A34@1322,0|uni1A601A20@1914,0|uni1A6E@1914,0|uni1A34@2506,0|uni1A6C@3098,0|uni1A65@3098,0|uni1A41@3098,0|uni1A7A@3689,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A36,U+1A70,U+1A6B,U+1A76,U+1A60,U+1A32:[uni1A70|uni1A36@592,0|uni1A6B@1184,0|uni1A76@1184,357|uni1A601A32@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A37,U+1A55,U+1A70,U+1A34,U+1A66,U+1A60,U+1A36:[uni1A70|uni1A55@592,0|uni1A37@818,0|uni1A34@1410,0|uni1A66@2002,0|uni1A601A36@2002,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3C,U+1A65,U+1A45,U+1A60,U+1A48,U+1A7A:[uni1A3C|uni1A65@859,0|uni1A45@933,0|uni1A601A48@1524,0|uni1A7A@1755,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A32,U+1A6F,U+1A3E,U+1A60,U+1A37,U+1A7A:[uni1A48|uni1A6F@592,0|uni1A32@1688,0|uni1A3E.v2@2620,0|uni1A601A37@3353,0|uni1A7A@3584,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A6E,U+1A65,U+1A41,U+1A7A,U+1A60,U+1A37:[uni1A6E|uni1A48@592,0|uni1A65@1184,0|uni1A41@1184,0|uni1A7A@1775,0|uni1A601A37@1775,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-7.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-7.tests new file mode 100644 index 0000000000000000000000000000000000000000..48aedd8acb7128a6c9f7887411f3478196df01ae --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-7.tests @@ -0,0 +1,18 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A62,U+1A75,U+1A57,U+1A63:[uni1A34|uni1A621A75@592,0|uni1A57@592,0|uni1A63@818,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A21,U+1A36,U+1A60,U+1A35,U+1A63:[uni1A21|uni1A361A63@592,0|uni1A601A35@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A76,U+1A60,U+1A2F,U+1A66,U+00A0:[uni1A23|uni1A76@592,0|uni1A601A2F@592,0|uni1A66@1095,0|space_nb@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A37,U+1A76,U+1A60,U+1A3E,U+1A63:[uni1A37|uni1A76@592,0|uni1A601A3E@592,0|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A37,U+1A60,U+1A76,U+1A3E,U+1A63:[uni1A37|uni1A76@592,0|uni1A601A3E@592,0|uni1A63@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A37,U+1A76,U+1A60,U+1A2F,U+1A63,U+1A60,U+1A3F:[uni1A37|uni1A76@592,0|uni1A601A2F@592,0|uni1A63@592,0|uni1A601A3F@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A27,U+1A62,U+1A60,U+1A45,U+1A64:[uni1A27|uni1A62@592,0|uni1A601A45@592,0|uni1A64@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A6E,U+1A60,U+1A53,U+1A60,U+1A45:[uni1A6E|uni1A48@592,0|uni1A601A53@1184,0|uni1A601A45@1311,-547] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A34,U+1A6F,U+1A60,U+1A36,U+1A73:[uni1A6F|uni1A34@1096,0|uni1A601A36@1688,0|uni1A73@1688,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A53,U+1A60,U+1A3E,U+1A63:[uni1A53|uni1A601A3E@762,0|uni1A63@933,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A20,U+1A6E,U+1A60,U+1A48,U+1A63:[uni1A6E|uni1A20@592,0|uni1A601A48@1524,0|uni1A63@1751,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A71,U+1A60,U+1A3E,U+1A63:[uni1A71|uni1A3B@592,0|uni1A601A3E@1354,0|uni1A63@1524,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A6E,U+1A60,U+1A45,U+1A76,U+1A64:[uni1A6E|uni1A48@592,0|uni1A601A45@1184,0|uni1A76@1184,0|uni1A64@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A45,U+1A6E,U+1A60,U+1A43,U+1A63:[uni1A6E|uni1A45@592,0|uni1A601A43@1184,0|uni1A63@1410,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A35,U+1A64,U+1A60,U+1A32,U+1A69:[uni1A35|uni1A64@592,0|uni1A601A32@863,0|uni1A69@863,-547] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A29,U+1A60,U+1A53:[uni1A29|uni1A601A53@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A6D,U+1A60,U+1A45,U+1A7B,U+1A63:[uni1A3B|uni1A6D@933,0|uni1A601A45@1137,-547|uni1A78@1204,195|uni1A63@1159,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A6B,U+1A60,U+1A26,U+1A63,U+1A60,U+1A36:[uni1A48|uni1A6B@592,0|uni1A601A26@592,0|uni1A63@592,0|uni1A601A36@1184,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-8.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-8.tests new file mode 100644 index 0000000000000000000000000000000000000000..ad1055a278677addd66432038f46361507536cab --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-8.tests @@ -0,0 +1,13 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A6C,U+1A73,U+1A75:[uni1A3B|uni1A6C.wide@933,0|uni1A73@762,0|uni1A75@762,447] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A48,U+1A37,U+1A77,U+1A63,U+1A60,U+1A3F:[uni1A48|uni1A37@592,0|uni1A77@1184,0|uni1A63@1184,0|uni1A601A3F@1775,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A45,U+1A60,U+1A3F,U+1A59:[uni1A45|uni1A601A3F@592,0|uni1A59@823,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A6A,U+1A7A:[uni1A23|uni1A6A@592,0|uni1A7A@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A81,U+1A82,U+00A0,U+1A3B,U+1A62,U+1A60,U+1A36,U+1A7B,U+1A63:[uni1A81|uni1A82@592,0|space_nb@1184,0|uni1A3B@1501,0|uni1A62@2263,0|uni1A601A36@2263,0|uni1A78@2263,357|uni1A63@2434,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A3B,U+1A71,U+1A7B,U+1A63,U+1A60,U+1A3F:[uni1A71|uni1A3B@592,0|uni1A78@1354,0|uni1A63@1524,0|uni1A601A3F@2116,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A29,U+1A60,U+1A3F,U+1A59,U+1A32,U+1A69,U+1A74:[uni1A29|uni1A601A3F@592,0|uni1A59@823,0|uni1A32@818,0|uni1A69@1580,0|uni1A74@1580,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A45,U+1A32,U+1A5B,U+1A69:[uni1A45|uni1A321A5B@592,0|uni1A69@1184,-734] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A45,U+1A32,U+1A60,U+1A33,U+1A69:[uni1A45|uni1A32@592,0|uni1A601A33@1354,0|uni1A69@1354,-547] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A2F,U+1A60,U+1A3F,U+1A74:[uni1A2F|uni1A601A3F@592,0|uni1A74@823,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A49,U+1A60,U+1A36,U+1A66,U+1A62,U+1A76:[uni1A49|uni1A601A36@762,0|uni1A66@762,0|uni1A621A76@1265,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A6E,U+1A42,U+1A60,U+1A20:[uni1A6E|uni1A41@592,0|uni1A42@1184,0|uni1A601A20@1775,-547] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A41,U+1A60,U+1A3F,U+1A7A:[uni1A41|uni1A601A3F@592,0|uni1A7A@823,0] diff --git a/test/shaping/data/text-rendering-tests/tests/SHLANA-9.tests b/test/shaping/data/text-rendering-tests/tests/SHLANA-9.tests new file mode 100644 index 0000000000000000000000000000000000000000..d37ed7416269152cb63d37c9be3e76f70b835681 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/tests/SHLANA-9.tests @@ -0,0 +1,6 @@ +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A74,U+1A37,U+1A74,U+1A75:[uni1A23|uni1A74@592,0|uni1A37@592,0|uni1A74@1184,0|uni1A75@1184,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A74,U+1A37,U+1A74:[uni1A23|uni1A74@592,0|uni1A37@592,0|uni1A74@1184,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A5D,U+1A74,U+1A75:[uni1A23|uni1A5D@592,0|uni1A74@592,0|uni1A75@592,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A74,U+1A5D,U+1A75:[uni1A23|uni1A74@592,0|uni1A5D@592,0|uni1A75@592,357] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A5D,U+1A74:[uni1A23|uni1A5D@592,0|uni1A74@592,0] +../fonts/TestShapeLana.ttf:--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft:U+1A23,U+1A74,U+1A5D:[uni1A23|uni1A74@592,0|uni1A5D@592,0] diff --git a/test/shaping/data/text-rendering-tests/update.py b/test/shaping/data/text-rendering-tests/update.py new file mode 100644 index 0000000000000000000000000000000000000000..cf119be0a728adc56cde23f43992aefebbe4f8c1 --- /dev/null +++ b/test/shaping/data/text-rendering-tests/update.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 + +import sys, os, subprocess, shutil, glob +import xml.etree.ElementTree as ET + +# Can we extract this from HTML element itself? I couldn't. +namespaces = { + 'ft': 'https://github.com/OpenType/fonttest', + 'xlink': 'http://www.w3.org/1999/xlink', +} +def ns (s): + ns,s = s.split(':') + return '{%s}%s' % (namespaces[ns], s) + +def unistr (s): + return ','.join('U+%04X' % ord(c) for c in s) + +def glyphstr (glyphs): + out = [] + for glyphname, x, y in glyphs: + if x or y: + out.append ('%s@%d,%d' % (glyphname, x, y)) + else: + out.append (glyphname) + return '[' + '|'.join (out) + ']' + +def extract_tests (input): + html = ET.fromstring (input) + found = False + + result = [] + + for elt in html.findall (".//*[@class='expected'][@ft:id]", namespaces): + found = True + name = elt.get (ns ('ft:id')) + text = elt.get (ns ('ft:render')) + font = elt.get (ns ('ft:font')) + variations = elt.get (ns ('ft:var'), '').replace (':', '=').replace (';', ',') + glyphs = [] + for use in elt.findall (".//use"): + x = int (use.get ('x')) + y = int (use.get ('y')) + href = use.get (ns ('xlink:href')) + assert href[0] == '#' + glyphname = '.'.join (href[1:].split ('/')[1].split ('.')[1:]) + glyphs.append ((glyphname, x, y)) + opts = '--font-size=1000 --ned --remove-default-ignorables --font-funcs=ft' + if variations: + opts = opts + ' --variations=%s' % variations + result.append ("../fonts/%s:%s:%s:%s" % (font, opts, unistr(text), glyphstr(glyphs))) + + for elt in html.findall (".//*[@class='expected-no-crash'][@ft:id]", namespaces): + found = True + name = elt.get (ns ('ft:id')) + text = elt.get (ns ('ft:render')) + font = elt.get (ns ('ft:font')) + variations = elt.get (ns ('ft:var'), '').replace (':', '=').replace (';', ',') + opts = '' + if variations: + opts = '--variations=%s' % variations + result.append ("../fonts/%s:%s:%s:*" % (font, opts, unistr (text))) + + assert found + return '\n'.join (result) + '\n' + +os.chdir (os.getenv ('srcdir', os.path.dirname (__file__))) + +git = shutil.which ('git') +assert git + +if os.path.isdir ('./text-rendering-tests'): + subprocess.run ([git, 'pull'], cwd='text-rendering-tests', check=True) +else: + subprocess.run ([git, 'clone', 'https://github.com/unicode-org/text-rendering-tests'], check=True) + +shutil.rmtree ('fonts', ignore_errors=True) +assert not os.path.exists ('fonts') +shutil.copytree ('text-rendering-tests/fonts', 'fonts') +subprocess.run([git, 'add', 'fonts'], check=True) + +shutil.rmtree ('tests', ignore_errors=True) +assert not os.path.isdir('tests') +os.mkdir ('tests') + +with open ('DISABLED', 'r') as f: disabled = f.read () + +tests = [] +disabled_tests = [] + +for x in sorted (os.listdir ('text-rendering-tests/testcases')): + if not x.endswith ('.html') or x == 'index.html': continue + out = 'tests/%s.tests' % x.split('.html')[0] + with open ('text-rendering-tests/testcases/' + x, 'r') as f: content = f.read () + with open (out, 'w') as f: f.write (extract_tests (content)) + if out in disabled: + disabled_tests.append (out) + else: + tests.append (out) + +subprocess.run([git, 'add', 'tests'], check=True) + +with open ('meson.build', 'w') as f: f.write ('\n'.join ( + ['text_rendering_tests = ['] + + [' \'%s\',' % x.split('tests/')[1] for x in tests] + + [']', '', 'disabled_text_rendering_tests = ['] + + [' \'%s\',' % x.split('tests/')[1] for x in disabled_tests] + + [']', ''] +)) + +with open ('Makefile.sources', 'w') as f: f.write ('\n'.join ( + ['TESTS = \\'] + + [' %s \\' % x for x in tests] + + [' $(NULL)', '', 'DISBALED_TESTS = \\'] + + [' %s \\' % x for x in disabled_tests] + + [' $(NULL)', ''] +)) + +subprocess.run([git, 'add', 'Makefile.sources'], check=True) + +print ('Updated the testsuit, now run `git commit -e -m "[test/text-rendering-tests] Update from upstream"`') diff --git a/test/shaping/data/text-rendering-tests/update.sh b/test/shaping/data/text-rendering-tests/update.sh deleted file mode 100755 index 47545bcdb6acd9006e915820de0ff5bcbb334017..0000000000000000000000000000000000000000 --- a/test/shaping/data/text-rendering-tests/update.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -dir=`dirname "$0"` - -set -ex -if test -d text-rendering-tests; then - cd text-rendering-tests - git pull - cd .. -else - git clone https://github.com/unicode-org/text-rendering-tests -fi - -test -d fonts && git rm -rf fonts -test -d fonts && (echo "fonts/ dir not empty; investigate."; false) -cp -a text-rendering-tests/fonts . -git add fonts - -rmdir tests || true -test -d tests && git rm -rf tests || true -test -d tests && (echo "tests/ dir not empty; investigate."; false) -mkdir tests - -echo "TESTS = \\" > Makefile.sources - -DISABLED="DISBALED_TESTS = \\" -for x in text-rendering-tests/testcases/*.html; do - test "x$x" = xtext-rendering-tests/testcases/index.html && continue - out=tests/`basename "$x" .html`.tests - "$dir"/extract-tests.py < "$x" > "$out" - if grep -q "^$out$" DISABLED; then - DISABLED="$DISABLED - $out \\" - else - echo " $out \\" >> Makefile.sources - fi -done -git add tests - -echo ' $(NULL)' >> Makefile.sources -echo >> Makefile.sources -echo "$DISABLED" >> Makefile.sources -echo ' $(NULL)' >> Makefile.sources -git add Makefile.sources - -git commit -e -m "[test/text-rendering-tests] Update from upstream" diff --git a/test/shaping/hb-diff b/test/shaping/hb-diff index 3705de7d02d8ef4a3e248d89be23314490cd41de..15a1e2725e5d10089e77b5036e8fc6fa4f2e17c8 100755 --- a/test/shaping/hb-diff +++ b/test/shaping/hb-diff @@ -1,10 +1,9 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * import sys, os if len (sys.argv) < 2: - print "usage: %s FILES..." % sys.argv[0] - sys.exit (1) + sys.exit ("usage: %s FILES..." % sys.argv[0]) ZipDiffer.diff_files (FileHelpers.open_file_or_stdin (f) for f in sys.argv[1:]) diff --git a/test/shaping/hb-diff-colorize b/test/shaping/hb-diff-colorize index 1fdae8a433bc54b3ff1756e4bdb241d724a32ae7..7c481f5a491545e97f8441276b9860aaf147c56c 100755 --- a/test/shaping/hb-diff-colorize +++ b/test/shaping/hb-diff-colorize @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * diff --git a/test/shaping/hb-diff-filter-failures b/test/shaping/hb-diff-filter-failures index 34b76de9a3062163485f72943b2633fc72102263..fc868d9959a8559affabf8b6773f7c2592e2f5cd 100755 --- a/test/shaping/hb-diff-filter-failures +++ b/test/shaping/hb-diff-filter-failures @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * diff --git a/test/shaping/hb-diff-stat b/test/shaping/hb-diff-stat index 12ee8f098b0a3452e8a79b044a00b65593d3471f..f8471164e9a496cc8afcbb3c706e394bca19ad41 100755 --- a/test/shaping/hb-diff-stat +++ b/test/shaping/hb-diff-stat @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * diff --git a/test/shaping/hb-unicode-decode b/test/shaping/hb-unicode-decode index 9ac5ed6e6962e702c93c1974303c963385896749..1dc70522a06f2e5439855ef8217224d32c5dee72 100755 --- a/test/shaping/hb-unicode-decode +++ b/test/shaping/hb-unicode-decode @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * diff --git a/test/shaping/hb-unicode-encode b/test/shaping/hb-unicode-encode index 588980714cbab539d1049f3126a72ddc62b43825..99a99b31d73e749955e6fdace9d908b649ed486d 100755 --- a/test/shaping/hb-unicode-encode +++ b/test/shaping/hb-unicode-encode @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * diff --git a/test/shaping/hb-unicode-prettyname b/test/shaping/hb-unicode-prettyname index 1d004c0e10c54effa1bda40b0637c08cdff24dd0..41289b53b9481d76ba97d138c8ad240ec07d25fd 100755 --- a/test/shaping/hb-unicode-prettyname +++ b/test/shaping/hb-unicode-prettyname @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from hb_test_tools import * diff --git a/test/shaping/hb_test_tools.py b/test/shaping/hb_test_tools.py index feff70afacd450aed9a97344580d078f2831b520..a9368adbd93826a654f30cdb772a0d17a9882d3b 100644 --- a/test/shaping/hb_test_tools.py +++ b/test/shaping/hb_test_tools.py @@ -1,13 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import - -import sys, os, re, difflib, unicodedata, errno, cgi +import sys, os, re, difflib, unicodedata, errno, cgi, itertools from itertools import * -try: - import unicodedata2 as unicodedata -except Exception: - pass diff_symbols = "-+=*&^%$#@!~/" diff_colors = ['red', 'green', 'blue'] @@ -15,78 +9,6 @@ diff_colors = ['red', 'green', 'blue'] def codepoints(s): return (ord (u) for u in s) -try: - unichr = unichr - - if sys.maxunicode < 0x10FFFF: - # workarounds for Python 2 "narrow" builds with UCS2-only support. - - _narrow_unichr = unichr - - def unichr(i): - """ - Return the unicode character whose Unicode code is the integer 'i'. - The valid range is 0 to 0x10FFFF inclusive. - - >>> _narrow_unichr(0xFFFF + 1) - Traceback (most recent call last): - File "", line 1, in ? - ValueError: unichr() arg not in range(0x10000) (narrow Python build) - >>> unichr(0xFFFF + 1) == u'\U00010000' - True - >>> unichr(1114111) == u'\U0010FFFF' - True - >>> unichr(0x10FFFF + 1) - Traceback (most recent call last): - File "", line 1, in ? - ValueError: unichr() arg not in range(0x110000) - """ - try: - return _narrow_unichr(i) - except ValueError: - try: - padded_hex_str = hex(i)[2:].zfill(8) - escape_str = "\\U" + padded_hex_str - return escape_str.decode("unicode-escape") - except UnicodeDecodeError: - raise ValueError('unichr() arg not in range(0x110000)') - - def codepoints(s): - high_surrogate = None - for u in s: - cp = ord (u) - if 0xDC00 <= cp <= 0xDFFF: - if high_surrogate: - yield 0x10000 + (high_surrogate - 0xD800) * 0x400 + (cp - 0xDC00) - high_surrogate = None - else: - yield 0xFFFD - else: - if high_surrogate: - yield 0xFFFD - high_surrogate = None - if 0xD800 <= cp <= 0xDBFF: - high_surrogate = cp - else: - yield cp - high_surrogate = None - if high_surrogate: - yield 0xFFFD - -except NameError: - unichr = chr - -try: - unicode = unicode -except NameError: - unicode = str - -def tounicode(s, encoding='ascii', errors='strict'): - if not isinstance(s, unicode): - return s.decode(encoding, errors) - else: - return s - class ColorFormatter: class Null: @@ -213,7 +135,7 @@ class ZipDiffer: def diff_files (files, symbols=diff_symbols): files = tuple (files) # in case it's a generator, copy it try: - for lines in izip_longest (*files): + for lines in itertools.zip_longest (*files): if all (lines[0] == line for line in lines[1:]): sys.stdout.writelines ([" ", lines[0]]) continue @@ -223,8 +145,7 @@ class ZipDiffer: sys.stdout.writelines ([symbols[i], l]) except IOError as e: if e.errno != errno.EPIPE: - print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr) - sys.exit (1) + sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)) class DiffFilters: @@ -276,7 +197,7 @@ class Stats: Self is Stats for sample. Returns larger absolute value if sample is highly unlikely to be random. Anything outside of -3..+3 is very unlikely to be random. - See: http://en.wikipedia.org/wiki/Standard_score""" + See: https://en.wikipedia.org/wiki/Standard_score""" return (self.mean () - population.mean ()) / population.stddev () @@ -399,8 +320,7 @@ class UtilMains: def process_multiple_files (callback, mnemonic = "FILE"): if "--help" in sys.argv: - print ("Usage: %s %s..." % (sys.argv[0], mnemonic)) - sys.exit (1) + sys.exit ("Usage: %s %s..." % (sys.argv[0], mnemonic)) try: files = sys.argv[1:] if len (sys.argv) > 1 else ['-'] @@ -408,23 +328,20 @@ class UtilMains: callback (FileHelpers.open_file_or_stdin (s)) except IOError as e: if e.errno != errno.EPIPE: - print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr) - sys.exit (1) + sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)) @staticmethod def process_multiple_args (callback, mnemonic): if len (sys.argv) == 1 or "--help" in sys.argv: - print ("Usage: %s %s..." % (sys.argv[0], mnemonic)) - sys.exit (1) + sys.exit ("Usage: %s %s..." % (sys.argv[0], mnemonic)) try: for s in sys.argv[1:]: callback (s) except IOError as e: if e.errno != errno.EPIPE: - print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr) - sys.exit (1) + sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)) @staticmethod def filter_multiple_strings_or_stdin (callback, mnemonic, \ @@ -432,9 +349,12 @@ class UtilMains: concat_separator = False): if "--help" in sys.argv: - print ("Usage:\n %s %s...\nor:\n %s\n\nWhen called with no arguments, input is read from standard input." \ - % (sys.argv[0], mnemonic, sys.argv[0])) - sys.exit (1) + sys.exit ("""Usage: + %s %s... +or: + %s +When called with no arguments, input is read from standard input. +""" % (sys.argv[0], mnemonic, sys.argv[0])) try: if len (sys.argv) == 1: @@ -452,15 +372,14 @@ class UtilMains: print (separator.join (callback (x) for x in (args))) except IOError as e: if e.errno != errno.EPIPE: - print ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror), file=sys.stderr) - sys.exit (1) + sys.exit ("%s: %s: %s" % (sys.argv[0], e.filename, e.strerror)) class Unicode: @staticmethod def decode (s): - return u','.join ("U+%04X" % cp for cp in codepoints (tounicode (s, 'utf-8'))) + return ','.join ("U+%04X" % cp for cp in codepoints (s)) @staticmethod def parse (s): @@ -470,9 +389,7 @@ class Unicode: @staticmethod def encode (s): - s = u''.join (unichr (x) for x in Unicode.parse (s)) - if sys.version_info[0] == 2: s = s.encode ('utf-8') - return s + return ''.join (chr (x) for x in Unicode.parse (s)) shorthands = { "ZERO WIDTH NON-JOINER": "ZWNJ", @@ -508,8 +425,8 @@ class Unicode: def pretty_names (s): s = re.sub (r"[<+>\\uU]", " ", s) s = re.sub (r"0[xX]", " ", s) - s = [unichr (int (x, 16)) for x in re.split ('[, \n]', s) if len (x)] - return u' + '.join (Unicode.pretty_name (x) for x in s).encode ('utf-8') + s = [chr (int (x, 16)) for x in re.split ('[, \n]', s) if len (x)] + return ' + '.join (Unicode.pretty_name (x) for x in s) class FileHelpers: @@ -528,8 +445,7 @@ class Manifest: if not os.path.exists (s): if strict: - print ("%s: %s does not exist" % (sys.argv[0], s), file=sys.stderr) - sys.exit (1) + sys.exit ("%s: %s does not exist" % (sys.argv[0], s)) return s = os.path.normpath (s) @@ -544,8 +460,7 @@ class Manifest: yield p except IOError: if strict: - print ("%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST")), file=sys.stderr) - sys.exit (1) + sys.exit ("%s: %s does not exist" % (sys.argv[0], os.path.join (s, "MANIFEST"))) return else: yield s diff --git a/test/shaping/meson.build b/test/shaping/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..b1e49190edd500e401086d2994b2373576c80bf7 --- /dev/null +++ b/test/shaping/meson.build @@ -0,0 +1,51 @@ + +subdir('data/in-house') # in_house_tests +subdir('data/aots') # aots_tests +subdir('data/text-rendering-tests') # text_rendering_tests + +shaping_run_tests_py = find_program('run-tests.py') + +env = environment() +env.set('HAVE_FREETYPE', '@0@'.format(conf.get('HAVE_FREETYPE', 0))) + +foreach file_name : in_house_tests + test_name = file_name.split('.')[0].underscorify() + + test(test_name, shaping_run_tests_py, + args: [ + hb_shape, + join_paths(meson.current_source_dir(), 'data', 'in-house', 'tests', file_name), + ], + env: env, + workdir: join_paths(meson.current_build_dir(), '..', '..'), + suite: ['shaping', 'in-house'], + ) +endforeach + +foreach file_name : aots_tests + test_name = file_name.split('.')[0].underscorify() + + test(test_name, shaping_run_tests_py, + args: [ + hb_shape, + join_paths(meson.current_source_dir(), 'data', 'aots', 'tests', file_name), + ], + env: env, + workdir: join_paths(meson.current_build_dir(), '..', '..'), + suite: ['shaping', 'aots'], + ) +endforeach + +foreach file_name : text_rendering_tests + test_name = file_name.split('.')[0].underscorify() + + test(test_name, shaping_run_tests_py, + args: [ + hb_shape, + join_paths(meson.current_source_dir(), 'data', 'text-rendering-tests', 'tests', file_name), + ], + env: env, + workdir: join_paths(meson.current_build_dir(), '..', '..'), + suite: ['shaping', 'text-rendering-tests'], + ) +endforeach diff --git a/test/shaping/record-test.sh b/test/shaping/record-test.sh index 7f24354c12c23a6348887c83a11cfc8872c7bdcd..62a4795997bddbd12f62d86a42f9971bfdd16113 100755 --- a/test/shaping/record-test.sh +++ b/test/shaping/record-test.sh @@ -115,7 +115,7 @@ exec 3<"$unicodes_file" exec 4<"$glyphs_file" relative_subset="$subset" if test "$out" != "/dev/stdout"; then - relative_subset="$(/usr/bin/python -c 'import os, sys; print (os.path.relpath (sys.argv[1], sys.argv[2]))' "$subset" "$(dirname "$out")")" + relative_subset="$(/usr/bin/env python3 -c 'import os, sys; print (os.path.relpath (sys.argv[1], sys.argv[2]))' "$subset" "$(dirname "$out")")" fi while read uline <&3 && read gline <&4; do echo "$relative_subset:$options:$uline:$gline" >> "$out" diff --git a/test/shaping/run-tests.py b/test/shaping/run-tests.py index 26853e4ee3606419cdbed98202985cd1b502bb20..4e9a3de77dfb1e4d15e2222727c359421544323e 100755 --- a/test/shaping/run-tests.py +++ b/test/shaping/run-tests.py @@ -1,12 +1,11 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -from __future__ import print_function, division, absolute_import - -import sys, os, subprocess, hashlib, tempfile, shutil +import sys, os, subprocess, hashlib def cmd(command): + print (command) global process - process.stdin.write ((' '.join (command) + '\n').encode ("utf-8")) + process.stdin.write ((':'.join (command) + '\n').encode ("utf-8")) process.stdin.flush () return process.stdout.readline().decode ("utf-8").strip () @@ -17,9 +16,10 @@ if len (args) and args[0] == "--reference": reference = True args = args[1:] +have_freetype = bool(int(os.getenv ('HAVE_FREETYPE', '1'))) + if not args or args[0].find('hb-shape') == -1 or not os.path.exists (args[0]): - print ("""First argument does not seem to point to usable hb-shape.""") - sys.exit (1) + sys.exit ("""First argument does not seem to point to usable hb-shape.""") hb_shape, args = args[0], args[1:] process = subprocess.Popen ([hb_shape, '--batch'], @@ -44,7 +44,7 @@ for filename in args: if filename == '-': f = sys.stdin else: - f = open (filename) + f = open (filename, encoding='utf8') for line in f: comment = False @@ -62,18 +62,23 @@ for filename in args: continue fontfile, options, unicodes, glyphs_expected = line.split (":") + options = options.split () if fontfile.startswith ('/') or fontfile.startswith ('"/'): - fontfile, expected_hash = fontfile.split('@') + if os.name == 'nt': # Skip on Windows + continue + + fontfile, expected_hash = (fontfile.split('@') + [''])[:2] try: with open (fontfile, 'rb') as ff: - actual_hash = hashlib.sha1 (ff.read()).hexdigest ().strip () - if actual_hash != expected_hash: - print ('different version of %s found; Expected hash %s, got %s; skipping.' % - (fontfile, expected_hash, actual_hash)) - skips += 1 - continue - except: + if expected_hash: + actual_hash = hashlib.sha1 (ff.read()).hexdigest ().strip () + if actual_hash != expected_hash: + print ('different version of %s found; Expected hash %s, got %s; skipping.' % + (fontfile, expected_hash, actual_hash)) + skips += 1 + continue + except IOError: print ('%s not found, skip.' % fontfile) skips += 1 continue @@ -92,42 +97,38 @@ for filename in args: if not reference: print ('%s "%s" %s %s --unicodes %s' % - (hb_shape, fontfile, ' '.join(extra_options), options, unicodes)) - - # hack to support fonts with space on run-tests.py, after several other tries... - if ' ' in fontfile: - new_fontfile = os.path.join (tempfile.gettempdir (), 'tmpfile') - shutil.copyfile(fontfile, new_fontfile) - fontfile = new_fontfile + (hb_shape, fontfile, ' '.join(extra_options), ' '.join(options), unicodes)) - glyphs1 = cmd ([hb_shape, "--font-funcs=ft", - fontfile] + extra_options + ["--unicodes", - unicodes] + (options.split (' ') if options else [])) - - glyphs2 = cmd ([hb_shape, "--font-funcs=ot", - fontfile] + extra_options + ["--unicodes", - unicodes] + (options.split (' ') if options else [])) + if "--font-funcs=ft" in options and not have_freetype: + skips += 1 + continue - if glyphs1 != glyphs2 and glyphs_expected != '*': - print ("FT funcs: " + glyphs1) # file=sys.stderr - print ("OT funcs: " + glyphs2) # file=sys.stderr - fails += 1 + if "--font-funcs=ot" in options or not have_freetype: + glyphs1 = cmd ([hb_shape, fontfile, "--font-funcs=ot"] + extra_options + ["--unicodes", unicodes] + options) else: - passes += 1 + glyphs1 = cmd ([hb_shape, fontfile, "--font-funcs=ft"] + extra_options + ["--unicodes", unicodes] + options) + glyphs2 = cmd ([hb_shape, fontfile, "--font-funcs=ot"] + extra_options + ["--unicodes", unicodes] + options) + + if glyphs1 != glyphs2 and glyphs_expected != '*': + print ("FT funcs: " + glyphs1, file=sys.stderr) + print ("OT funcs: " + glyphs2, file=sys.stderr) + fails += 1 + else: + passes += 1 if reference: - print (":".join ([fontfile, options, unicodes, glyphs1])) + print (":".join ([fontfile, " ".join(options), unicodes, glyphs1])) continue if glyphs1.strip() != glyphs_expected and glyphs_expected != '*': - print ("Actual: " + glyphs1) # file=sys.stderr - print ("Expected: " + glyphs_expected) # file=sys.stderr + print ("Actual: " + glyphs1, file=sys.stderr) + print ("Expected: " + glyphs_expected, file=sys.stderr) fails += 1 else: passes += 1 if not reference: - print ("%d tests passed; %d failed; %d skipped." % (passes, fails, skips)) # file=sys.stderr + print ("%d tests passed; %d failed; %d skipped." % (passes, fails, skips), file=sys.stderr) if not (fails + passes): print ("No tests ran.") elif not (fails + skips): diff --git a/test/subset/CMakeLists.txt b/test/subset/CMakeLists.txt deleted file mode 100644 index af2b41ab4a99c60ce6472b54029f515fa9a058ba..0000000000000000000000000000000000000000 --- a/test/subset/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -if (HB_BUILD_UTILS) - file (READ "${CMAKE_CURRENT_SOURCE_DIR}/data/Makefile.sources" SOURCES) - extract_make_variable (TESTS ${SOURCES}) - foreach (test IN ITEMS ${TESTS}) - add_test (NAME ${test} - COMMAND "${PYTHON_EXECUTABLE}" run-tests.py $ "data/${test}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - set_property(TEST ${test} PROPERTY SKIP_RETURN_CODE 77) - endforeach () -endif () diff --git a/test/subset/Makefile.am b/test/subset/Makefile.am index 1673cfbd168d022de7913ab7806a86dea45c578a..cfd739b3195d85fd27ba69721b622d8ae66eceae 100644 --- a/test/subset/Makefile.am +++ b/test/subset/Makefile.am @@ -6,13 +6,16 @@ CLEANFILES = SUBDIRS = data # Convenience targets: -lib: +lib: libs # Always build subsetter lib in this subdir +libs: @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs EXTRA_DIST += \ - CMakeLists.txt \ + meson.build \ run-tests.py \ + run-repack-tests.py \ subset_test_suite.py \ + repack_test.py \ $(NULL) CLEANFILES += \ diff --git a/test/subset/data/Makefile.am b/test/subset/data/Makefile.am index 1e90367d17f6cc93c8aad4916b7a4b28b6f925d8..03c32baf447735f6e61909136d7544e33831655d 100644 --- a/test/subset/data/Makefile.am +++ b/test/subset/data/Makefile.am @@ -3,7 +3,7 @@ NULL = EXTRA_DIST = CLEANFILES = -SUBDIRS = +SUBDIRS = repack_tests EXTRA_DIST += \ $(TESTS) \ @@ -14,6 +14,30 @@ EXTRA_DIST += \ expected/cff-japanese \ expected/layout \ expected/layout.gpos \ + expected/layout.gpos2 \ + expected/layout.gpos3 \ + expected/layout.gpos4 \ + expected/layout.gpos5 \ + expected/layout.gpos6 \ + expected/layout.gpos8 \ + expected/layout.gpos8.amiri \ + expected/layout.gpos9 \ + expected/layout.gsub3 \ + expected/layout.gsub5 \ + expected/layout.gsub6 \ + expected/layout.gsub8 \ + expected/layout.khmer \ + expected/layout.gdef \ + expected/layout.context \ + expected/layout.gdef-varstore \ + expected/layout.gdef-attachlist \ + expected/layout.notonastaliqurdu \ + expected/cmap \ + expected/cmap14 \ + expected/sbix \ + expected/colr \ + expected/cbdt \ + expected/variable \ fonts \ profiles \ $(NULL) diff --git a/test/subset/data/Makefile.sources b/test/subset/data/Makefile.sources index 8bacc51d2451851bc3909391f831d96e7a4375df..dd71a1101c76453d442b40c1949ab339ba08ef22 100644 --- a/test/subset/data/Makefile.sources +++ b/test/subset/data/Makefile.sources @@ -1,11 +1,35 @@ TESTS = \ tests/basics.tests \ - tests/full-font.tests \ + tests/cbdt.tests \ tests/cff-full-font.tests \ - tests/japanese.tests \ tests/cff-japanese.tests \ - tests/layout.tests \ + tests/cmap.tests \ + tests/cmap14.tests \ + tests/colr.tests \ + tests/full-font.tests \ + tests/japanese.tests \ + tests/layout.context.tests \ + tests/layout.gdef-attachlist.tests \ + tests/layout.gdef-varstore.tests \ + tests/layout.gdef.tests \ tests/layout.gpos.tests \ + tests/layout.gpos2.tests \ + tests/layout.gpos3.tests \ + tests/layout.gpos4.tests \ + tests/layout.gpos5.tests \ + tests/layout.gpos6.tests \ + tests/layout.gpos8.tests \ + tests/layout.gpos8.amiri.tests \ + tests/layout.gpos9.tests \ + tests/layout.gsub3.tests \ + tests/layout.gsub5.tests \ + tests/layout.gsub6.tests \ + tests/layout.gsub8.tests \ + tests/layout.khmer.tests \ + tests/layout.notonastaliqurdu.tests \ + tests/layout.tests \ + tests/sbix.tests \ + tests/variable.tests \ $(NULL) XFAIL_TESTS = \ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf index efe5bcb4c2d6263c061bd1c66ea8b2008ed36b0c..163ebcbb26a9ec5a0b0d11e6d3fa349a14b0da12 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf index 8e122417869dd9c40eb799564488168c1a478a3c..867ddfcb17c982c28c7d3662ef0884713fec9c74 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf index bd802a57ee2dbb5acc262e74a7b570fd5691fb1f..76ad2fa0bba3691aa1b4c7d5c200ae49a1415f3c 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf index 9fbebb5d4f92b4a617fafc734cd25c5a60569090..0f95a1e9eded7d4f62f3a2f488b3505b1aebe341 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf index 73917418a33d7055de3c7fd6d90e788234192b7f..23a8777d620be10339a147dbe9d6b67cd699ad29 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf index 5de8d898119a25f52c9d9ba39b16ce6b84779025..a6100c7ed21313b4c338112dbf3d860d4d2c7ac8 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.default.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf index 05d83d8f956fdd85cc75a4643cc9eea1ad2aed35..732414df41ce8d66f627e247e441297a1533c02c 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf index f47887e941b2ac2b0c441da55e814ff4ef8b37e8..ac228485ad01f135d2535df974365c0397c02776 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf index bfa9267b9783d46559cddb592ee9ab7c9be03a5b..88e26567dee7e4455a81ded743d482e204d6da76 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf index 8c121581a6c33097b5fd66840de7c80a40348111..bfafaa2ea2ac69f06ec9fd56486485cd4bac9e2e 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf index 6a47c39d63e474380e090811a36f7d433241bb5c..4ba4125fa3fe7f2bc9c4134bb2e5116419848402 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf index e3c0727608e1bba1fbd10fb11a71f915f8c7ea3b..ce8fd887eb24eca04c1e40986d35ebcbfd289010 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints-retain-gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf index 36a4b9a4501404f7ea7d7adcda3faac9c7f4a70e..53398975c35bb36e3331c35aed7c1c344bfbfafb 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf index 251794c257b7bc6191052f66ef11121376a7148b..ac861aae9c2fdad49a8e8f9babdd4b7c251b8646 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf index 9e65c8385833a9de499aecfa991888f656cf310a..d2d1881b0a698afa50a7b06e099643cdb1d3c97a 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf index ada1649afcc05f411e016013c26ca1a5144434e6..009ef070283a8bf7cefed6f0f20c91a224f9fc7c 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf index 6b0dc6c3d69cd7a74828cc50fa5433d274c503fc..960d66ed19171f306e16676d5a8561c84e0c8373 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf index 6425ecfd1e19375f43ed9df41b120d6b24705fa4..102f5c6725ea9ef8a18b2bd389d97037fa92b763 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.drop-hints.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7ec6a0db616d6f1c3a2a5d19729b42bee7715880 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7160f0feab4676f83794a5aae01ccf7f62be1ffb Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..69c08d90429de37f2ac641c95d893a7535994548 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bed98973ea0f7a0d4c4dc7afe2c20c6eb5bad6ef Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..29be22f6807de06501c5447ce722c9c6600a066d Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a6100c7ed21313b4c338112dbf3d860d4d2c7ac8 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf index 90e49bef6b67ebb086e89914bd70e964feba8a45..4c485126c1ab695ffb0c4ec1cd8035bf95ac504e 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf index 5277d1508c02f5436656c2a0d611e862c4c4f1f0..dd8d99b187dd8c7f3d71c4454706db3014c374e7 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf index de06660d073e7489213056216607f00006ed4393..019bc1190d29b2db23d2ab2e5044258cc1ca66b0 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf index effad7b68552031f1a66fb93f25119cd0fd81ede..a5efad895a758805d922035fc0de33e8059a4d7e 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf index 21c8205cb6b397547e4c8d71b6f0774e01b7b3f9..0c828d2ba9e0e2e4c8d1e1495b827b23f772743e 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf index fbb8c33ac7984ca9b1c1b3a2259d660724e0bc18..4a172ab83b621e8deaa4c1a30db59df8cd07f1b0 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-ids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..163ebcbb26a9ec5a0b0d11e6d3fa349a14b0da12 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..867ddfcb17c982c28c7d3662ef0884713fec9c74 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..76ad2fa0bba3691aa1b4c7d5c200ae49a1415f3c Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0f95a1e9eded7d4f62f3a2f488b3505b1aebe341 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..23a8777d620be10339a147dbe9d6b67cd699ad29 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a6100c7ed21313b4c338112dbf3d860d4d2c7ac8 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-languages.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..163ebcbb26a9ec5a0b0d11e6d3fa349a14b0da12 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..867ddfcb17c982c28c7d3662ef0884713fec9c74 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..76ad2fa0bba3691aa1b4c7d5c200ae49a1415f3c Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0f95a1e9eded7d4f62f3a2f488b3505b1aebe341 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..23a8777d620be10339a147dbe9d6b67cd699ad29 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a6100c7ed21313b4c338112dbf3d860d4d2c7ac8 Binary files /dev/null and b/test/subset/data/expected/basics/Comfortaa-Regular-new.name-legacy.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf index 3c0f4cd5bb5c894859712f324c492e1130ddaa22..a6b3aa174af80b019899d5e685e1415f583eb0ac 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf index a5ce9e05d9061fe5afb4a739079549dbebb2e7dd..c4262e57b7d9b11a13cbfab282c6f9a1987e4369 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf index 1b843357d546c2e1ce01c20d352a037045ad4f44..578802026d5ffce5f02f313e8e92be6d71866b8e 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf index 97eaa26ad39edc5837a5ef2e689586e64d321664..407e11034af2eb0c8168ad474477c8b7b4546b7c 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.62.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf index f42edb71f0c5a09dff3d6c1b5179bf2b6d96823b..3735a53d728c26bd3c05e488bab0a961b5c1042b 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf index cc2805a019468f70af028e141aed87ef4974a4e9..a1733e04653ac2a220ce0312c4d3432c26ce541a 100644 Binary files a/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Comfortaa-Regular-new.retain-gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5913420e3c290b8380daf2c54312d002b53c6e58 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3635f68be507538e0d3682c9febf6f865bce9436 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..91fcad84a09e6dbbcfa21ac741629bfb5b68e5eb Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..737cbdc7eb584e073e957a05b85eabeac5bd6cf9 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9744bc31d7da41a12b0ed144702f2a6e2ea66697 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.default.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bf8264b44abc374cf466e8f164489057035b0d65 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c64172a7628ce25663e90d01d44ae6564009c666 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9b261449d59a140f2e25d9773fac5d9d74e23628 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d737cd79b0cafbb2c727673892573fe8f4d130e7 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5e4d49477c00d47489d07542dea16d9b6d572549 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..892ccb8ea1a99e2cc9c0ae197779b03f2587e84f Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints-retain-gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bf8264b44abc374cf466e8f164489057035b0d65 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bc54940a3d0476757c5929cd454ba9f6a9f77abd Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9b261449d59a140f2e25d9773fac5d9d74e23628 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..32cf9f7dab78ddb8cda657105ed768eab914bf2e Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..776e758f0d14539815d97c5c5063f14dda3af7a2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..892ccb8ea1a99e2cc9c0ae197779b03f2587e84f Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.drop-hints.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9744bc31d7da41a12b0ed144702f2a6e2ea66697 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a7af973903fd13b691033d2a4b9c2b6973ac397d Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ac780dbb93693619922451d5244b6af271652546 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c4321d1bc000d5251404b8129787fad0a27dea68 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4c553ca794c284fdd8cbd5916e0548303714ee77 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5234b742e88c4f603d97afae74963c1ecccd2d69 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9d225419fa2f7e4e11b020931a37326ffa3312fe Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-ids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9bb2a9d1f8b52c44bb6fd5241279c6452bca473e Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7373aa3bec8f37ac606488fda7d76a2926f7d7ea Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..26fe19eabeba4a1aab183c77f02ed02b8607db71 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..02cd27022ab3e03403501dbcacd115e5af0246f7 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..64a892e43d0f693691745855625985d511ef6cb4 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d5d423810c1ad2d23c8d47c8deef2167e98f9773 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-languages.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5913420e3c290b8380daf2c54312d002b53c6e58 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3635f68be507538e0d3682c9febf6f865bce9436 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..91fcad84a09e6dbbcfa21ac741629bfb5b68e5eb Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..737cbdc7eb584e073e957a05b85eabeac5bd6cf9 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9744bc31d7da41a12b0ed144702f2a6e2ea66697 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.name-legacy.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbed582fb56afff74f581a9be494eac5adb9b3b2 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..47e72c6a392900e73bda31c8a839ed7ebad7a659 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3635f68be507538e0d3682c9febf6f865bce9436 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.62.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..57f7ec7699135b06fdf6879194b71f7768e621d6 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.62.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.63.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d0426a0d5722f3ebdbe95acace7cd67ef3a25a92 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9744bc31d7da41a12b0ed144702f2a6e2ea66697 Binary files /dev/null and b/test/subset/data/expected/basics/NanumMyeongjo-Regular-subset.retain-gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf index 12d92081b31eda6deaf2aa8b62e69c0535dfe225..712674fa22479ff9b21f78c415184515f0e505ab 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf index 1af233f482d63226cf4cb10e502e243b83c6fa4e..f4b4a085239704e72854cdf2af82caba076ef6e3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf index a699eea0bced6d31e273e28487cb5292da5bc78b..60e3c5cbb911c10507b113a6b47b6277ff8446d3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf index 52706dc90320133d24a0a6c3109b9d1ef1bf8ec7..a2916f82be2bb2159efcbd2bb1b4037b744b43c3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf index 3de7c7734f88cc537915222a2fd265cf19a4f450..e3964f8e98354e0030fb28f547aa239b6bf6cc7b 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf index 12d92081b31eda6deaf2aa8b62e69c0535dfe225..712674fa22479ff9b21f78c415184515f0e505ab 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.default.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf index 52dc47457e65cd613c5cea2d2d4a4c05333cd755..e55c73487872ee73b69ee28308b5cc51cd8478a6 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf index d6c516eecdf6dbf6ed21f0f56403494a8275d365..b8b5cbedd64ba86a1605c2049a8c5c314bdb610e 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf index 128eae01645604031f9a5fe2619c0339f481c2e1..5e65b856807c18206de6b47233df8dbc8b9a0b26 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf index 2d2b65b0d2ba55182f69c318c72a3d06ca15d7dd..d2c5b79b4df91cb081e6c4532681b1285fba561b 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf index ac735b3cbdc72e1202709cd3e631eb96d3417601..e9cc364b2e4d1f1f8e3e2ca3257ffdb459cefedb 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf index 52dc47457e65cd613c5cea2d2d4a4c05333cd755..e55c73487872ee73b69ee28308b5cc51cd8478a6 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints-retain-gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf index 52dc47457e65cd613c5cea2d2d4a4c05333cd755..e55c73487872ee73b69ee28308b5cc51cd8478a6 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf index 1873672bfd893875698df4be191957ff3fd1556a..55a63e7ef97a79689f459c16342161c88a061ec3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf index 128eae01645604031f9a5fe2619c0339f481c2e1..5e65b856807c18206de6b47233df8dbc8b9a0b26 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf index 122b10976839df2becb1c9175f66b58195a1d4e8..27a579fa9684f88f3bc33ed91db6577152222db2 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf index 381e97e933aeeaa87eeb65132c6e889abcc5372c..bcd194dfa280762b5b080fff1641140e26b75ce3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf index 52dc47457e65cd613c5cea2d2d4a4c05333cd755..e55c73487872ee73b69ee28308b5cc51cd8478a6 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.drop-hints.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf index 12d92081b31eda6deaf2aa8b62e69c0535dfe225..712674fa22479ff9b21f78c415184515f0e505ab 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf index 1af233f482d63226cf4cb10e502e243b83c6fa4e..f4b4a085239704e72854cdf2af82caba076ef6e3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf index a699eea0bced6d31e273e28487cb5292da5bc78b..60e3c5cbb911c10507b113a6b47b6277ff8446d3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf index 52706dc90320133d24a0a6c3109b9d1ef1bf8ec7..a2916f82be2bb2159efcbd2bb1b4037b744b43c3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf index 3de7c7734f88cc537915222a2fd265cf19a4f450..e3964f8e98354e0030fb28f547aa239b6bf6cc7b 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf index 12d92081b31eda6deaf2aa8b62e69c0535dfe225..712674fa22479ff9b21f78c415184515f0e505ab 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-ids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f4b4a085239704e72854cdf2af82caba076ef6e3 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..60e3c5cbb911c10507b113a6b47b6277ff8446d3 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a2916f82be2bb2159efcbd2bb1b4037b744b43c3 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e3964f8e98354e0030fb28f547aa239b6bf6cc7b Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-languages.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f4b4a085239704e72854cdf2af82caba076ef6e3 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..60e3c5cbb911c10507b113a6b47b6277ff8446d3 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a2916f82be2bb2159efcbd2bb1b4037b744b43c3 Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e3964f8e98354e0030fb28f547aa239b6bf6cc7b Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..712674fa22479ff9b21f78c415184515f0e505ab Binary files /dev/null and b/test/subset/data/expected/basics/Roboto-Regular.abc.name-legacy.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf index 12d92081b31eda6deaf2aa8b62e69c0535dfe225..712674fa22479ff9b21f78c415184515f0e505ab 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,62,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf index f545375656b4f23db3020371ae4eb3435012aa7d..89abe99f2b6c15c59d3b0ffb27849864c19b44c8 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61,63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf index a699eea0bced6d31e273e28487cb5292da5bc78b..60e3c5cbb911c10507b113a6b47b6277ff8446d3 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.61.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf index eb84f9c9f6476def8c8c9485cd25becc45c6067f..aab73fd8cb0c7dd9026ab066ae0f4463e72c5042 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.62.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf index efd7c16fb7d344e3c25cf7f672d786a731aad379..0946e02c3c7b9179d196e9b5d27a070d153d367b 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.63.ttf differ diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf index 12d92081b31eda6deaf2aa8b62e69c0535dfe225..712674fa22479ff9b21f78c415184515f0e505ab 100644 Binary files a/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf and b/test/subset/data/expected/basics/Roboto-Regular.abc.retain-gids.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b577752aeb87a2c7dc23f975f0430f5591d692ec Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6f4814cc5a23c01f8b9dae25f91fe22b29777e33 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1872d24b1c4269ede0887e955e585b78a8886294 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14a544ad5fbf4d31ef8339d7393d2aa071d41bac Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5631ded6441e02eae47497894233aace366ab896 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34e878ee0e96c8d1abbe7f7f2d95d1f5c7f80cad Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1764f93290bb76300df4f6ea3386388f6ec28942 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.default.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c9d65ccc1e2ceb13301c4817e61d9ff526e7b6d4 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9b25457922eb26d228fe497e4f7c4ca658dc9f87 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7b36e6f10c34a91b36d7973276e40d429d15c39c Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1fcc8ca11281b3a02563f22fdcafbd3606289f5 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..159644469cdaeb941bd976967e33fbf7be15b577 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f7075d2f9c8a6ee341a899b19c7774a38784e872 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8a68548df6c80e531b76c0e423c5b72e1e289b55 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints-retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..073edc9325e5ee28e4c1975f8b50de0b7c353a04 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3d9c7828f520dfb8fd796255f11ea0eca310b044 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b8eadb047642dda7c7e587ace422065cb8203732 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a1fcc8ca11281b3a02563f22fdcafbd3606289f5 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..eabf61af9cd98faa55ab7fd15141564ea7f2b74a Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..936bb3c0a9fe5767bf896ecff8264815df0c550f Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..77f4be203724125738bdaf08ba13f31b7b63f380 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.drop-hints.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..79e2d5dc881a1506275014265344b3f90f78a072 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..81832019afefcedb74a3ec4dc7e8363a669b8967 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b465c5e58b753e830c4b3b01b27b858b974b4516 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4b7649d0363d99518a31d77e0b7982084472810e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3074fb34b940d95af39fc3593174303ca6dd5b90 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..18b002fd35568d6cb63386b0e570d10150456a02 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c627676046fd7cd7e9e324d6819150395c011acf Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.default.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..129e7f9683a94470350118a88a52227796146c5f Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ac583809ddd281fff995afb514e4f5eed45ed460 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..128da7ce6bc60c1dfaac80eea9c0ab3114b1ee73 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b2f7f731b02391bec92f4d90ccd305e174e8a860 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a79bd91081952c8b5cb7cec23919e7b337a80dfc Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e663b7bc41bdfa5c6a0a115cb4043145d02fccdf Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c5682520bf5b586143675e648ab893ec434bdb5e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints-retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fe772c9872a3505c4b3651a92c11170df85c96a7 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..45b4dedbdffc4e40e27a651415e8ffc30590c644 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1306b06f6d085da2338d80f2ea694b9949ca8d51 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b2f7f731b02391bec92f4d90ccd305e174e8a860 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..abd10a626d932831fb7503d5274af4b96b6f284b Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..36e40960abdb9880c3ecad21b47c24892f6cc562 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8659f8b6260d785f5075e4fb7e559e785b10e3c9 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.drop-hints.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2cee9505cc2fa37093d7ddcd1541258a843fff5a Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..70c9f1b3a46195884435a9bbc23dc80b4a4f9103 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..de9ec81db3da1520820ed45103792272968ff424 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4b7649d0363d99518a31d77e0b7982084472810e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..17a8911607e391ebb3e53b3037ff34ac6f8af719 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c63734d24cd4e230f187125af9e44b80d3ea2f01 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..981fdac6bdbb8d2ff1d37a104157ed5ea6bbd243 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.gap.retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6b82a2903e266056c35926b5baef7e863244a16d Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9dd4d2efb87c2242374a46c68f1c43833e2113d8 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a8034f7a85a30716da7a9406ba343c2d02c2f275 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c800f406fa00d6f0d84134ac4b76b275e796db01 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3792ec5f9aee84b0a2dd6c5cea52644cf06a4bfd Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9570f7a76ebb66db086a956e36e75e00ab33403d Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..54a914bc8d1437e872638e265a84ce67bf28415e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.default.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b2241cdcf5e832363b902393b9e33378048cda19 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8068d6e4b63c87ca1d01dd33506a3bdda5fb7b90 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2386fec10e0e8079901e485a20a381a70cc28860 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5b13eaf1b9e504e5679281d57390b45d324cc408 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b5630560182397cb1a2795d451a27cc6967e969f Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7e55cf5f7f8c8a0005bd33e24351b1cf3820e3b7 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..246e099708400cdd444eb0606587d4a6ef0df8ac Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints-retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..57414b33fc316585dc1c69845f6e3eff1549770a Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4dd5622a9e8f06cfc0991b56d2a4e231e2c247af Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..69d9ade248865e34fdb9322e9648a4b82e0c13b5 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5b13eaf1b9e504e5679281d57390b45d324cc408 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a7834d353e33b1cff188beb971ea771b3fc9ab58 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..362463c079f4febf6e16157d9f7b1d3ce41fb017 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e19a549ae7fa4bb00257f8c1c3eb1d24c7501e93 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.drop-hints.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f44eb72096a7f4dbfa9e56028c6f984569de36d3 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..96ea0aceee35cd12d092a6b49f919fa6c19f6e6a Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3e749ea0e86273c1e7c2f3c052580d0a432949ed Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c800f406fa00d6f0d84134ac4b76b275e796db01 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ea9f7977db060596096f2ce4d3a486b36574fc5e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c463b6488f1e8b366047931300321a5c673eb09f Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d9d73af263012ff45de8e953de180f74121ce876 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.index_format3.retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..91135db141b9fa6ee00391ece99da9732e66e7fe Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..327b5a9d7ff5bdd37d9d867b333c5f4b2bb6d346 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..90509e0a4f66216dbfd1f8d73e36830d9f2897a8 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dc414bc03cffe7f87fab68b181a26851e2a0d3b2 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e560bcb3720832c526185135743cc95a5d6b97cb Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5e6fe091d4bb6ddf6f658e843960c15942a24f2f Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2395fbca670989341f3ac84b3c4976a7114177e7 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.default.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1579c3c5bb6fcf9749bf6397217d682b042dfe4e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6601691a61deb5585644224340576b75a79e1e85 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9777dba31b2c615b208f3f1b49c6bf2649e41764 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f684e1774e219300f8cfddb5b426069675f28cd Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d5f7c44be7baa291d065f8ba878851cd2b8dc0d Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c6751236ae76dbd157661fa1d99322baf888f63d Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..40ab37f2792a70f72edd10ccf2c101125082bd22 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints-retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3314adafd6f7239628f15547d374be0380bbc748 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..11481e07bdfe06b5dc232c2497158f6cc88c42a1 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..66a5ce93ec758eaf2a6272ed480ca8cd5bed4a91 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f684e1774e219300f8cfddb5b426069675f28cd Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..aff5f6c3e06400b0a4fe89018f1e500c9165bd5b Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..359c37fc714198446dd994d6a564eaefb4425168 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f456bdb3019b8496526a502f2990494461ae13bc Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.drop-hints.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9bbbfc1eac668307b7d184aeb7227892fac0fc6e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..129b0c7a3626944adcded99e36153c3550221001 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6bcdf40f862e715730a882ef2c1c0b5137593315 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dc414bc03cffe7f87fab68b181a26851e2a0d3b2 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c55b0a7ad1f0cffe7c3a70072d5a4963b9a88949 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6d5fa0e9b42d3176f2e8bc02528368c8ba95c5bf Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..82e9d841ae304310b23158e832189e383c5189c3 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.multiple_size_tables.retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..968ed75e0754e30a9f8ad3b9721cc6fea63cda10 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2f14cad64a7a34417991384c6caa725055bd652e Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8e211fd169e361276fa33091f43a44458deea8f7 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,39,AE,2049,38,20E3.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,39,AE,2049,38,20E3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14a544ad5fbf4d31ef8339d7393d2aa071d41bac Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,39,AE,2049,38,20E3.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,AE,2049.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,AE,2049.ttf new file mode 100644 index 0000000000000000000000000000000000000000..06fbe73a46fbe54f00d8e12d06e8c03f4f50c578 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.38,AE,2049.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.39.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.39.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dc003fe99eb95dc402a01ea4f7539988b373c879 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.39.ttf differ diff --git a/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.AE.ttf b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.AE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c990eca7f6ed68a58798d6b6bdf74de8fab6cbb0 Binary files /dev/null and b/test/subset/data/expected/cbdt/NotoColorEmoji.subset.retain-gids.AE.ttf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf index f0ea3ca97aad985c355d7bcc3f66173115393695..36b2980a921dd6cbb6166243b91384178f913ae1 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf index 7ea55a27fdf247755ac9e423317208a8d7267752..c4c49ad0442b8f886b5d371b983fb9db2bb64535 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf index 07b9aa219b7ba0f48fe12d55b6146c314a63d924..be1e1d765ef0a52facb4a9b60090b5e948f379de 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.default.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf index 2811017ca78f4a1a57bf62a814f9f9391f4b2729..f6d90c169cc0a7fdfdfa4e9e6bfc747d773ec10c 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf index 98bbf38d6f64d31d3ba0536eb84db6648c5a2ad4..dd41df16bac47d783bc608cdaea6832d5435c509 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf index 2d88e570bbbd65529ea1498062d16b45531f64a7..0f59d858e57881de3470bdff38c0ebc0d21242ee 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf index cf0fbf6018981fc0e839effa29155cb4cabbfc7a..da612a06c1fcf289fee555454e651f4b0760624d 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf index 8ab8294ccd32a50b02244368da84a540c0d4cddf..f65ae3133cd9d67fec89708bb25e40037ae7915c 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf index de475e60a3a7dd475cc3070d980f93ed60c55ec1..41ea5309d1fbcf71d7318d7757a0312bb38f5b7a 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.desubroutinize.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf index e5775fd8d2656d9a827af24d7d5eb6eb9e19cbd8..a62bcc80b41f025178e3bb44c2f001ae0d039244 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf index 572ea742b737823bbd8213db7b1a290cb40d4cff..d57a8f06535a92043aef6b87a37860272e0d5610 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf index 376f658ca16a54917414e946df33e4a37a9f483d..3d645389cfae1f1312d8ef17b1e92f9935e531cf 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize-retain-gids.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf index cf3228d23cdb41f2fc1f16ed060d0b6f03e82765..29839512ddd7b76fe4d0cbaab5af5a3bd90de066 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf index 1bafff1239438896364ce13af454b911d5451a49..baaae1d66a1510611b17db0c09dd9ecfb3a968f4 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf index 34303e790a3d9d6445153ee0f6340bf187b4aa72..4dbbaa3d28d972db5014329c21ca1293ce9d195f 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-desubroutinize.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf index e23e37f4b3fe3ed38f7a10d589ae282a51204b81..cfa140fdfd39d28295c1f6300fb5e3d5f5b485e0 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf index b5a565e3ae16fe3d262687f9b46625193480e178..054f32ff0455e348023e766fcea2d029c3093f76 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf index 6045b4c6fa28f5462112915234e1ad041ccffef1..cd7fbc0122988b62dd5542ade4c9c69e3f45ddb7 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints-retain-gids.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf index 112dec7045f627eac83287c8bd9b635edd1ffe01..c600cd387dfa14bb58459b8b323f4eecf965a0a5 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf index 929c4e2d199ef215ae8b419b05d7ee4c58ab0895..6900288bab0a8f80eefdcd2c7f61ccc6220b4a33 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf index 939a565a99537829277c1f7b2f79c8a9e1ec512a..03785e1f4957fdddb72ded4bd3202ac3aa15dc4b 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.drop-hints.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf index e1613ac5f0082e160fb1b7d7fd48857f9f3855b3..cfbe2efba4676f5beb31294e06a193089f1a3156 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.1FC,21,41,20,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf index 479c5e0164f1d9cc094168c48a3168cfc2e8dcdc..b5111f138c6b268de7e689e668bfc4c461b1e35a 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.61,62,63.otf differ diff --git a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf index 95149dcfa3453787b99803fbb6f0fc3183419606..fc34389379fbe86f4ca1130db16c6a120767f5e9 100644 Binary files a/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf and b/test/subset/data/expected/cff-full-font/SourceSansPro-Regular.retain-gids.D7,D8,D9,DA,DE.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf index 6065be461a6986053d875c9d1a3c1f5fc77e0ec3..571a0f10aecd2d3457e39d3e2f93e1cef84556a4 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf index cee758499234d6bb48435298050c8d53286ea4ea..2556452f4edbebd3ddff6b8bdae47d78ab23bed1 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf index 0f13fa512f3df999ee6058f488d7ef042a99e35a..47344b859c0704ecf6d53d2f9dbffdb1bc8272bd 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf index 6db56f42d89970332ff16b2bf5db136f66412589..24b8302578b0639879dcf75c4111c0972676bda8 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf index 1b216ccb8899d7a59390b32a57a304c27cc3e34d..37c9aa3c279faed31423e3b65a2fba05b11b48e4 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.default.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf index 690fe90f48771a99a0f43eac9f5ce68f1ab7d7a7..e899c9d9b0c29f9962fc8cb293d1ea12f6069e47 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf index f1f0cb1bebbe5dab35197f961c919b611277137b..1c5006844a2268b459b52c0c2b19f38eff799119 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf index b353d43466e48e5fd93cc019d0aea85f0fdf7641..19691e321d789c83efef31b3890a075176b7cf40 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf index 7d966674c02af052e38288ad0d943f92dccf3c4f..ecc6e8685c99881647c8b025320179c4de5e9348 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf index afd9c3363acfc6cdf7663ce0365b3cd7a53ec687..3c9ef2d0c7eb3172744c976df91cb41590ac49a1 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize-retain-gids.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf index 1a47c85a6cf78611c70a2022fd75b9a3e20937f4..d70016f343a8f474e99545f0a6253e2d5ec1b5fb 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf index b69448b5e6822a63467077a4f93a3674a587bf0d..cc89e9fd695f8e857ae8f4a0cbcb77fc57ccf3ae 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf index 3682a0d46767a07d2c5be2194fe7e00a6a082037..f7031f91adc445d88b7659df3d6347c72625ed6a 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf index 6f98c8fb5204f883de03024e0c17eaa9fc94feea..eecc3a8e88d7d33a9ca9dcce4334c49bb3f48357 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf index 1497979a3d7f7a87bb0334d9eca8a5fdd349fcf5..49665316c4792ded55c75435a39aa13df7dcc02b 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.desubroutinize.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf index c728315ba46d08c048934b3776e2d54f74244142..48e7f87d9999f6028f777a49128e740effa57925 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf index 9a0e72600fdc2690bda1549d74027c4d66c3fc2b..cc1d0b95f39cd9ec0a04d2c1d43bb78f605456ea 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf index 513d47ee92217931165df3dfe662fc118831619a..5b4340c157716b9eab5298e177d280607928f8a8 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf index b10526d713f8ed3db5f1bedd395c29b9966ee15a..d2228cb94845113102566edcf67b8c06503db3b0 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf index 2684381c9bc70e07c1f08c8218f3f197520c6afe..d56cbb5e727aef245658c2f7e00d2b5811d055b7 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize-retain-gids.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf index 68a254ee1350570c751b7c993de60fb69c83041c..1889e5946de3bfca231d8451f66e1bf6fe0f7380 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf index b900d92a84f8792705a49110108ee2b2085d91e0..defc18ec5153cc06c7a3c10cea95c4698cbd34af 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf index 6b7cc2efe0d29ed902e084606e3976d0f612b03b..a57076771a706e61ae566f6023c3f7db96a4dac7 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf index 69b6b2e7492b052af1d95543c5eb4df66bad1001..55dc279ad27a448ba66fe86cd485519817b6f413 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf index 460baced3ba1c226da4896e9ad915ec087fe5515..c6e6b0925fb26c402ee988151e81627e984ff521 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-desubroutinize.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf index ecdd5d64a95004a2a762732b255a55b023a1ef47..095b62f51e8519dfebf418439985f26fb542c79f 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf index 77b1f95a3cdd050ce33375034b50d66cc62091f4..e02b0e4065cfb62c6162532536a5ddd1b226d173 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf index 8a1bc968a936955b32960f6d453ab0200c8addad..683df5f3bac7851593a5970131ee82b701efdc90 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf index 7d943fd2438eac127cfa5511e283e9983cbc633c..10e1a8d9cf1904ff6814bff421f2ee8a6b5ffb21 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf index eb01e55a3cf59e1a3002c48dcd18836847c61141..e3cec520dc51ea24c671a1d715e9f1122b815f94 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints-retain-gids.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf index 19c8ed86e97c6fa313d2feb5a35565915547ec4d..252f8c424c15627a29093c8bcb6fe197c24d5c68 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf index 5c7ac1ac3219ccb0ba1a64e538c9b22535059a58..78be9b0a8819e0077297fc4204370b23ecc9be65 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf index abac3dd75a073de79bab2eec652ee00cc496f215..0825d1bc170377e5c95d37d256d4e3f1af0535de 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf index e593d6df2038ae05bcb5c0e3a8133c9b7169cbe0..05484a3cab91de126e139e472944b4c38eac58cc 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf index e586904fea43f1fce612abb9db9d33050a0b3304..5edf7d2389f6a5825e1489b077a5bf0631a5ba25 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.drop-hints.660E.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf index 75f16131097863825a54b2b4d9bbc1924d3408ec..52aa46b785f8c82966e78435528275540a905cac 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,3048,304A,304B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf index 6f3794c34a2fe06909ec23ec8a07d54d930dc288..2c4cd816551b704e338310dd4c07f122ef406711 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.3042,3044,3046,73E0,5EA6,8F38.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf index 7c5f648c399b45c0a34087320f9b0d47244f0a0a..8495146e8961916b60762069cb0b9c01c8c2a065 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.61,63,65,6B.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf index 2dcd75b77f479c85e1b72a02328c65ce8bc3cb18..804df21a9310bbfb25a211258989051098d60fbf 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E,6975,73E0,5EA6,8F38,6E05.otf differ diff --git a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf index a5d40d0004db94a2083960a20987b43b3e6af4a7..e42e2c4958eb004a882f3a5bce3fded88df84378 100644 Binary files a/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf and b/test/subset/data/expected/cff-japanese/SourceHanSans-Regular_subset.retain-gids.660E.otf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5eb324e76c6b8da97dc4393f703ec5c95968640d Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,62.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f992c46043cd862adea3d2d2fd2e8f4cd4f92fdc Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.61,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEE6,FECF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dd44a81e614c73e06c1fde3c201553dcbac94be7 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEE6,FECF.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEF9,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bb09c4d5d0e196917520a5ab57a6239dd2e1259a Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEF9,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..209f0392239e497579bb82b3282cab297a9f4638 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.default.FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b61474dce76d2f39971f5ce6dd377faa98bb1a80 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,62.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..675e2d321dcde78d71798383ea84e4a91bb9c07e Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.61,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEE6,FECF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..12a9fb265520da32e0913740ae094e496dde1920 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEE6,FECF.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEF9,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..82ce49d2d3c93b48e20a122acae672a08bc68df0 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEF9,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..46ec429c0c442e409136d132eda772d53d633fe4 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints-retain-gids.FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..bdba814ee4228d6da24e3c7a88f3234f42b80b77 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,62.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2678e54640a838fb6a2c93e3c2c4a054ff51ead7 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.61,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEE6,FECF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dc1e50c41e7b2ca1f042f219a39e5495f7450a21 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEE6,FECF.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEF9,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7b2add8b9de5dc1d48eb379560429a1035b18ca4 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEF9,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1aa367ca34ca783b28317452e1586cdac800b243 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.drop-hints.FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b2e46572b6de1bea4d8eb1b003838bf976b62aa8 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,62.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..76dd00d516cc2b95a15b9f4e1f0e42b1d14b169a Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.61,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEE6,FECF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f5cdbfd272d880a3301e89268fe8d9df437aa64 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEE6,FECF.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEF9,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ce964fd524f6232a355a0f0f2c3c44de7cd9adb3 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEF9,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..859a7f1e34abdec3474be076f496be3d9622e5fa Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.name-ids.FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,62.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..745e32d4115d4b12341df6cf2cc7012efd44a44a Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,62.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6faea208c3c2ebcf873e2913123df6c475ea479e Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.61,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEE6,FECF.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEE6,FECF.ttf new file mode 100644 index 0000000000000000000000000000000000000000..77fa170d4aea6770de8a27dab27f3da3e6edb8ff Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEE6,FECF.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEF9,FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEF9,FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..54620eddd7e5174dde4a40c88ad1ed55ff7b66dc Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEF9,FEFA.ttf differ diff --git a/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEFA.ttf b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEFA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..06d379beb707e23365e8713796d757daa06142c9 Binary files /dev/null and b/test/subset/data/expected/cmap/AdobeBlank-Regular.retain-gids.FEFA.ttf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..fb41408b39f55156fcf586be404c8ee7a1621fa9 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..e50256d085b8b79c279c116474bfb16ec3722768 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..24f38717e68a9e60d17158119a2ae0887881c044 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..38672bad6e06d78019bc707ed1f8ebada674c240 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..c5f898ea43d765c07d021afbcd4599f620511baf Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..03cae07466ff54ea8c4d6b03191e606f2de490c2 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..2506a41d33061314d600180449560e8320805344 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..e8ebeb484fb410f365021a106dd54f7f98d09a15 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..910cc0fefeefa6789d17973a10f60c0f85cbaefe Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..d7d69727ea8efc843b501db445570256475790e9 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..a1c001ce3fcf8db95ba5df5878dba09098fdc16b Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..5b418025a3eaeb8b3d0a3a5a91d1f356b66175d6 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..b88e288e84271c0f78b0b40d2f0242948c7c1d29 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..6d95272a79734a0dad13bc479f7b928a188b2f9d Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..251568f3ecf243be88a228a34bbfbfc6696510fd Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..2b1d7a7b744d980c68e0503a595383e2eff789ba Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..dce7f14beab0b697d4a19f05b915580e42c8db3b Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..e1e22453a1a6aa8efd13b0adddcd751656c53ef0 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..f72cdc9084ba32ecf36b50a378101cd072244552 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..4efa2e2c68d2464b1de6ad06eb131eed2d2755ca Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints-retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..a440b96c21d9c298d92322ae808ff800bef934e6 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..c503e386a72f9c9dca7c7cae7ba66fcfa0ef63cd Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..d36d15543552f6c549441b07c4272a2c73529a0d Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..34a84693047c1fc5414236dbd203f0dd62f12d02 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..d695329ef6adc3fff5863925b749e6a182351d17 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..1c4d2b5edb55fb303711a784143b8b0cf7bab8da Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..e5981f03c2c364e5b6bf91a230918d6c9d0ff6e4 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..4b76f1c4d4544a40b5b168df5a3de31638d41634 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..cf602159a899deac15e2cca396e9f0f2b42be4b4 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..bf353ed1402e4ab2122b64f7cc6916c24b057af9 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.drop-hints.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..aecfd1c04d0431dfd21f68bf834a2ce309f3ff01 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..3249149bc25f54f73524605d41707104b41cadc3 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..1c17acfa46d982e4d8d930da2c5f518446b789be Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..4a66226557b6fafd5593ff723ce9329bd19720af Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..806f6890181e11fe897dfbbbd1d36ab437e1900f Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..55f28d4d6f092e39a37ae63579c38d89166b5089 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..d17a22af17f1b64dcd783227743e51b3a59f3ff1 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..cc4305dbfc9ba1962a5878ac553e797f32538b7a Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..f2093c9e37ec1c3acd2d74fc6677c3e07c0e0267 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..09c8f8df61aa8a2cec3f22c30ab315b623dedbc5 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..a7b67bfb373d9b1f507efdcc45cf7ec557f94a28 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..7c6805d886096355946679fdfb582bd25696ec0a Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..b1876b6c6e71957e0a36cb89677343257c336543 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..b07778f23b7f943f064065f56fd597962a46539a Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..fb776323c85df5ae0d2384596a7505a2973c26ac Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..4ec322c573041ea637fb64963a6277dc0d69b09d Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..ec2075586ea7174094a5ae6d51fe913f75463d60 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..bf2c086508bfe40b3dfab0c1b6d9af6346cd2818 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..0a3721e1e8e3ea12edb183f7e33c26c5d62d2592 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..eaaa56db43a49bb698f11c9940138174058f1075 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.name-ids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..5c5ce5c08e83e96ff4ec8b6bac3bcb70624f73a1 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..3b87f548979d510944bde65e32cc86b36dd2b745 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..e06a24df0b8d4680e78835250b777cba52e23b9a Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..aabdc5e80235df7c04790b3103d9f954e9a6fdab Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..4183c9f12126ac2671fb6b1ad900712decb63b1f Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..66ef901fe5b8a6348814951f48a973fb38d32226 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..4bee46fd7009a4f84043be690090cd80c236875c Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..6e8baa95ae078086cc27644193f3467c89e235b4 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..f6191dad165fd8e379397644f567f9445874c707 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..bf2746bddf47b6e47461cbda7d138c97a9bc0035 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..460e81bcf854aca89296ceff5f5d95491d0724f9 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..f6df4cf38e7137afc19cc3012f6c98b34648b9ef Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..5d15cd7a6c5a61a219f8113681a24d0ead67dbf3 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..71bc4d6fa4d5dbed13c0c6d9c0a192ed4f48f356 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..f28bd1d68dd255c3c71e6e5427af67dc81070404 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..d4401c73c46d1d684ddc05e6d4a1b224b892c65f Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..65c74c4aecaa3df1554d49428e8c4e3ddef4ac6b Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..97942772c8a33cf514652198ed5419ad1faa68df Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..dea9124d1b86be978613c894840504d39cb6366b Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.default.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..12365f4525244a7e72124f6aa882b2d9c0d539b1 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..f7679f5fea1e604881e08dcca0220e27f3603aa4 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..327f83f593b8ff7d438d00a76e28f14e4f0d65e4 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..a3289fd5f303b0a054ba1f0fa893abb4380ca278 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..d0ba8604ff93daf3af69b352b6c065874c6e69bd Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..9707490ccf5e584ed90c50d304ffd055b455c255 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..f5de519271a80318005015ea54ac3a06af5ee0e8 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..9203411ccb749a8d40d6e56d25dcc35f089fe7af Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..d7b13afc54be263b1355ad82aea699d370f00594 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..ae141a6d2e3d934e0883d9aef8cb0b259a518058 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..646ed6f6489c14cfbef28de602dd7418e8f9e91f Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints-retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..04934520ed6cfb3cdc7a15de85aa8c6a6b328382 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..2322e5d2f4e1f6a7f0c08461c444d2de245b1635 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..6b9edac0f80dae13bd27c43bb588b65f3c91d9ef Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..9f243b8eb4f6fc3afe259d5b2bfbb2775951d556 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..8954cd74e518bb5fefa32bc2ac6a82acfe57ad1b Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..e623928636ab73f6820b6cc3ee9b7375ad718878 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..51237ad2f7dfef7d867b4f7f13c8984bc2f901fc Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..e219c39cc032cf632dbb9aff9b96724c45705022 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..9fc0bda2daf09e08eef26f408c76a27bbec9b056 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..02232eaee298dd841e0b45e4f229a4179935a3a8 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.drop-hints.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..f9022879027c6828a192ee2198b66fed3aa6a916 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..426f7692ca76bb3cab7008a880368c8b48628646 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..0c2674a0b039ddcf49a578cd61aed3d336de0333 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..a59de5dffdc63705808bf6bbf6fdaa58eb4db990 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..6a5a3a774346be8025a062c5aa79911825a68502 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..df159d0124eea173f4bd6798bba207ec031a1005 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..9b9f2b4d59a60d802595b62389886c4ec14fe3a0 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..bbac4f5c178c3e965212f53013cc5157c2210882 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..38b3fa8b21c8fc806b123b60a2cd30518e8229ce Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..3996080d95bb181e5810425c598de7c46bb2184e Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..021c9805be5297f3f21fadd414913a92f855fdcf Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..cf3a5b3f47bad5183fb4bd415b47c20ecc7f17c8 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..7c537c13a9bedd44523c8948413ac40c85c52eb7 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..f24488b37cca303ce3449b98b56c773a4649ebc2 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..8d9e65a38e7fc1a87b7c0dac47a41d13b4abdf38 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..f2f5ba03ada7eb3cac9c1a5af212963cef1b7f25 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..aef4bd39022afea8baaf98049f02c14e90a562c8 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..f24ad1fd577b9507c1120ea64c585a8855625981 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..00c466f26bd0fb4bddb94aad337ed45fd21e1aba Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.name-ids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..86fe67b150c715d110450eb93bf809fc61ecfa6a Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.name-ids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E02,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E02,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..0bc930a9d03ad44f5da8917573906a851ea94d6f Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E02,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..9746b455933419105ade25262142ec66d5413096 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E05,4E07.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E05,4E07.otf new file mode 100644 index 0000000000000000000000000000000000000000..2d378d85a6a68388dac06543f65a4ecd8537b81c Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E00,4E05,4E07.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E02,4E03,4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E02,4E03,4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..42ada2ee911acc7c4d685aa591f35709b106ca0c Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E02,4E03,4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E02.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E02.otf new file mode 100644 index 0000000000000000000000000000000000000000..7e4cf58f0c016ed3462a269a9e88f31a94e65953 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E02.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E03.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E03.otf new file mode 100644 index 0000000000000000000000000000000000000000..846fee5c5200672e286ab62c57cc1ea36fa196ed Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E03.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E05,4E07,4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E05,4E07,4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..018805cd0e542ba8fd7fa88dfde7b6852560744d Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E05,4E07,4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E08,4E09.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E08,4E09.otf new file mode 100644 index 0000000000000000000000000000000000000000..1945b0b28e241298378427898867504eff555ecc Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E08,4E09.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E08.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E08.otf new file mode 100644 index 0000000000000000000000000000000000000000..f45fda15b2b8f6647c7e8fa7f5a3d03c70b8d931 Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.4E08.otf differ diff --git a/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..ac622b63cc16f5109ba3e37f563de970e123af2f Binary files /dev/null and b/test/subset/data/expected/cmap14/cmap14_font2.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..357dda3b96d86c569e94f579d14a2c87bc4cfbce Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..adedf7a98304b62c0008f67479ff837df257d93d Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1fbce419b97602c141151035a2b74db1c68a343f Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34ea336085583864af7bcadc8d289acc8d6b93fe Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.32.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3d021a24588ff529728f9520acfa38ce8789e666 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b8c6e6be49f9eafdd1b457b37bcc08d8f365ccce Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d2abf386c7228bb0657aa522b99e360c73faab3d Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.default.3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3644ec01f94976d17dd71c3faa202ce06b0e28b0 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..81c92b499f4326a118b241eadafbefef533a67ea Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..37ab302b4a0f6e8e781861e0ae6de31d12fd142b Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c84776dd084ff686c726b90e0886a1b0155d185f Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.32.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f7f8ef51622a7448f88e0c6a359bd39129805dc Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..271c6b412a348063e9e335b4d4ece06006a6e3d0 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..88b4ec94c3d28f863ffcc94a822177623290e15a Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints-retain-gids.3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3644ec01f94976d17dd71c3faa202ce06b0e28b0 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..12040a129157c4df0b8019a2500f8b5d1d3536cb Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ab4b9e24f37582cf1a87c9667f382ce10ae5cb3b Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c84776dd084ff686c726b90e0886a1b0155d185f Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.32.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7707dcc339763598f7be02fb8ef3889e3383e7d5 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dd0e1a9bd5f44d36d2fa1f153c83693f3d306781 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e59928b574fe048a47f1fce6e5f0cb65d33278d5 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.drop-hints.3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..357dda3b96d86c569e94f579d14a2c87bc4cfbce Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d04142da750d6aa8042095f3d6a2b1086145af7c Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..983eb75766471f8b0c32d2627637cbba1c3c9b67 Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34ea336085583864af7bcadc8d289acc8d6b93fe Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.32.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297,3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297,3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ed602762dff8aba8138d43e3c55ea82c49ac68bc Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297,3299.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297.ttf new file mode 100644 index 0000000000000000000000000000000000000000..60a5a3aa53fd30b7e2f04c50825d1e0ce60c1b5d Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3297.ttf differ diff --git a/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3299.ttf b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3299.ttf new file mode 100644 index 0000000000000000000000000000000000000000..803af3f4922045773f48cda780948dc6fdd96c2f Binary files /dev/null and b/test/subset/data/expected/colr/TwemojiMozilla.subset.retain-gids.3299.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf index e8b7b375c81b39eeb81f67966e165c144dc7bbdb..e644241acd4dd7cd825e0c8d0b1c406f49dcd506 100644 Binary files a/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.default.1FC,21,41,20,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf index 912e1fb2452d3bfe0a6161603df6d9be42e6a24a..32340c4fae3707e8ed1c1386bd7a76632359b8de 100644 Binary files a/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf index 6f19df6e261431a07e0e87c6ffd7824209ce3232..97863b6c8c8ffa0c24d3b8ed6242b95126cd69ad 100644 Binary files a/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.default.D7,D8,D9,DA,DE.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf index 9ea42ab0960415a70faf933a45d5a75aed1bdeeb..c51a5e4cc7eb32a8cd9fab52420c258fd5cd0eee 100644 Binary files a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.1FC,21,41,20,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf index 4d125939c6c7aa4f0654a27ad5e45ca25ba4fe7a..38cb8f7ad2a6caba44c1744e7313fdc5e391edbb 100644 Binary files a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf index 281b47523407df5ca94270dc96c51a84d8d998f1..8c7a34148dfa54d1057372d1478208c444292bf1 100644 Binary files a/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf and b/test/subset/data/expected/full-font/Roboto-Regular.drop-hints.D7,D8,D9,DA,DE.ttf differ diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a8c7e64ee03191302e10589c3319177032712e45 Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.1FC,21,41,20,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..36825cc59c759f0f50550447a4df6e8a260cc160 Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.61,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34cb87aed604fe63cf9cd06e3eb99422d1415c96 Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.default.D7,D8,D9,DA,DE.ttf differ diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7fe00abb4801e1a6adea8669acbfe9f53be0e9d8 Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.1FC,21,41,20,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf new file mode 100644 index 0000000000000000000000000000000000000000..36825cc59c759f0f50550447a4df6e8a260cc160 Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.61,62,63.ttf differ diff --git a/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34cb87aed604fe63cf9cd06e3eb99422d1415c96 Binary files /dev/null and b/test/subset/data/expected/full-font/SourceSerifVariable-Roman.drop-hints.D7,D8,D9,DA,DE.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.1D715,1D7D8,41,42.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.1D715,1D7D8,41,42.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f4b0f011e0522635f1be8b5c6d611b57f91c1364 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.1D715,1D7D8,41,42.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.25771.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.25771.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0e0f8be07886c45a1ef0a1c19f5e1b52e93c9d1c Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.25771.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf index 6770dacabc0e8f1a1a26e8be550fbee4ff2e5164..32097ab5d161e4266a343da1d10e1d87df36c4d1 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,3048,304A,304B.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf index 0c662199c2ffa5dad0eea90f4addd2aa5b612985..c08c3e579b7b78188529921925ecec741781faa1 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.3042,3044,3046,73E0,5EA6,8F38.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf index 4a5a6f8ab46606409d5767c43a4339e5bc2a3bd5..cfe6cff8f5e6a6ed398fdcdfaae396a430537ae9 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.61,63,65,6B.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf index 465ce3479c94571b9cbd69d397fd08fa2d4c63bc..28ecfc8cc6781bac5656059325a88462a7d0ba05 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E,6975,73E0,5EA6,8F38,6E05.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf index 28f3c37176247003ed8d82e838d44757a0598d64..770b034c4410403a595864e216f226fe30568a06 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.default.660E.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.1D715,1D7D8,41,42.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.1D715,1D7D8,41,42.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6da7d3094826e0ca35dd7e7621695c00f1ffe44b Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.1D715,1D7D8,41,42.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.25771.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.25771.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6d8aa5d8086120951a4054be49e828733805f08b Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.25771.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf index 1bebda7f284ad9969f325879799f50ec3cac83b7..8edadb54dc7bae0e74a045deffaccc55ce45d39e 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,3048,304A,304B.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf index a43998d1bc3de7d7944f31430dc8f6b0f99052ca..78b7199ef729953cf0e9d28099724ffad2eaaa88 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.3042,3044,3046,73E0,5EA6,8F38.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf index 34c7788b405fad3cce9032f8cbf4dc7cf54ed65c..76a5151f3b253a11ff05023eea876b0052597a1b 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.61,63,65,6B.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf index 92ec10b57729ccafa3f8293fb1a39bdaa1a5b8e6..b4abab9257b113b82b1f2c5b1f8fb8927a02b53c 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E,6975,73E0,5EA6,8F38,6E05.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf index b9bb5397495e2d333ef651822342c182ca788012..4f7b482fa073f72df74bad373fdfb623bf8cb0bc 100644 Binary files a/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf and b/test/subset/data/expected/japanese/Mplus1p-Regular.drop-hints.660E.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.1D715,1D7D8,41,42.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.1D715,1D7D8,41,42.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f4b0f011e0522635f1be8b5c6d611b57f91c1364 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.1D715,1D7D8,41,42.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.25771.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.25771.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0e0f8be07886c45a1ef0a1c19f5e1b52e93c9d1c Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.25771.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,3048,304A,304B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,3048,304A,304B.ttf new file mode 100644 index 0000000000000000000000000000000000000000..32097ab5d161e4266a343da1d10e1d87df36c4d1 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,3048,304A,304B.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,73E0,5EA6,8F38.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,73E0,5EA6,8F38.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c08c3e579b7b78188529921925ecec741781faa1 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.3042,3044,3046,73E0,5EA6,8F38.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.61,63,65,6B.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.61,63,65,6B.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cfe6cff8f5e6a6ed398fdcdfaae396a430537ae9 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.61,63,65,6B.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E,6975,73E0,5EA6,8F38,6E05.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E,6975,73E0,5EA6,8F38,6E05.ttf new file mode 100644 index 0000000000000000000000000000000000000000..28ecfc8cc6781bac5656059325a88462a7d0ba05 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E,6975,73E0,5EA6,8F38,6E05.ttf differ diff --git a/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E.ttf b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E.ttf new file mode 100644 index 0000000000000000000000000000000000000000..770b034c4410403a595864e216f226fe30568a06 Binary files /dev/null and b/test/subset/data/expected/japanese/Mplus1p-Regular.keep-gdef.660E.ttf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b1a0b3c8f65b5235dc6d7dbc85533834e5d2da25 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,42.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..b070e2bc9a3a19f7692e01e52f33098531fcad85 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..a2715ef0d0b0b5c021f13d31d996be656e6aeca1 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..c94a78f60124a5a4c10c22918e3189d332b7d6bd Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.41.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..6354eff8fc1a7fe36a8a8cb7c1ebca8dab9df12e Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..41f4ff45ad714da25558235605f89d7f0ca20edf Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..67e87dc0ed7c4caa2654cdbb9c62f07702eed11b Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..47fe5d0801c9c547db3a06cc46109946004e1c61 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..48e05245f9cfecc599847f225d8ee2af57c9d461 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..6354eff8fc1a7fe36a8a8cb7c1ebca8dab9df12e Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..3deac416e63e1c1af5e5bbc8323140d2d88c78c1 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..5f0ded38042ba23a46501d0366d6b1d01e062c70 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..5c14c1b8d96b1a59fe52c01337c12b20c7bdab35 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..2152ca7fd2f6c711d459b2fe995baa1c068c2481 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.41.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..0691569c75deae8d2597e36f831c6b42ab0fb3ee Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..520a37393bf9e8674f66719c7618bce47b993df7 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..b9e8c99f14aa2bfe86966c8d2ca129a5dbcfa47c Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..52fcc8c62af1a03132503441d82fdbf2bb4f8a51 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..ae6325f7da799953a199706fe159cb00f7fcbd0b Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..0691569c75deae8d2597e36f831c6b42ab0fb3ee Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..7c11995486b6f8b640c1f398e042470b290c1c62 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,42.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..2ee02fe34632a94694dbe741967a242ed82e5fa8 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..6e881ee476c0262d808c45b077c7d1bfe615d0b8 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..a4c8c42cd4bc66f716338f46bfaec70ad672fdcc Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.41.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..684e9912612807dd0eeeaae78f8a1aab6f5925c7 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..ab85997155b8eff32a6a7c72ec50fabe7c923404 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,42.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..ca3494fe692b0663d3d0d09095129e032a14a607 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,43.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..58c9bf42e841f43498f487d12d19b6a483a044ea Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..84bae1acfbc92a0f60e559cf0205e8a1d49aa7df Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..684e9912612807dd0eeeaae78f8a1aab6f5925c7 Binary files /dev/null and b/test/subset/data/expected/layout.context/gpos_context3_simple_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A01.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A01.ttf new file mode 100644 index 0000000000000000000000000000000000000000..38b6f410784256d6554d6a35dea65e9b68443785 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A01.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A05,A06.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A05,A06.ttf new file mode 100644 index 0000000000000000000000000000000000000000..97a197a2db14c7fe16eedca9959f961792f1afdd Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A05,A06.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A07,A1B.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A07,A1B.ttf new file mode 100644 index 0000000000000000000000000000000000000000..539dc167454b8d2e2da5f4ea41f566af7174799b Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.A07,A1B.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..72b23dddf98e7c7be457394ec69df6778da99267 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.default.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A01.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A01.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dbf36e544c04ab8c77b4ba207e06532da00a31a0 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A01.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A05,A06.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A05,A06.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4f01a346bf4b39aaec96a92b0eed5c019e2f8bdc Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A05,A06.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A07,A1B.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A07,A1B.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a76c4f75e34d2be5416679286ecc26e28ffc4bff Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.A07,A1B.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..75a510f7caf860b069473d1fa27958d89e11ea8d Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.drop-hints.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A01.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A01.ttf new file mode 100644 index 0000000000000000000000000000000000000000..38b6f410784256d6554d6a35dea65e9b68443785 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A01.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A05,A06.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A05,A06.ttf new file mode 100644 index 0000000000000000000000000000000000000000..97a197a2db14c7fe16eedca9959f961792f1afdd Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A05,A06.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A07,A1B.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A07,A1B.ttf new file mode 100644 index 0000000000000000000000000000000000000000..539dc167454b8d2e2da5f4ea41f566af7174799b Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.A07,A1B.ttf differ diff --git a/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf new file mode 100644 index 0000000000000000000000000000000000000000..72b23dddf98e7c7be457394ec69df6778da99267 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-attachlist/IndicTestJalandhar-Regular.keep-gdef.retain-all-codepoint.ttf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42,43,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..574824a5f4d4c01b29f913b49770c946ad07da89 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42,43,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..d946c63e61cdaea6aabb53212842a6944b477ab0 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..aa13f114a1a7075e4f9bcf7da13d238fb0a3b24a Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,56,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..eb57e403b5b479a84dda28c11ebfb552fdb4bc61 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41,56,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..8c351f7212101acf6ebcb998dd6ec267c272ff8d Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.41.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.42,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..7cc801ab6ad69ae6819e4ac5ad89c0e72947f749 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.default.42,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42,43,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..9bd8d65338ec04874bbf2f03881fdd6dc2872d30 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42,43,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..08f54728ec8ac441e7fe1805aae24d841814a4d4 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..f51c9c0567fc297b2470ef4fd945784dd5a22b17 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,42.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,56,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..97d85034b875c832a67f0a68f9e5a27f006c5722 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41,56,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..3a8ea5955058e16c8e1312afd472f02dbe1d307d Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.41.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.42,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..88abc1c8060b0e3f0022d76b9897890b43d5c1bb Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.drop-hints.42,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42,43,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42,43,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..574824a5f4d4c01b29f913b49770c946ad07da89 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42,43,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42,43.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..d946c63e61cdaea6aabb53212842a6944b477ab0 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..aa13f114a1a7075e4f9bcf7da13d238fb0a3b24a Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,42.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,56,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,56,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..eb57e403b5b479a84dda28c11ebfb552fdb4bc61 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41,56,57.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..8c351f7212101acf6ebcb998dd6ec267c272ff8d Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.41.otf differ diff --git a/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.42,57.otf b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.42,57.otf new file mode 100644 index 0000000000000000000000000000000000000000..7cc801ab6ad69ae6819e4ac5ad89c0e72947f749 Binary files /dev/null and b/test/subset/data/expected/layout.gdef-varstore/AdobeVFPrototype.keep-gdef-gpos.42,57.otf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d39d65450d9cb1170d7cd888012b250f440fe878 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.1E00,303.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9534fbc9a782f414a98b7adf75ea4974dc81dce8 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.303.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf new file mode 100644 index 0000000000000000000000000000000000000000..64d53dfda682759ddda11e332b8f9e7e2ec77551 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.309,20,30F.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d8cb70096595300d32b68f8ee2a63b551576732f Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.323.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a4a5df187795c5597d6fa36320e5938b190ac999 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.default.41,42,43.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5e4e48046aa74e49dfe3cf34ad6d98e5282e509c Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.1E00,303.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c463e546f55cbbf70113ea63dd3c3ba077b71528 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.303.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f721be6c533d4bd4341a8fee58cf4e1cf977a9ea Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.309,20,30F.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf new file mode 100644 index 0000000000000000000000000000000000000000..73100d59ea9fb144e9bbe47abb4907d353676912 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.323.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf new file mode 100644 index 0000000000000000000000000000000000000000..762edc70dcfdaec1a0c63260d4cb876b0749c602 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.drop-hints.41,42,43.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d39d65450d9cb1170d7cd888012b250f440fe878 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.1E00,303.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9534fbc9a782f414a98b7adf75ea4974dc81dce8 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.303.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf new file mode 100644 index 0000000000000000000000000000000000000000..64d53dfda682759ddda11e332b8f9e7e2ec77551 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.309,20,30F.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d8cb70096595300d32b68f8ee2a63b551576732f Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.323.ttf differ diff --git a/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a4a5df187795c5597d6fa36320e5938b190ac999 Binary files /dev/null and b/test/subset/data/expected/layout.gdef/Roboto-Regular.keep-gdef-gpos.41,42,43.ttf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..5277309e99ae8b6c911eab34546803eef7ca3204 Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..5a74887dc7014eae60bbd63f8f473a37c5cb2eba Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41,46.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..1caeeab35bb31f929cbabcdada1f172659264040 Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.41.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.default.42,44.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.42,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..09e38d5ffbf4f8bc4cb6f941de99012c58696fc9 Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.42,44.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.default.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.43,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..c429dc98155dc32ba00793ce531bcd303a69c48b Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.43,46.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.default.retain-all-codepoint.otf similarity index 100% rename from test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.retain-all-codepoint.otf rename to test/subset/data/expected/layout.gpos/gpos1_2_font.default.retain-all-codepoint.otf diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41,43.otf similarity index 100% rename from test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,43.otf rename to test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41,43.otf diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41,46.otf similarity index 100% rename from test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.41,46.otf rename to test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41,46.otf diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..e56bbf4c5aec6fdb3dec94cc9755a08a84e32712 Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.42,44.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.42,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..eb8f88ca28f66c9c13028930673a36628635d3a0 Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.42,44.otf differ diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.43,46.otf similarity index 100% rename from test/subset/data/expected/layout.gpos/gpos1_2_font.keep-layout-retain-gids.43,46.otf rename to test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.43,46.otf diff --git a/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2d6962bb6d625653ff44c09d9c5b959a14252aa0 Binary files /dev/null and b/test/subset/data/expected/layout.gpos/gpos1_2_font.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.21,23,25.otf new file mode 100644 index 0000000000000000000000000000000000000000..47fea1ac694d2ae6e27847b48d557d969ec17f57 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.21,23,25.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.21,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..99e813fc5dd0909daf51047ec70670bc2e1dbe49 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.21,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.2E,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..7ffd4689adfebd398b37722bf4ac5e3a2b36ec8a Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.2E,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..852808e453f59d71253f68cf396be093d55ebe23 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..8f18b89c6eafb66b9c388bcff406a362b5caa48d Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.21,23,25.otf new file mode 100644 index 0000000000000000000000000000000000000000..49039feeb61b24f4061b8261e1bf6c70507672d1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.21,23,25.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.21,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..68cb0ec5dab7197778903d54cf970598041f842b Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.21,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.2E,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..849a7c5b1ea6ac647aa08fdca20baedf304e0bbd Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.2E,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..597223417bb1fb5ceecf2ec830c9c9259c9cfd47 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..8f18b89c6eafb66b9c388bcff406a362b5caa48d Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_1_font7.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.21,23,25.otf new file mode 100644 index 0000000000000000000000000000000000000000..f227d5ad605e099e9ed975f6b02d4754fce45db5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.21,23,25.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.21,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..a785d496776cd04d75fa5b0bd72759fcada34552 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.21,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.2E,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..a80ccfcbc2a2806ddb12a58b16ff46eb4f32c57c Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.2E,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..3766e7f65f9a7610ef555d5f2ddbe9f1a67ad27b Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..aebc39673a8aaf5d911945218a25d64c595aba52 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.21,23,25.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.21,23,25.otf new file mode 100644 index 0000000000000000000000000000000000000000..77c408cd17e4f96a201731feb850ecab94a91242 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.21,23,25.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.21,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.21,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..9abdd3204421ce38d15c42031d7497f2f2d3fc64 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.21,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.2E,23.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.2E,23.otf new file mode 100644 index 0000000000000000000000000000000000000000..786de302894f08ad3ea95f87769c3b2f17c319ab Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.2E,23.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..1fb3d12e8a8402c61dfc9d01340f5d8fa66d23e5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..aebc39673a8aaf5d911945218a25d64c595aba52 Binary files /dev/null and b/test/subset/data/expected/layout.gpos2/gpos2_2_font5.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.default.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.28,29.otf new file mode 100644 index 0000000000000000000000000000000000000000..f3ca19a2f83b9e926df6020e96f13833353eac05 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.28,29.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.default.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.28,2B.otf new file mode 100644 index 0000000000000000000000000000000000000000..2a8114ad6c552edbe2993802101ce50084994975 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.28,2B.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.default.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.29,2B.otf new file mode 100644 index 0000000000000000000000000000000000000000..1426d50af5c31725db2d1b4570c7740fe9659bbe Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.29,2B.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.default.41,42,43.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..aea6a560acebed494075c1af61d11f7af7201154 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..8dbc8200da8111d0f6aa4cbce88b4cf3e9a8ebb1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.28,29.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.28,29.otf new file mode 100644 index 0000000000000000000000000000000000000000..17aa6d8332275e2861ce1e4f8795d56ff45e070c Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.28,29.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.28,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.28,2B.otf new file mode 100644 index 0000000000000000000000000000000000000000..9e6f2eb84f7c469a6033adcf3ebb67066c733441 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.28,2B.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.29,2B.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.29,2B.otf new file mode 100644 index 0000000000000000000000000000000000000000..0187ed7b9c08d095607b903eefc8ac26ad82cfba Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.29,2B.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..5c6dcee12d776bd55b728d7163b56bb832c8d341 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..8dbc8200da8111d0f6aa4cbce88b4cf3e9a8ebb1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos3/gpos3_font3.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..5447973d58353201e793e51c33627d32cda2ee60 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..e6c891b2e7a23a1e833d2c803f8dc148fa2ca447 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..127f798f3666520c79b23c440e620895282224b6 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..6cafcb8313c29d5d0c60adb3f3e39fec07c15dca Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,44,45,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..5f4754268bf33dcd62f6d57751b5912ee5141369 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,44,45,46.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..8fe4d63eb220a9a18c2b0266421e7cec6e477efa Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..147ed5782449830e31190abe3f8516e2761a0206 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..1b0f24362c59597c5ceb74d5f730f2771a0355a1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..657b6867416be57f566b7ba2ebd28db5ca079e9a Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.41.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..3765d20de9808a9cefc879d7ff6fd84ef465861e Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..1c2e5a4622a044448605628032c0c1b53960353c Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..2fed45d31783595e44f0c0a9fb3e24780779e5e4 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..00076157a5f332b4aed08550620dc0010493fc0b Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..8eb6ace1982a6bbd89ebc84d7d4cce4c43959538 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,44,45,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..73315f3ed5395d3f6eca3e95836e963e5cb3927a Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,44,45,46.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..4005a0d77cf504b194899df1ba038c9fc89c508d Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..c9f261ce9d72d8dbd9b40eca89b9b49b910ec1b8 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..9ed6a9b77ab599193cdd6c169d9bf60dc1821102 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..f50cc90bc860508a22ecb4021252f767f4d23649 Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..3765d20de9808a9cefc879d7ff6fd84ef465861e Binary files /dev/null and b/test/subset/data/expected/layout.gpos4/gpos4_multiple_anchors_1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..3749d354523d7c349893697105565a099985e328 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..5d4fcee062c719845a678d7ce5779f80d6a44cfc Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..54fc0684b25a0e0761f10cd5e45f0ed7c6793a66 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..d4c95a645054237bd3b836d60d73ee6aa8847739 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,44.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..656792d7257a318a3ef675ece1643cd38e45d788 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42,45.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..cc2f5f7eec9f6ae43926362954770e7dbdbebcc8 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..946c63c682a895516200f026e245c8759fa964d5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..093f4eef098b4ba9a99288f429e86319a7bde68d Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.41.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.42.otf new file mode 100644 index 0000000000000000000000000000000000000000..9e1aabf1ccf30b36748099d3ebfa7621918b4f91 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.42.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2a82c60bd849405d96f9b4026f6a122930b72ca5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..13a1fb7850b1db697631d89a87f6832d87cdea06 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..51533581f11490b94578ef6059755d71b32c546b Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b7a0bc625d42d2de4c452fbd5e84257dfaa811bc Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,44.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..bb7d74b52ce8bd7d33cf14172c539f479a4edce7 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,44.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,45.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..0da7880e31edf385258188d93971f4a4b64e36d1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42,45.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..9b6e1589ff218a59d8421cc87f6eae3b13cb6bbd Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..c28bed156d37aa42b8f3fd980c6be4b754e015da Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..7878d4b8f9f47be6e9ad958479c39459ea78453f Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.42.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.42.otf new file mode 100644 index 0000000000000000000000000000000000000000..f5824e48048ca947c5dbf402407111d4ff59b80d Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.42.otf differ diff --git a/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2a82c60bd849405d96f9b4026f6a122930b72ca5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos5/gpos5_font1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..106c55abc738fe07439482046b1904e5dd6fdd35 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..ba37625a1bf85359bccae5a4ffd4607cad333e98 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..8a6aa87e93b049e281d7c8f33f11bbd50bbaa8c8 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..1b8a1cab122f03d590ed97d8e1646615e7578a9d Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,44,45,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..09e27e695b1392be4bda060b6e3a7889fe671d9d Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,44,45,46.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..48e8928e3a49ddf942f065c652c48c1ee5f23313 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..e4656fe0217d30a517306823f2690b0f1e250981 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..5527d9ff4252375159c056a915b071803c110ae5 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..c151b9d8a8f5132b982b60fe28e71163831c7d46 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.41.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..0feba1bd61371788f1ae5c109bb32bfa8aab4293 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..92d1e28f9798737625e94efe04b7f63afb5ef022 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..28d5cb4955433aedeeaa403e83d43dee5cecb39d Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..7d58a98f7da34dff4d1638c28da2627825f95395 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..426108161a0ceb66668547d74400116e65a8a929 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,44,45,46.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,44,45,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..d944ebf9281785cfc2a72d8be86c095bcb1005df Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,44,45,46.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,44.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,44.otf new file mode 100644 index 0000000000000000000000000000000000000000..7dc3d6211e151cecb3eeddcdab843990341e73b1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,44.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,45.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,45.otf new file mode 100644 index 0000000000000000000000000000000000000000..f7727d4fd8205b2fafd02b2c5ce2ce116b8af18b Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43,45.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..7e564d5d0702b63e2fb21c5d6df37bde5e7a45af Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..c9ae1c71f2713aeb3da9972406f36389e054c075 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..0feba1bd61371788f1ae5c109bb32bfa8aab4293 Binary files /dev/null and b/test/subset/data/expected/layout.gpos6/gpos6_font1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,623,62D,644,627,645,2E.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9862336a0a0ea706c4414ac3605dc25ba7e8424b Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,623,62D,644,627,645,2E.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,62D,628.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,62D,628.ttf new file mode 100644 index 0000000000000000000000000000000000000000..00f78036bafeede17d3e2af4d9e6d3a1ef4545d4 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644,62D,628.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c1537155b77ab995b1d1a13466065dc9aeabd05b Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.627,644.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.633,645,627,621,20,644,627.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0e5dd57b9f454a30a04fec8814d14666267a2eca Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.633,645,627,621,20,644,627.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.63A,64A,631.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.63A,64A,631.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d27cb63003dbaf7acc8e6fbd9e0b0a8bab993f0 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.default.63A,64A,631.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf new file mode 100644 index 0000000000000000000000000000000000000000..494dee006d1dc280c4e327628e024f578af426c1 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,623,62D,644,627,645,2E.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,62D,628.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,62D,628.ttf new file mode 100644 index 0000000000000000000000000000000000000000..f4a1ce43a48b6309e4ec6de61455a14fd9e9006e Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644,62D,628.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644.ttf new file mode 100644 index 0000000000000000000000000000000000000000..45f11775bd9a02c99ccc90457623d79b7538556f Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.627,644.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.633,645,627,621,20,644,627.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.633,645,627,621,20,644,627.ttf new file mode 100644 index 0000000000000000000000000000000000000000..82976b0e0e48445798743e92701b2af3129d5dd2 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.633,645,627,621,20,644,627.ttf differ diff --git a/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.63A,64A,631.ttf b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.63A,64A,631.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ebc2866c8b6897579199d4a01f21a04f7a34b8af Binary files /dev/null and b/test/subset/data/expected/layout.gpos8.amiri/Amiri-Regular.retain-gids.63A,64A,631.ttf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..34966da1d51ce4bb7d1f9bcd195de407c743e092 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..206062b21dea465c1b975c75c4fbaa896888b9fa Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..aee1579938096407110a1f9c95473febcf1834c7 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..61f41df1048db11e615cf1953f23eaf6acdcc75f Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..319094281d41898d3c9bfd4fac0177e4ce1f5d40 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..aee1579938096407110a1f9c95473febcf1834c7 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..7130a4c6cec286d9b455cb981fe1fb4ce8f5d81f Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b64fb14cea2e14d2d1bcbad7d29295b626770541 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..48b30c79b9ae853fb485da4d71b0e76bf4dcc519 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..4c3af1350bb105127da276a3b29095bc94e1fc07 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..4a10c7683f6bba71dbf7990cd31cddb5a6ac0403 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..48b30c79b9ae853fb485da4d71b0e76bf4dcc519 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..55f3f66554961e11877fc52ab9f46c4654f4011a Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..5f69d873a82f99e24ea86b320c9ecf59038c0493 Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2f0e4b9d11d22c28ac19634a76632cd1dcd592af Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..9bc50e5aa03ee52b2f7e1502cccc5eaad6fa3a6b Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..66b19412b3204b0a58e96799736328eb7ad5d38c Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2f0e4b9d11d22c28ac19634a76632cd1dcd592af Binary files /dev/null and b/test/subset/data/expected/layout.gpos8/gpos_chaining3_simple_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.default.41,42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..46484863c4ccbf0b298b99172533bbb2360fef5b Binary files /dev/null and b/test/subset/data/expected/layout.gpos9/gpos9_font2.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.default.41.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..cd2c4c268877a031e0df9c01605b357965e09a4a Binary files /dev/null and b/test/subset/data/expected/layout.gpos9/gpos9_font2.default.41.otf differ diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.default.42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.default.42.otf new file mode 100644 index 0000000000000000000000000000000000000000..09e20f80435fc69b332cc30f9ee6d7213e53a180 Binary files /dev/null and b/test/subset/data/expected/layout.gpos9/gpos9_font2.default.42.otf differ diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.41,42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..968dd372936c9486d3f9931b6b28ae6188db1bc4 Binary files /dev/null and b/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.41.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..842cf79d07219f8f0829fdefcdf497501a245d26 Binary files /dev/null and b/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.42.otf b/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.42.otf new file mode 100644 index 0000000000000000000000000000000000000000..5ef0589f141e5d78cf4b5d2d9c044974acf5db8c Binary files /dev/null and b/test/subset/data/expected/layout.gpos9/gpos9_font2.retain-gids.42.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53A9,53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53A9,53F1.otf new file mode 100644 index 0000000000000000000000000000000000000000..685c2c90cb16a6074f60e284082be25e668f8825 Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53A9,53F1.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53A9.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53A9.otf new file mode 100644 index 0000000000000000000000000000000000000000..fc1f61bb94547c69bd57676bb2a301f9abb327f2 Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53A9.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53F1.otf new file mode 100644 index 0000000000000000000000000000000000000000..367edeb111701e317a068aeed0fdfbb3b405987a Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.53F1.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..c55b233596460b2605385f86f5168e80bc331c93 Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53A9,53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53A9,53F1.otf new file mode 100644 index 0000000000000000000000000000000000000000..1d67ee49575190233a88abac605469c63d230db4 Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53A9,53F1.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53A9.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53A9.otf new file mode 100644 index 0000000000000000000000000000000000000000..31fc761c5f528ea44119123f86783af8fca4febc Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53A9.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53F1.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53F1.otf new file mode 100644 index 0000000000000000000000000000000000000000..2fd89a4ade6865bebc9bfcaf876ed15761d5faa9 Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.53F1.otf differ diff --git a/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..e737ed1ff83bcc313f2635e2c22106fa9b3d5fe3 Binary files /dev/null and b/test/subset/data/expected/layout.gsub3/gsub_alternate_substitution.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..e1a944d25fb7c5620c8541500d9a48b1d2afd718 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..73c0650b4ddbb25f0fc6dbec962c6a704f09351a Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..3b1ae2a63d388876a71a7231d3f6c2f4d7732955 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..70e8ef7e89445581c8385839d9c7fe292d24e3df Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.41.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..817e5c4ab2a4f3c3b4df40d22e90552334b5bdb0 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..a99ffb88a83ad4cd18a555706bcecf382ea47dd1 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..6b020cdac20ee94a16ba6b734255bf6abff1634e Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..8cf90bf0b2832183f12232b4d9fca05e33a2f238 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..ebc0f0087fe3f35d12a19fe908802b1b2d6bbb90 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..817e5c4ab2a4f3c3b4df40d22e90552334b5bdb0 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context1_multiple_subrules_f2.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b1155251efe099b7fe8e5eb9ad74af9fbe4b4e89 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..32437e447bb53974e683b20885d364bdf75a4f5c Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..59dd1dcc45821446f700df426e67267494e8f6ef Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..32c57fae66b87410bde35e7e40ce22a5d09de21d Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.41.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..a0ca58f6fea48a17de433930bf55c03d0e45cb62 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..14caaccfb5df06a2d356a64f28d927729acd92e3 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..c79a5bdaeabb8a97d2d442cac355266ca325ad97 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..88f2ddb894bde6ef91bd4be38056f8d60175e856 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..01471cb56b864a183622d148ba14f0e445237ecf Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..a0ca58f6fea48a17de433930bf55c03d0e45cb62 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context2_multiple_subrules_f2.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..7857a0e3e3415fbb5706b2aaa3f2640b1fedf2b6 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..1824f31dedf9ceb44ee9af0432d7edb2c5589f6e Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,42.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..b72ad4fe8e5a43568d1a673a9ce646fc5dd80b07 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..9474c38e6338b9bad49a185292131623253d3cbe Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.41.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..1e4055a6b715ed40dc0ffbcdf9ebe3fc9c559d35 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..748fd4e694db4316a247a971e093176f05dd4d7d Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,42.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,42.otf new file mode 100644 index 0000000000000000000000000000000000000000..8ac3085f96ef831420dce4a0abb499da5e490271 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,42.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,43.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..6a41f5629ab199a36158cd228938c314b2a3b6b5 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41,43.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..31d7ce7e0d05eb90efb92b723030e4ab73a271a0 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..1e4055a6b715ed40dc0ffbcdf9ebe3fc9c559d35 Binary files /dev/null and b/test/subset/data/expected/layout.gsub5/gsub_context3_successive_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..bdaa8059f59f89fedd26d3ded9ea00c2861aef20 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..e87cfff7d9932e2047ec03c4c4b262c591b35b93 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..3e7ecef82127d65f64431d58b6d04857ed4a8131 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..e10d863c069ce71861f6c1542fb47241f44d047d Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..30e98e022de529ed1ce3d74fb09d31fdbbdfa5bf Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..3e7ecef82127d65f64431d58b6d04857ed4a8131 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining1_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..a53b114d6cb037601fbfa5f2375a15ea18697a51 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..80da7953a0e09cbb158f9d6b1f6fe694e1fc5dff Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..6b55fe6ad696a005f6836f12045668fc63ec3af9 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..856249e7291e8bd06e36e88c215be4411d7d32c9 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..90634d6fb219c260dd6f74955b11e8d8362f5c9d Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..6b55fe6ad696a005f6836f12045668fc63ec3af9 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining2_multiple_subrules_f1.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..fbd9a4461a481ddd6eca863499e3b57b5453f985 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..45bc0be51507b550f9514163d1408bee10361eba Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2af5abbe5de9785cfc429e59cf9dd558358c0437 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.30,31,32,33.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.30,31,32,33.otf new file mode 100644 index 0000000000000000000000000000000000000000..2d08eb0b59e153f46543d2c27cadfc8be556864e Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.30,31,32,33.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..d87455d0705e834b0ab2fa459a3e8c384d393605 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..2af5abbe5de9785cfc429e59cf9dd558358c0437 Binary files /dev/null and b/test/subset/data/expected/layout.gsub6/gsub_chaining3_simple_f2.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,47,48,49.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,47,48,49.otf new file mode 100644 index 0000000000000000000000000000000000000000..4e30f4718d4d39b96a04b92830bd8acbffa5ba16 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,47,48,49.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,47.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,47.otf new file mode 100644 index 0000000000000000000000000000000000000000..0f8ef5ac3f854dc2ae0d46cccc28b190e7811d48 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,47.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,4D.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,4D.otf new file mode 100644 index 0000000000000000000000000000000000000000..7b18952d62ff42c83c6aa4ac7e950d6068a8e323 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,4D.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,51.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,51.otf new file mode 100644 index 0000000000000000000000000000000000000000..f96a05aa8617cfed5795bff8763071603d3c36b6 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46,51.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..97dd96d4ef373278d3d89d3126edf3e9f7f3cc63 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43,44,45,46.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..d4783b35160f731bd6a9457f72bf4870c8c593ea Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..b442889e1638ce5477f40bd731a20b549267c65d Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.41.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.61.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.61.otf new file mode 100644 index 0000000000000000000000000000000000000000..62764981521cde36d27dd3ca95f44c45bd76d55a Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.61.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..aae2b269c468e70e20368b06592b7fcb0264c30c Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.default.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,47,48,49.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,47,48,49.otf new file mode 100644 index 0000000000000000000000000000000000000000..8495a4a1601b7dc9a35daae731affed35b09deab Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,47,48,49.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,47.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,47.otf new file mode 100644 index 0000000000000000000000000000000000000000..4838600e230d6f78a59f1468b0c1cd18ad6b1278 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,47.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,4D.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,4D.otf new file mode 100644 index 0000000000000000000000000000000000000000..27982fd91dd87e7ddc3330f3a4e4f1d02c7448ff Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,4D.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,51.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,51.otf new file mode 100644 index 0000000000000000000000000000000000000000..87a06c03405d92cad2b13e66bbbc069de89579f0 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46,51.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46.otf new file mode 100644 index 0000000000000000000000000000000000000000..eea44642ba41cc3b9439adf14521068a78d1fab2 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43,44,45,46.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43.otf new file mode 100644 index 0000000000000000000000000000000000000000..89553364da45104f7d85f1ea4099f4029a393c73 Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41,42,43.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41.otf new file mode 100644 index 0000000000000000000000000000000000000000..1a29bbe47114a2b870a4b28ed4a4a12f001a4b5f Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.41.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.61.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.61.otf new file mode 100644 index 0000000000000000000000000000000000000000..eebf28c875a4d8c7c4468e34b9fb62b23f177b9a Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.61.otf differ diff --git a/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.retain-all-codepoint.otf b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.retain-all-codepoint.otf new file mode 100644 index 0000000000000000000000000000000000000000..aae2b269c468e70e20368b06592b7fcb0264c30c Binary files /dev/null and b/test/subset/data/expected/layout.gsub8/gsub8_manually_created.retain-gids.retain-all-codepoint.otf differ diff --git a/test/subset/data/expected/layout.khmer/Khmer.default.1780.ttf b/test/subset/data/expected/layout.khmer/Khmer.default.1780.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e3d9c8f87a8b05404d7fc5541a2330ce9b052505 Binary files /dev/null and b/test/subset/data/expected/layout.khmer/Khmer.default.1780.ttf differ diff --git a/test/subset/data/expected/layout.khmer/Khmer.default.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf b/test/subset/data/expected/layout.khmer/Khmer.default.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9c122b5536496f46805d90db323fe1c589f25fa6 Binary files /dev/null and b/test/subset/data/expected/layout.khmer/Khmer.default.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf differ diff --git a/test/subset/data/expected/layout.khmer/Khmer.default.31.ttf b/test/subset/data/expected/layout.khmer/Khmer.default.31.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fb54e5ba8fcc854e0baee31350bbd4f3938738c8 Binary files /dev/null and b/test/subset/data/expected/layout.khmer/Khmer.default.31.ttf differ diff --git a/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1780.ttf b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1780.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6f5e789065d11f99eed3ed98f4053cecb50d41f5 Binary files /dev/null and b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1780.ttf differ diff --git a/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf new file mode 100644 index 0000000000000000000000000000000000000000..572c41feb3d48d1122e31f151413b2252fba02eb Binary files /dev/null and b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.1789,17BB,17C6,1794,17B6,1793,1798,17BE.ttf differ diff --git a/test/subset/data/expected/layout.khmer/Khmer.retain-gids.31.ttf b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.31.ttf new file mode 100644 index 0000000000000000000000000000000000000000..31a6c1a6994b6901861b31975e734571662ea44b Binary files /dev/null and b/test/subset/data/expected/layout.khmer/Khmer.retain-gids.31.ttf differ diff --git a/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D.ttf b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D.ttf new file mode 100644 index 0000000000000000000000000000000000000000..394d92c362e950872245bbcb2b8eeadde622c554 Binary files /dev/null and b/test/subset/data/expected/layout.notonastaliqurdu/NotoNastaliqUrdu-Bold.retain-gids.627,644,62D.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf similarity index 83% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf index d0d9d5a288e34361e8dea71a784c53ed1b33e0dc..33aa3f7f49e90d6e0ca352055a3a1a6304f0a4ae 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,42,43.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,42,43.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf similarity index 81% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf index f4d881f294e1872fa469b3a5204bb82b113ffe56..c207f0932e2afd990cb59bbf6ac1b76ff403c193 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41,43.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41,43.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf similarity index 78% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf index 9e6dd28f54332c366709ebed5c3dfbcb81153122..70251b38aeb7af4bf9d4fc1f2ea61ffc82a1d6e6 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.41.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.41.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf similarity index 79% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf index 50260c54d3fda4f25f8e69052062d491fa80036c..2109fafc728cf17c3d2e9f8a6347f7d847216654 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.43.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.43.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf similarity index 81% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf index 22d5b619811ca317eecf91ff9be2a7b23fb9e1ae..16c6d432e5b1e3d7f7a9aa8fca93ddd6ce11d6c1 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout.CA,CB.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.default.CA,CB.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf similarity index 92% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf index aa007bac5ca2a8a46925124da8c4467e3b147e5b..95e055f53d55015daa9fb9e1305682979eaa3a16 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,42,43.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,42,43.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf similarity index 92% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf index f3be30c5bf8ed5cc5d5a77c0cea4a380d1f7a5b0..1702a1022468952b2bc571877fdb2a1c1eef5465 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41,43.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41,43.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf similarity index 91% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf index 44c329eb1e928c5c3458efe47487f5804a9802cb..c03e8cbf559245add790782c4abc99b44394f87b 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.41.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.41.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf similarity index 91% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf index b0a1ea3dced025ae7d9ba1888062ff847797a0e1..be5e6d9f48c2c6351859dc87a8033cd915c12943 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.43.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.43.ttf differ diff --git a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf similarity index 93% rename from test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf rename to test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf index 16ad9d515278563a9b4358327dda2455f0627f4e..9798bc48eea620bf287450d85a76caefe2021a90 100644 Binary files a/test/subset/data/expected/layout/Roboto-Regular.smallcaps.keep-layout-retain-gids.CA,CB.ttf and b/test/subset/data/expected/layout/Roboto-Regular.smallcaps.retain-gids.CA,CB.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.default.58,59.ttf b/test/subset/data/expected/sbix/sbix.default.58,59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d99bfc97abeb052040d2d9e7915f14e0e0215838 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.default.58,59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.default.58.ttf b/test/subset/data/expected/sbix/sbix.default.58.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6960f8f98f89832d5dcd3fef32f48e1a7b9e0457 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.default.58.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.default.59.ttf b/test/subset/data/expected/sbix/sbix.default.59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1a4ac9725229f28a48425eeded64aada9e46a752 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.default.59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58,59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58,59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..96f03e63d880c3e8be85a4c3ca7d97213ebc9c6e Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58,59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58.ttf b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d88e416df58dc62a8ac8f0b5c95781fd15ce39ac Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.58.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0de61a8560d4536e4f3defdf4bfba03f3ed59c1a Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.drop-hints-retain-gids.59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.drop-hints.58,59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints.58,59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..96f03e63d880c3e8be85a4c3ca7d97213ebc9c6e Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.drop-hints.58,59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.drop-hints.58.ttf b/test/subset/data/expected/sbix/sbix.drop-hints.58.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d88e416df58dc62a8ac8f0b5c95781fd15ce39ac Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.drop-hints.58.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.drop-hints.59.ttf b/test/subset/data/expected/sbix/sbix.drop-hints.59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a3c09e99a8145332657dea10b8087d5f81c705e5 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.drop-hints.59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.retain-gids.58,59.ttf b/test/subset/data/expected/sbix/sbix.retain-gids.58,59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d99bfc97abeb052040d2d9e7915f14e0e0215838 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.retain-gids.58,59.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.retain-gids.58.ttf b/test/subset/data/expected/sbix/sbix.retain-gids.58.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6960f8f98f89832d5dcd3fef32f48e1a7b9e0457 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.retain-gids.58.ttf differ diff --git a/test/subset/data/expected/sbix/sbix.retain-gids.59.ttf b/test/subset/data/expected/sbix/sbix.retain-gids.59.ttf new file mode 100644 index 0000000000000000000000000000000000000000..21d014bd17fffbedd0571ba9614e50fbd8a0c424 Binary files /dev/null and b/test/subset/data/expected/sbix/sbix.retain-gids.59.ttf differ diff --git a/test/subset/data/expected/variable/Fraunces.default.26,66,69,124,125.ttf b/test/subset/data/expected/variable/Fraunces.default.26,66,69,124,125.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9d45fcba875a81d19be32867c1b682224cb2c2e3 Binary files /dev/null and b/test/subset/data/expected/variable/Fraunces.default.26,66,69,124,125.ttf differ diff --git a/test/subset/data/expected/variable/Fraunces.default.61.ttf b/test/subset/data/expected/variable/Fraunces.default.61.ttf new file mode 100644 index 0000000000000000000000000000000000000000..381ef6d2607517bd27f3d0ca5640c7b0e7a1a145 Binary files /dev/null and b/test/subset/data/expected/variable/Fraunces.default.61.ttf differ diff --git a/test/subset/data/fonts/AdobeBlank-Regular.ttf b/test/subset/data/fonts/AdobeBlank-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..817f51a7aca0e99a29918c5b61653cb8287535ef Binary files /dev/null and b/test/subset/data/fonts/AdobeBlank-Regular.ttf differ diff --git a/test/subset/data/fonts/AdobeVFPrototype.otf b/test/subset/data/fonts/AdobeVFPrototype.otf new file mode 100644 index 0000000000000000000000000000000000000000..2f1b173910401482395148c8670f07da86644daa Binary files /dev/null and b/test/subset/data/fonts/AdobeVFPrototype.otf differ diff --git a/test/subset/data/fonts/Amiri-Regular.ttf b/test/subset/data/fonts/Amiri-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..508a1bfce418ab2339271e0821579426bca65161 Binary files /dev/null and b/test/subset/data/fonts/Amiri-Regular.ttf differ diff --git a/test/subset/data/fonts/Fraunces.ttf b/test/subset/data/fonts/Fraunces.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8210f9488d3c732359a9292dd09aca3f2bae830e Binary files /dev/null and b/test/subset/data/fonts/Fraunces.ttf differ diff --git a/test/subset/data/fonts/IndicTestJalandhar-Regular.ttf b/test/subset/data/fonts/IndicTestJalandhar-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4d7397569957e265ae7e0328a27cfe385f1140db Binary files /dev/null and b/test/subset/data/fonts/IndicTestJalandhar-Regular.ttf differ diff --git a/test/subset/data/fonts/Khmer.ttf b/test/subset/data/fonts/Khmer.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4c37487acb6f0306cd20c8109948e069ead76852 Binary files /dev/null and b/test/subset/data/fonts/Khmer.ttf differ diff --git a/test/subset/data/fonts/NanumMyeongjo-Regular-subset.ttf b/test/subset/data/fonts/NanumMyeongjo-Regular-subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..73b395e7cffb031577f2d74679e3b21f1ae32141 Binary files /dev/null and b/test/subset/data/fonts/NanumMyeongjo-Regular-subset.ttf differ diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.gap.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.gap.ttf new file mode 100644 index 0000000000000000000000000000000000000000..885059a5617b8a6eed198abcec91114bb068a667 Binary files /dev/null and b/test/subset/data/fonts/NotoColorEmoji.subset.gap.ttf differ diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.index_format3.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.index_format3.ttf new file mode 100644 index 0000000000000000000000000000000000000000..df1ff9bb3c3a2e9dc64df51c171067b2ae933ae2 Binary files /dev/null and b/test/subset/data/fonts/NotoColorEmoji.subset.index_format3.ttf differ diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf new file mode 100644 index 0000000000000000000000000000000000000000..cdccdeda2b4458028ff7c7301584d11f79512a2f Binary files /dev/null and b/test/subset/data/fonts/NotoColorEmoji.subset.multiple_size_tables.ttf differ diff --git a/test/subset/data/fonts/NotoColorEmoji.subset.ttf b/test/subset/data/fonts/NotoColorEmoji.subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..14a544ad5fbf4d31ef8339d7393d2aa071d41bac Binary files /dev/null and b/test/subset/data/fonts/NotoColorEmoji.subset.ttf differ diff --git a/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf b/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d05dabe0b5312b09de1ac70b867019b1fb8116fc Binary files /dev/null and b/test/subset/data/fonts/NotoNastaliqUrdu-Bold.ttf differ diff --git a/test/subset/data/fonts/SourceSerifVariable-Roman.ttf b/test/subset/data/fonts/SourceSerifVariable-Roman.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4a738451fe55206c1268bc39bc9ec00bfe4888fa Binary files /dev/null and b/test/subset/data/fonts/SourceSerifVariable-Roman.ttf differ diff --git a/test/subset/data/fonts/TwemojiMozilla.subset.ttf b/test/subset/data/fonts/TwemojiMozilla.subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..357dda3b96d86c569e94f579d14a2c87bc4cfbce Binary files /dev/null and b/test/subset/data/fonts/TwemojiMozilla.subset.ttf differ diff --git a/test/subset/data/fonts/cmap14_font1.otf b/test/subset/data/fonts/cmap14_font1.otf new file mode 100644 index 0000000000000000000000000000000000000000..a4283c678f43a09d0a37a0a8a700887574a302ea Binary files /dev/null and b/test/subset/data/fonts/cmap14_font1.otf differ diff --git a/test/subset/data/fonts/cmap14_font2.otf b/test/subset/data/fonts/cmap14_font2.otf new file mode 100644 index 0000000000000000000000000000000000000000..4a7da8041616f07349d915873842a56782e92298 Binary files /dev/null and b/test/subset/data/fonts/cmap14_font2.otf differ diff --git a/test/subset/data/fonts/gpos2_1_font7.otf b/test/subset/data/fonts/gpos2_1_font7.otf new file mode 100644 index 0000000000000000000000000000000000000000..22b54ea7e66c94954d7d88b271f9c6ad792577e8 Binary files /dev/null and b/test/subset/data/fonts/gpos2_1_font7.otf differ diff --git a/test/subset/data/fonts/gpos2_2_font5.otf b/test/subset/data/fonts/gpos2_2_font5.otf new file mode 100644 index 0000000000000000000000000000000000000000..19833cf8fd17abf64c0fbf2ea796ec23c47a6b51 Binary files /dev/null and b/test/subset/data/fonts/gpos2_2_font5.otf differ diff --git a/test/subset/data/fonts/gpos3_font3.otf b/test/subset/data/fonts/gpos3_font3.otf new file mode 100644 index 0000000000000000000000000000000000000000..69c74a3242f1818a5ef13f88c5f0ca12c446d44e Binary files /dev/null and b/test/subset/data/fonts/gpos3_font3.otf differ diff --git a/test/subset/data/fonts/gpos4_multiple_anchors_1.otf b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf new file mode 100644 index 0000000000000000000000000000000000000000..e77cbb654d4c7d0c1ecce38ebb131dd181537dca Binary files /dev/null and b/test/subset/data/fonts/gpos4_multiple_anchors_1.otf differ diff --git a/test/subset/data/fonts/gpos5_font1.otf b/test/subset/data/fonts/gpos5_font1.otf new file mode 100644 index 0000000000000000000000000000000000000000..c7e2132bda67e5c4745fdc0009a13e723e0ef20a Binary files /dev/null and b/test/subset/data/fonts/gpos5_font1.otf differ diff --git a/test/subset/data/fonts/gpos6_font1.otf b/test/subset/data/fonts/gpos6_font1.otf new file mode 100644 index 0000000000000000000000000000000000000000..fd640acb2bddf30b5046f45c5b9cb057b920687a Binary files /dev/null and b/test/subset/data/fonts/gpos6_font1.otf differ diff --git a/test/subset/data/fonts/gpos9_font2.otf b/test/subset/data/fonts/gpos9_font2.otf new file mode 100644 index 0000000000000000000000000000000000000000..1378f81e84bbe46af0e0c12bd0aad25b52b6ba74 Binary files /dev/null and b/test/subset/data/fonts/gpos9_font2.otf differ diff --git a/test/subset/data/fonts/gpos_chaining1_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_chaining1_multiple_subrules_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..721115e7bf1b50788e8a5e885c0a352bdee5d85b Binary files /dev/null and b/test/subset/data/fonts/gpos_chaining1_multiple_subrules_f1.otf differ diff --git a/test/subset/data/fonts/gpos_chaining2_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_chaining2_multiple_subrules_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..ef7f63510914ea49698d30250f84c149c7f7843c Binary files /dev/null and b/test/subset/data/fonts/gpos_chaining2_multiple_subrules_f1.otf differ diff --git a/test/subset/data/fonts/gpos_chaining3_simple_f1.otf b/test/subset/data/fonts/gpos_chaining3_simple_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..b6f1863fbd1554a296f3f71f8995ff5533e91756 Binary files /dev/null and b/test/subset/data/fonts/gpos_chaining3_simple_f1.otf differ diff --git a/test/subset/data/fonts/gpos_context1_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_context1_multiple_subrules_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..fc84d1fcb3a523aff45ad5bbbba7e6799e26d452 Binary files /dev/null and b/test/subset/data/fonts/gpos_context1_multiple_subrules_f1.otf differ diff --git a/test/subset/data/fonts/gpos_context2_multiple_subrules_f1.otf b/test/subset/data/fonts/gpos_context2_multiple_subrules_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..c5afd3ebcd66c73e62956408e2db7625a54597e3 Binary files /dev/null and b/test/subset/data/fonts/gpos_context2_multiple_subrules_f1.otf differ diff --git a/test/subset/data/fonts/gpos_context3_simple_f1.otf b/test/subset/data/fonts/gpos_context3_simple_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..fad7550444456acf7ac13bb6199dcfbfe3cb6d8b Binary files /dev/null and b/test/subset/data/fonts/gpos_context3_simple_f1.otf differ diff --git a/test/subset/data/fonts/gsub8_manually_created.otf b/test/subset/data/fonts/gsub8_manually_created.otf new file mode 100644 index 0000000000000000000000000000000000000000..00cbb4bb30b88fcc97ba46b9230695bfe7e562dc Binary files /dev/null and b/test/subset/data/fonts/gsub8_manually_created.otf differ diff --git a/test/subset/data/fonts/gsub_alternate_substitution.otf b/test/subset/data/fonts/gsub_alternate_substitution.otf new file mode 100644 index 0000000000000000000000000000000000000000..188b8e8b5470607d03253dce91732d91df193a22 Binary files /dev/null and b/test/subset/data/fonts/gsub_alternate_substitution.otf differ diff --git a/test/subset/data/fonts/gsub_chaining1_multiple_subrules_f1.otf b/test/subset/data/fonts/gsub_chaining1_multiple_subrules_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..74b99455829bc625bf3873d5e77a9bf73948e6f9 Binary files /dev/null and b/test/subset/data/fonts/gsub_chaining1_multiple_subrules_f1.otf differ diff --git a/test/subset/data/fonts/gsub_chaining2_multiple_subrules_f1.otf b/test/subset/data/fonts/gsub_chaining2_multiple_subrules_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..a3a1846e6cf5c5f48df42f788e2705edea379f71 Binary files /dev/null and b/test/subset/data/fonts/gsub_chaining2_multiple_subrules_f1.otf differ diff --git a/test/subset/data/fonts/gsub_chaining3_simple_f2.otf b/test/subset/data/fonts/gsub_chaining3_simple_f2.otf new file mode 100644 index 0000000000000000000000000000000000000000..bc9ed9a79f9ef4ef9f73e2325672a610a5c78d25 Binary files /dev/null and b/test/subset/data/fonts/gsub_chaining3_simple_f2.otf differ diff --git a/test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf b/test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf new file mode 100644 index 0000000000000000000000000000000000000000..cb62adb9a9802c41e30724bf90400c37d22d8622 Binary files /dev/null and b/test/subset/data/fonts/gsub_context1_multiple_subrules_f2.otf differ diff --git a/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf b/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf new file mode 100644 index 0000000000000000000000000000000000000000..fe5b94bd581e8a5e122e0062210c4dec0bd33a19 Binary files /dev/null and b/test/subset/data/fonts/gsub_context2_multiple_subrules_f2.otf differ diff --git a/test/subset/data/fonts/gsub_context3_successive_f1.otf b/test/subset/data/fonts/gsub_context3_successive_f1.otf new file mode 100644 index 0000000000000000000000000000000000000000..682520a7ead5e88e66856959d496c44dfc06a104 Binary files /dev/null and b/test/subset/data/fonts/gsub_context3_successive_f1.otf differ diff --git a/test/subset/data/fonts/sbix.ttf b/test/subset/data/fonts/sbix.ttf new file mode 100644 index 0000000000000000000000000000000000000000..575af900a811e0334ca677ef0cf62cfe94242815 Binary files /dev/null and b/test/subset/data/fonts/sbix.ttf differ diff --git a/test/subset/data/profiles/gids.txt b/test/subset/data/profiles/gids.txt new file mode 100644 index 0000000000000000000000000000000000000000..4fa4f6e415c34d79bc0c9531fd1df94e2740e64b --- /dev/null +++ b/test/subset/data/profiles/gids.txt @@ -0,0 +1 @@ +--gids=1,2,3 diff --git a/test/subset/data/profiles/keep-gdef-gpos.txt b/test/subset/data/profiles/keep-gdef-gpos.txt new file mode 100644 index 0000000000000000000000000000000000000000..071f3412515eec397f19346580f0969a13e99d84 --- /dev/null +++ b/test/subset/data/profiles/keep-gdef-gpos.txt @@ -0,0 +1 @@ +--drop-tables-=GDEF,GPOS diff --git a/test/subset/data/profiles/keep-gdef.txt b/test/subset/data/profiles/keep-gdef.txt new file mode 100644 index 0000000000000000000000000000000000000000..4252d6734d7bff0f8e8b0fd1d62c156293857a9d --- /dev/null +++ b/test/subset/data/profiles/keep-gdef.txt @@ -0,0 +1 @@ +--drop-tables-=GDEF diff --git a/test/subset/data/profiles/keep-layout-retain-gids.txt b/test/subset/data/profiles/keep-layout-retain-gids.txt deleted file mode 100644 index f4787adefdf18fe0de239854d5ff865e51dfd28c..0000000000000000000000000000000000000000 --- a/test/subset/data/profiles/keep-layout-retain-gids.txt +++ /dev/null @@ -1,2 +0,0 @@ ---drop-tables-=GSUB,GPOS ---retain-gids diff --git a/test/subset/data/profiles/keep-layout.txt b/test/subset/data/profiles/keep-layout.txt deleted file mode 100644 index 56da0ffe3ed1e91350a6af6ebed26da6158d1f49..0000000000000000000000000000000000000000 --- a/test/subset/data/profiles/keep-layout.txt +++ /dev/null @@ -1 +0,0 @@ ---drop-tables-=GSUB,GPOS diff --git a/test/subset/data/profiles/name-languages.txt b/test/subset/data/profiles/name-languages.txt new file mode 100644 index 0000000000000000000000000000000000000000..1a6f933222e5692d3cb8aea878cb503a518b41a3 --- /dev/null +++ b/test/subset/data/profiles/name-languages.txt @@ -0,0 +1 @@ +--name-languages=* diff --git a/test/subset/data/profiles/name-legacy.txt b/test/subset/data/profiles/name-legacy.txt new file mode 100644 index 0000000000000000000000000000000000000000..18674453bfd675e9712528cc6f25a5d69b15f70b --- /dev/null +++ b/test/subset/data/profiles/name-legacy.txt @@ -0,0 +1 @@ +--name-legacy diff --git a/test/subset/data/repack_tests/Makefile.am b/test/subset/data/repack_tests/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..f85af6a1b71a2a4eaaa70cf69ca87592fcb01744 --- /dev/null +++ b/test/subset/data/repack_tests/Makefile.am @@ -0,0 +1,21 @@ +# Process this file with automake to produce Makefile.in + +NULL = +EXTRA_DIST = +CLEANFILES = +SUBDIRS = + +# Convenience targets: +lib: libs # Always build subsetter lib in this subdir +libs: + @$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src libs + +TEST_EXTENSIONS = .tests +TESTS_LOG_COMPILER = $(srcdir)/../../run-repack-tests.py $(top_builddir)/util/hb-subset$(EXEEXT) +include Makefile.sources + +EXTRA_DIST += \ + $(TESTS) \ + $(NULL) + +-include $(top_srcdir)/git.mk diff --git a/test/subset/data/repack_tests/Makefile.sources b/test/subset/data/repack_tests/Makefile.sources new file mode 100644 index 0000000000000000000000000000000000000000..e778e52a73e1f3cb8769baaaf90f66652435b0a1 --- /dev/null +++ b/test/subset/data/repack_tests/Makefile.sources @@ -0,0 +1,12 @@ +TESTS = \ + basic.tests \ + prioritization.tests \ + table_duplication.tests \ + $(NULL) + +XFAIL_TESTS = \ + advanced_prioritization.tests \ + $(NULL) + +DISABLED_TESTS = \ + $(NULL) diff --git a/test/subset/data/repack_tests/advanced_prioritization.tests b/test/subset/data/repack_tests/advanced_prioritization.tests new file mode 100644 index 0000000000000000000000000000000000000000..adcbb001be2ef49d7a8d570527d2b07c0f9130c7 --- /dev/null +++ b/test/subset/data/repack_tests/advanced_prioritization.tests @@ -0,0 +1,72 @@ +NotoNastaliqUrdu-Bold.ttf +0x0020 +0x0028 +0x0029 +0x002C +0x002D +0x002E +0x0030 +0x0031 +0x0032 +0x0033 +0x0034 +0x0035 +0x0036 +0x0037 +0x0038 +0x0039 +0x003A +0x060C +0x061F +0x0621 +0x0622 +0x0623 +0x0624 +0x0625 +0x0626 +0x0627 +0x0628 +0x0629 +0x062A +0x062B +0x062C +0x062D +0x062E +0x062F +0x0630 +0x0631 +0x0632 +0x0633 +0x0634 +0x0635 +0x0636 +0x0637 +0x0638 +0x0639 +0x063A +0x0640 +0x0641 +0x0642 +0x0643 +0x0644 +0x0645 +0x0646 +0x0647 +0x0648 +0x0649 +0x064A +0x064B +0x064C +0x064F +0x0651 +0x067E +0x0686 +0x0698 +0x06A9 +0x06AF +0x06BE +0x06CC +0x200C +0x200D +0x200E + diff --git a/test/subset/data/repack_tests/basic.tests b/test/subset/data/repack_tests/basic.tests new file mode 100644 index 0000000000000000000000000000000000000000..896cc9b48b02102956a76a53b7ce314affe6a6ba --- /dev/null +++ b/test/subset/data/repack_tests/basic.tests @@ -0,0 +1,52 @@ +NotoNastaliqUrdu-Bold.ttf +0x060C +0x061F +0x0621 +0x0622 +0x0623 +0x0624 +0x0625 +0x0626 +0x0627 +0x0628 +0x0629 +0x062A +0x062B +0x062C +0x062D +0x062E +0x062F +0x0630 +0x0631 +0x0632 +0x0633 +0x0634 +0x0635 +0x0636 +0x0637 +0x0638 +0x0639 +0x063A +0x0640 +0x0641 +0x0642 +0x0643 +0x0644 +0x0645 +0x0646 +0x0647 +0x0648 +0x0649 +0x064A +0x064B +0x064F +0x0651 +0x067E +0x0686 +0x0698 +0x06A9 +0x06AF +0x06CC +0x200C +0x200D +0x200E diff --git a/test/subset/data/repack_tests/prioritization.tests b/test/subset/data/repack_tests/prioritization.tests new file mode 100644 index 0000000000000000000000000000000000000000..63b437c9282845986419d23cee3caf9b6098fbe1 --- /dev/null +++ b/test/subset/data/repack_tests/prioritization.tests @@ -0,0 +1,77 @@ +NotoNastaliqUrdu-Bold.ttf +0x0020 +0x0028 +0x0029 +0x002C +0x002D +0x002E +0x0030 +0x0031 +0x0032 +0x0033 +0x0034 +0x0035 +0x0036 +0x0037 +0x0038 +0x0039 +0x003A +0x060C +0x061F +0x0621 +0x0622 +0x0623 +0x0624 +0x0625 +0x0626 +0x0627 +0x0628 +0x0629 +0x062A +0x062B +0x062C +0x062D +0x062E +0x062F +0x0630 +0x0631 +0x0632 +0x0633 +0x0634 +0x0635 +0x0636 +0x0637 +0x0638 +0x0639 +0x063A +0x0640 +0x0641 +0x0642 +0x0643 +0x0644 +0x0645 +0x0646 +0x0647 +0x0648 +0x0649 +0x064A +0x064B +0x064F +0x0651 +0x0653 +0x0679 +0x067E +0x0686 +0x0688 +0x0691 +0x0698 +0x06A9 +0x06AF +0x06BA +0x06BE +0x06C1 +0x06CC +0x06D2 +0x200C +0x200D +0x200E diff --git a/test/subset/data/repack_tests/table_duplication.tests b/test/subset/data/repack_tests/table_duplication.tests new file mode 100644 index 0000000000000000000000000000000000000000..3cc90d6bcb63c55bfc55d46efd482012ae934320 --- /dev/null +++ b/test/subset/data/repack_tests/table_duplication.tests @@ -0,0 +1,97 @@ +NotoNastaliqUrdu-Bold.ttf +0x0028 +0x0029 +0x002C +0x002D +0x002E +0x0030 +0x0031 +0x0032 +0x0033 +0x0034 +0x0035 +0x0036 +0x0037 +0x0038 +0x0039 +0x003A +0x0041 +0x0042 +0x0043 +0x0044 +0x0045 +0x0046 +0x0047 +0x0048 +0x0049 +0x004C +0x004D +0x004E +0x004F +0x0050 +0x0052 +0x0053 +0x0054 +0x0055 +0x0056 +0x0057 +0x0061 +0x0062 +0x0063 +0x0064 +0x0065 +0x0066 +0x0067 +0x0068 +0x0069 +0x006B +0x006C +0x006D +0x006E +0x006F +0x0070 +0x0072 +0x0073 +0x0074 +0x0075 +0x0076 +0x0077 +0x0078 +0x0079 +0x060C +0x0626 +0x0627 +0x0628 +0x062A +0x062C +0x062D +0x062E +0x062F +0x0631 +0x0632 +0x0633 +0x0634 +0x0635 +0x0636 +0x0637 +0x0638 +0x0639 +0x0641 +0x0642 +0x0644 +0x0645 +0x0646 +0x0648 +0x0653 +0x0679 +0x067E +0x0686 +0x0688 +0x0691 +0x06A9 +0x06AF +0x06BA +0x06BE +0x06C1 +0x06CC +0x06D2 diff --git a/test/subset/data/tests/basics.tests b/test/subset/data/tests/basics.tests index 772f33cc328e5d5bae932e79eb00e76dba1022de..c5aa136ea25fead0a594413efa403027319611c0 100644 --- a/test/subset/data/tests/basics.tests +++ b/test/subset/data/tests/basics.tests @@ -1,6 +1,7 @@ FONTS: Roboto-Regular.abc.ttf Comfortaa-Regular-new.ttf +NanumMyeongjo-Regular-subset.ttf PROFILES: default.txt @@ -8,6 +9,9 @@ drop-hints.txt drop-hints-retain-gids.txt retain-gids.txt name-ids.txt +name-languages.txt +name-legacy.txt +gids.txt SUBSETS: abc diff --git a/test/subset/data/tests/cbdt.tests b/test/subset/data/tests/cbdt.tests new file mode 100644 index 0000000000000000000000000000000000000000..5e74fef737d6cfac29d554e73176ec5de415dc0a --- /dev/null +++ b/test/subset/data/tests/cbdt.tests @@ -0,0 +1,20 @@ +FONTS: +NotoColorEmoji.subset.ttf +NotoColorEmoji.subset.index_format3.ttf +NotoColorEmoji.subset.multiple_size_tables.ttf +NotoColorEmoji.subset.gap.ttf + +PROFILES: +default.txt +drop-hints.txt +drop-hints-retain-gids.txt +retain-gids.txt + +SUBSETS: +89®⁉8⃣ +8®⁉ +8⁉ +® +9 +⁉ +8⃣ diff --git a/test/subset/data/tests/cmap.tests b/test/subset/data/tests/cmap.tests new file mode 100644 index 0000000000000000000000000000000000000000..7d5cba74cc5e4c73f0865c78ff00d4cb79c2181f --- /dev/null +++ b/test/subset/data/tests/cmap.tests @@ -0,0 +1,16 @@ +FONTS: +AdobeBlank-Regular.ttf + +PROFILES: +default.txt +drop-hints.txt +drop-hints-retain-gids.txt +retain-gids.txt +name-ids.txt + +SUBSETS: +ﻺ +ﻹﻺ +ﻦﻏ +ab +aﻺ diff --git a/test/subset/data/tests/cmap14.tests b/test/subset/data/tests/cmap14.tests new file mode 100644 index 0000000000000000000000000000000000000000..0ed4fb878b74d1b0f2824f00bcf592e06e041d81 --- /dev/null +++ b/test/subset/data/tests/cmap14.tests @@ -0,0 +1,23 @@ +FONTS: +cmap14_font1.otf +cmap14_font2.otf + +PROFILES: +default.txt +drop-hints.txt +drop-hints-retain-gids.txt +retain-gids.txt +name-ids.txt +gids.txt + +SUBSETS: +一丂七 +丂 +七 +一七 +一丅万 +丅万丈三 +丈 +丈三 +丂七丈 +* diff --git a/test/subset/data/tests/colr.tests b/test/subset/data/tests/colr.tests new file mode 100644 index 0000000000000000000000000000000000000000..5da60b6880677c73a12ff5c44f4624dc01eccf08 --- /dev/null +++ b/test/subset/data/tests/colr.tests @@ -0,0 +1,17 @@ +FONTS: +TwemojiMozilla.subset.ttf + +PROFILES: +default.txt +drop-hints.txt +drop-hints-retain-gids.txt +retain-gids.txt + +SUBSETS: +2 +㊗ +㊙ +2㊗ +2㊙ +㊗㊙ +2㊗㊙ diff --git a/test/subset/data/tests/full-font.tests b/test/subset/data/tests/full-font.tests index 225bb484af934777c9094708436621c2e5349bd8..d9519b69fa7c2e47d84f86921efca3af2382c028 100644 --- a/test/subset/data/tests/full-font.tests +++ b/test/subset/data/tests/full-font.tests @@ -1,5 +1,6 @@ FONTS: Roboto-Regular.ttf +SourceSerifVariable-Roman.ttf PROFILES: default.txt diff --git a/test/subset/data/tests/japanese.tests b/test/subset/data/tests/japanese.tests index 5a0438012956ba5d90126c7ef1fdc5f41f032b82..28264ade111fdef54704ff67fec37014ff5a4fe9 100644 --- a/test/subset/data/tests/japanese.tests +++ b/test/subset/data/tests/japanese.tests @@ -4,6 +4,7 @@ Mplus1p-Regular.ttf PROFILES: default.txt drop-hints.txt +keep-gdef.txt SUBSETS: 明 @@ -11,6 +12,7 @@ acek 明極珠度輸清 あいうえおか あいう珠度輸 - +𝜕𝟘AB +𥝱 diff --git a/test/subset/data/tests/layout.context.tests b/test/subset/data/tests/layout.context.tests new file mode 100644 index 0000000000000000000000000000000000000000..5dab14af560e5e59a9bf5121f462ab8edcce4782 --- /dev/null +++ b/test/subset/data/tests/layout.context.tests @@ -0,0 +1,15 @@ +FONTS: +gpos_context1_multiple_subrules_f1.otf +gpos_context2_multiple_subrules_f1.otf +gpos_context3_simple_f1.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +A +AB +AC +ABC +* diff --git a/test/subset/data/tests/layout.gdef-attachlist.tests b/test/subset/data/tests/layout.gdef-attachlist.tests new file mode 100644 index 0000000000000000000000000000000000000000..b380ac106de7c71550ad8b718e54b1e6e72512ed --- /dev/null +++ b/test/subset/data/tests/layout.gdef-attachlist.tests @@ -0,0 +1,13 @@ +FONTS: +IndicTestJalandhar-Regular.ttf + +PROFILES: +default.txt +drop-hints.txt +keep-gdef.txt + +SUBSETS: +ਁ +ਅਆ +ਇਛ +* diff --git a/test/subset/data/tests/layout.gdef-varstore.tests b/test/subset/data/tests/layout.gdef-varstore.tests new file mode 100644 index 0000000000000000000000000000000000000000..fa19c7f295cc6b847fd9648f1cc995cfde099777 --- /dev/null +++ b/test/subset/data/tests/layout.gdef-varstore.tests @@ -0,0 +1,16 @@ +FONTS: +AdobeVFPrototype.otf + +PROFILES: +default.txt +drop-hints.txt +keep-gdef-gpos.txt + +SUBSETS: +A +AB +ABC +BW +AVW +ABCW + diff --git a/test/subset/data/tests/layout.gdef.tests b/test/subset/data/tests/layout.gdef.tests new file mode 100644 index 0000000000000000000000000000000000000000..def862f32c074ff33f59034c5139dbd5d5a677d6 --- /dev/null +++ b/test/subset/data/tests/layout.gdef.tests @@ -0,0 +1,14 @@ +FONTS: +Roboto-Regular.ttf + +PROFILES: +default.txt +drop-hints.txt +keep-gdef-gpos.txt + +SUBSETS: +Ḁ̃ +̣ +̃ +̉ ̏ +ABC diff --git a/test/subset/data/tests/layout.gpos.tests b/test/subset/data/tests/layout.gpos.tests index 2d0f9365f2d9b445c778a747ed2f7edf52788f10..6bbef228c99e7dbdd9e31581a2b79876ef6db8db 100644 --- a/test/subset/data/tests/layout.gpos.tests +++ b/test/subset/data/tests/layout.gpos.tests @@ -2,10 +2,13 @@ FONTS: gpos1_2_font.otf PROFILES: -keep-layout-retain-gids.txt +default.txt +retain-gids.txt SUBSETS: +A AC CF AF +BD * diff --git a/test/subset/data/tests/layout.gpos2.tests b/test/subset/data/tests/layout.gpos2.tests new file mode 100644 index 0000000000000000000000000000000000000000..0b333d1151cd9a3fc8b1920e27fb195aaedaebce --- /dev/null +++ b/test/subset/data/tests/layout.gpos2.tests @@ -0,0 +1,14 @@ +FONTS: +gpos2_1_font7.otf +gpos2_2_font5.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +!# +!#% +.# +ABC +* diff --git a/test/subset/data/tests/layout.gpos3.tests b/test/subset/data/tests/layout.gpos3.tests new file mode 100644 index 0000000000000000000000000000000000000000..58436586b08e56f8ee2f19d805c29caa479c32fa --- /dev/null +++ b/test/subset/data/tests/layout.gpos3.tests @@ -0,0 +1,13 @@ +FONTS: +gpos3_font3.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +() +(+ +)+ +ABC +* diff --git a/test/subset/data/tests/layout.gpos4.tests b/test/subset/data/tests/layout.gpos4.tests new file mode 100644 index 0000000000000000000000000000000000000000..49acd4a44c4c84bd86730d825bd932cc1cb53fb6 --- /dev/null +++ b/test/subset/data/tests/layout.gpos4.tests @@ -0,0 +1,18 @@ +FONTS: +gpos4_multiple_anchors_1.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +A +AB +AC +ABC +ACE +ABCE +ACD +ACDEF +ABCD +* diff --git a/test/subset/data/tests/layout.gpos5.tests b/test/subset/data/tests/layout.gpos5.tests new file mode 100644 index 0000000000000000000000000000000000000000..5d1cb5d87575fe96ba6135ad864eb8e443e203b3 --- /dev/null +++ b/test/subset/data/tests/layout.gpos5.tests @@ -0,0 +1,18 @@ +FONTS: +gpos5_font1.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +A +B +AB +AC +ABC +ABE +ABCE +ABD +ABCD +* diff --git a/test/subset/data/tests/layout.gpos6.tests b/test/subset/data/tests/layout.gpos6.tests new file mode 100644 index 0000000000000000000000000000000000000000..fa3812dad50da51b0dad660cd1b796b4528ffcde --- /dev/null +++ b/test/subset/data/tests/layout.gpos6.tests @@ -0,0 +1,18 @@ +FONTS: +gpos6_font1.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +A +AB +AC +ABC +ACE +ABCE +ACD +ACDEF +ABCD +* diff --git a/test/subset/data/tests/layout.gpos8.amiri.tests b/test/subset/data/tests/layout.gpos8.amiri.tests new file mode 100644 index 0000000000000000000000000000000000000000..183d8a973ad2d6ca04b1d8584045402980b6fcb0 --- /dev/null +++ b/test/subset/data/tests/layout.gpos8.amiri.tests @@ -0,0 +1,13 @@ +FONTS: +Amiri-Regular.ttf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +ال +الأحلام. +غير +سماء لا +الحب diff --git a/test/subset/data/tests/layout.gpos8.tests b/test/subset/data/tests/layout.gpos8.tests new file mode 100644 index 0000000000000000000000000000000000000000..9880554113a3a6e7d86a4ffcbbe51a368c38b853 --- /dev/null +++ b/test/subset/data/tests/layout.gpos8.tests @@ -0,0 +1,13 @@ +FONTS: +gpos_chaining1_multiple_subrules_f1.otf +gpos_chaining2_multiple_subrules_f1.otf +gpos_chaining3_simple_f1.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +0123 +ABC +* diff --git a/test/subset/data/tests/layout.gpos9.tests b/test/subset/data/tests/layout.gpos9.tests new file mode 100644 index 0000000000000000000000000000000000000000..e5f1fdc0bcfdf34c8ec3f6b859ffe3d20327a915 --- /dev/null +++ b/test/subset/data/tests/layout.gpos9.tests @@ -0,0 +1,11 @@ +FONTS: +gpos9_font2.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +A +B +AB diff --git a/test/subset/data/tests/layout.gsub3.tests b/test/subset/data/tests/layout.gsub3.tests new file mode 100644 index 0000000000000000000000000000000000000000..8f98f63b7d99570938ad587b8e4d13a2b2258abb --- /dev/null +++ b/test/subset/data/tests/layout.gsub3.tests @@ -0,0 +1,12 @@ +FONTS: +gsub_alternate_substitution.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +厩 +叱 +厩叱 +* diff --git a/test/subset/data/tests/layout.gsub5.tests b/test/subset/data/tests/layout.gsub5.tests new file mode 100644 index 0000000000000000000000000000000000000000..a084365982b190514517c9eb6f00d94acd838ab9 --- /dev/null +++ b/test/subset/data/tests/layout.gsub5.tests @@ -0,0 +1,15 @@ +FONTS: +gsub_context1_multiple_subrules_f2.otf +gsub_context2_multiple_subrules_f2.otf +gsub_context3_successive_f1.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +A +AB +AC +ABC +* diff --git a/test/subset/data/tests/layout.gsub6.tests b/test/subset/data/tests/layout.gsub6.tests new file mode 100644 index 0000000000000000000000000000000000000000..344349b92b40633997de162d3dbec437eebf7a13 --- /dev/null +++ b/test/subset/data/tests/layout.gsub6.tests @@ -0,0 +1,13 @@ +FONTS: +gsub_chaining1_multiple_subrules_f1.otf +gsub_chaining2_multiple_subrules_f1.otf +gsub_chaining3_simple_f2.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +0123 +ABC +* diff --git a/test/subset/data/tests/layout.gsub8.tests b/test/subset/data/tests/layout.gsub8.tests new file mode 100644 index 0000000000000000000000000000000000000000..6bfc02a9a77fbe9ea3da170c2ad7f36f5a7578de --- /dev/null +++ b/test/subset/data/tests/layout.gsub8.tests @@ -0,0 +1,17 @@ +FONTS: +gsub8_manually_created.otf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +a +A +ABC +ABCDEF +ABCDEFG +ABCDEFGHI +ABCDEFM +ABCDEFQ +* diff --git a/test/subset/data/tests/layout.khmer.tests b/test/subset/data/tests/layout.khmer.tests new file mode 100644 index 0000000000000000000000000000000000000000..8c94482123255bc64b88bf772081d4c178a9842f --- /dev/null +++ b/test/subset/data/tests/layout.khmer.tests @@ -0,0 +1,11 @@ +FONTS: +Khmer.ttf + +PROFILES: +default.txt +retain-gids.txt + +SUBSETS: +1 +ក +ញុំបានមើ diff --git a/test/subset/data/tests/layout.notonastaliqurdu.tests b/test/subset/data/tests/layout.notonastaliqurdu.tests new file mode 100644 index 0000000000000000000000000000000000000000..a34845681007f1facad6f8e7f007078695b9968c --- /dev/null +++ b/test/subset/data/tests/layout.notonastaliqurdu.tests @@ -0,0 +1,8 @@ +FONTS: +NotoNastaliqUrdu-Bold.ttf + +PROFILES: +retain-gids.txt + +SUBSETS: +الح diff --git a/test/subset/data/tests/layout.tests b/test/subset/data/tests/layout.tests index dd1c26ee9c88cc6802ef4a71aada200537cd0a00..20e6152f10e190aed0c9e27746b6444e079e1183 100644 --- a/test/subset/data/tests/layout.tests +++ b/test/subset/data/tests/layout.tests @@ -2,8 +2,8 @@ FONTS: Roboto-Regular.smallcaps.ttf PROFILES: -keep-layout.txt -keep-layout-retain-gids.txt +default.txt +retain-gids.txt SUBSETS: ABC diff --git a/test/subset/data/tests/sbix.tests b/test/subset/data/tests/sbix.tests new file mode 100644 index 0000000000000000000000000000000000000000..2796873ed6b5ca4907f893cd672669b23ba8c2d5 --- /dev/null +++ b/test/subset/data/tests/sbix.tests @@ -0,0 +1,13 @@ +FONTS: +sbix.ttf + +PROFILES: +default.txt +drop-hints.txt +drop-hints-retain-gids.txt +retain-gids.txt + +SUBSETS: +X +Y +XY diff --git a/test/subset/data/tests/variable.tests b/test/subset/data/tests/variable.tests new file mode 100644 index 0000000000000000000000000000000000000000..bda5875ceb1b4623a22a8228c91b9eb4e9cf9a6a --- /dev/null +++ b/test/subset/data/tests/variable.tests @@ -0,0 +1,9 @@ +FONTS: +Fraunces.ttf + +PROFILES: +default.txt + +SUBSETS: +a +&fiĤĥ diff --git a/test/subset/generate-expected-outputs.py b/test/subset/generate-expected-outputs.py index 6c65627e3fa6d5b3f3e1bacdb7c7c166788a554e..ec69bb616e8d62db13da55be850df58c9832e635 100755 --- a/test/subset/generate-expected-outputs.py +++ b/test/subset/generate-expected-outputs.py @@ -1,11 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Pre-generates the expected output subset files (via fonttools) for # specified subset test suite(s). -from __future__ import print_function, division, absolute_import - -import io import os import sys @@ -20,10 +17,9 @@ def usage(): def generate_expected_output(input_file, unicodes, profile_flags, output_path): args = ["fonttools", "subset", input_file] args.extend(["--notdef-outline", - "--name-languages=*", - "--name-legacy", - "--layout-features=*", - "--drop-tables+=DSIG,GPOS,GSUB,GDEF,gvar,avar,MVAR,HVAR", + "--layout-features=*", + "--drop-tables+=DSIG", + "--drop-tables-=sbix", "--unicodes=%s" % unicodes, "--output-file=%s" % output_path]) args.extend(profile_flags) @@ -35,7 +31,7 @@ if not args: usage() for path in args: - with io.open(path, mode="r", encoding="utf-8") as f: + with open(path, mode="r", encoding="utf-8") as f: test_suite = SubsetTestSuite(path, f.read()) output_directory = test_suite.get_output_directory() diff --git a/test/subset/meson.build b/test/subset/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..d41c267b24e92c6db978d5e0f6a177b410949810 --- /dev/null +++ b/test/subset/meson.build @@ -0,0 +1,73 @@ +tests = [ + 'basics', + 'full-font', + 'cff-full-font', + 'japanese', + 'cff-japanese', + 'layout', + 'layout.gpos', + 'layout.gpos2', + 'layout.gpos3', + 'layout.gpos4', + 'layout.gpos5', + 'layout.gpos6', + 'layout.gpos8', + 'layout.gpos8.amiri', + 'layout.gpos9', + 'layout.gsub3', + 'layout.gsub5', + 'layout.gsub6', + 'layout.gsub8', + 'layout.gdef', + 'layout.khmer', + 'layout.context', + 'layout.gdef-varstore', + 'layout.gdef-attachlist', + 'layout.notonastaliqurdu', + 'cmap', + 'cmap14', + 'sbix', + 'colr', + 'cbdt', + 'variable', +] + +repack_tests = [ + 'basic', + 'prioritization', + 'table_duplication', +] + + +run_test = find_program('run-tests.py') + +foreach t : tests + fname = '@0@.tests'.format(t) + + test(t, run_test, + args: [ + hb_subset, + join_paths(meson.current_source_dir(), 'data', 'tests', fname), + ], + # as the tests are ran concurrently let's raise acceptable time here + # ideally better to break and let meson handles them in parallel + timeout: 500, + workdir: join_paths(meson.current_build_dir(), '..', '..'), + suite: ['subset', 'slow'], + ) +endforeach + +run_repack_test = find_program('run-repack-tests.py') + +foreach t : repack_tests + fname = '@0@.tests'.format(t) + + test(t, run_repack_test, + args: [ + hb_subset, + join_paths(meson.current_source_dir(), 'data', 'repack_tests', fname), + ], + workdir: join_paths(meson.current_build_dir(), '..', '..'), + suite: ['subset', 'repack'], + ) +endforeach diff --git a/test/subset/repack_test.py b/test/subset/repack_test.py new file mode 100644 index 0000000000000000000000000000000000000000..2b53dd333c98a5edc6a5b7dae531e02deefd5ea6 --- /dev/null +++ b/test/subset/repack_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +import os + +# Parses a single repacking test file. The first line of the file is +# the name of the font to use and the remaining lines define the set of +# codepoints in the subset. +class RepackTest: + + def __init__(self, test_path, definition): + self.test_path = test_path + self.font_name = None + self.codepoints = set () + self._parse(definition) + + def font_path(self): + return os.path.join (self._base_path (), "fonts", self.font_name) + + def codepoints_string (self): + return ",".join (self.codepoints) + + def _base_path(self): + return os.path.join( + os.path.dirname(self.test_path), + "../") + + + def _parse(self, definition): + lines = definition.splitlines () + self.font_name = lines.pop (0) + for line in lines: + line = line.strip() + if not line: + continue + + self.codepoints.add (line) diff --git a/test/subset/run-repack-tests.py b/test/subset/run-repack-tests.py new file mode 100644 index 0000000000000000000000000000000000000000..22154ba9fa20ccacdfb0de7e34b453505956fbbc --- /dev/null +++ b/test/subset/run-repack-tests.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz +# to subsetting via fonttools. + +from difflib import unified_diff +import os +import re +import subprocess +import sys +import tempfile +import shutil +import io + +from repack_test import RepackTest + +try: + from fontTools.ttLib import TTFont +except ImportError: + print ("fonttools is not present, skipping test.") + sys.exit (77) + +ots_sanitize = shutil.which ("ots-sanitize") + +def cmd (command): + p = subprocess.Popen ( + command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True) + (stdoutdata, stderrdata) = p.communicate () + print (stderrdata, end="", file=sys.stderr) + return stdoutdata, p.returncode + +def fail_test (test, cli_args, message): + print ('ERROR: %s' % message) + print ('Test State:') + print (' test.font_name %s' % test.font_name) + print (' test.test_path %s' % os.path.abspath (test.test_path)) + return 1 + +def run_test (test, should_check_ots): + out_file = os.path.join (tempfile.mkdtemp (), test.font_name + '-subset.ttf') + cli_args = [hb_subset, + "--font-file=" + test.font_path (), + "--output-file=" + out_file, + "--unicodes=%s" % test.codepoints_string (), + "--drop-tables-=GPOS,GSUB,GDEF",] + print (' '.join (cli_args)) + _, return_code = cmd (cli_args) + + if return_code: + return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code)) + + try: + with TTFont (out_file) as font: + pass + except Exception as e: + print (e) + return fail_test (test, cli_args, "ttx failed to parse the result") + + if should_check_ots: + print ("Checking output with ots-sanitize.") + if not check_ots (out_file): + return fail_test (test, cli_args, 'ots for subsetted file fails.') + + return 0 + +def has_ots (): + if not ots_sanitize: + print ("OTS is not present, skipping all ots checks.") + return False + return True + +def check_ots (path): + ots_report, returncode = cmd ([ots_sanitize, path]) + if returncode: + print ("OTS Failure: %s" % ots_report) + return False + return True + +args = sys.argv[1:] +if not args or sys.argv[1].find ('hb-subset') == -1 or not os.path.exists (sys.argv[1]): + sys.exit ("First argument does not seem to point to usable hb-subset.") +hb_subset, args = args[0], args[1:] + +if len (args) != 1: + sys.exit ("No tests supplied.") + +has_ots = has_ots() + +fails = 0 + +path = args[0] +if not path.endswith(".tests"): + sys.exit ("Not a valid test case path.") + +with open (path, mode="r", encoding="utf-8") as f: + # TODO(garretrieger): re-enable OTS checking. + fails += run_test (RepackTest (path, f.read ()), False) + + +if fails != 0: + sys.exit ("%d test(s) failed." % fails) +else: + print ("All tests passed.") diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py index 5d221e6bb3bb7624bda9bdaac25ed49e25c5b293..0e01c3fd6a0c7d3df32046eef61fe6c8af184652 100755 --- a/test/subset/run-tests.py +++ b/test/subset/run-tests.py @@ -1,63 +1,43 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Runs a subsetting test suite. Compares the results of subsetting via harfbuzz # to subsetting via fonttools. -from __future__ import print_function, division, absolute_import - -import io from difflib import unified_diff import os import re import subprocess import sys import tempfile +import shutil +import io from subset_test_suite import SubsetTestSuite -# https://stackoverflow.com/a/377028 -def which (program): - def is_exe (fpath): - return os.path.isfile (fpath) and os.access (fpath, os.X_OK) - - fpath, _ = os.path.split (program) - if fpath: - if is_exe (program): - return program - else: - for path in os.environ["PATH"].split (os.pathsep): - exe_file = os.path.join (path, program) - if is_exe (exe_file): - return exe_file - - return None - -fonttools = which ("fonttools") -ots_sanitize = which ("ots-sanitize") - -if not fonttools: +try: + from fontTools.ttLib import TTFont +except ImportError: print ("fonttools is not present, skipping test.") sys.exit (77) -def cmd(command): +ots_sanitize = shutil.which ("ots-sanitize") + +def cmd (command): p = subprocess.Popen ( - command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True) (stdoutdata, stderrdata) = p.communicate () - print (stderrdata, end="") # file=sys.stderr + print (stderrdata, end="", file=sys.stderr) return stdoutdata, p.returncode -def read_binary (file_path): - with open (file_path, 'rb') as f: - return f.read () - def fail_test (test, cli_args, message): print ('ERROR: %s' % message) print ('Test State:') print (' test.font_path %s' % os.path.abspath (test.font_path)) print (' test.profile_path %s' % os.path.abspath (test.profile_path)) print (' test.unicodes %s' % test.unicodes ()) - expected_file = os.path.join(test_suite.get_output_directory (), - test.get_font_name ()) + expected_file = os.path.join (test_suite.get_output_directory (), + test.get_font_name ()) print (' expected_file %s' % os.path.abspath (expected_file)) return 1 @@ -67,7 +47,8 @@ def run_test (test, should_check_ots): "--font-file=" + test.font_path, "--output-file=" + out_file, "--unicodes=%s" % test.unicodes (), - "--drop-tables+=DSIG,GPOS,GSUB,GDEF,gvar,avar,MVAR,HVAR"] + "--drop-tables+=DSIG", + "--drop-tables-=sbix"] cli_args.extend (test.get_profile_flags ()) print (' '.join (cli_args)) _, return_code = cmd (cli_args) @@ -75,21 +56,29 @@ def run_test (test, should_check_ots): if return_code: return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code)) - expected_ttx, return_code = run_ttx (os.path.join (test_suite.get_output_directory (), - test.get_font_name ())) - if return_code: - return fail_test (test, cli_args, "ttx (expected) returned %d" % (return_code)) - - actual_ttx, return_code = run_ttx (out_file) - if return_code: - return fail_test (test, cli_args, "ttx (actual) returned %d" % (return_code)) - - print ("stripping checksums.") - expected_ttx = strip_check_sum (expected_ttx) - actual_ttx = strip_check_sum (actual_ttx) - - if not actual_ttx == expected_ttx: - for line in unified_diff (expected_ttx.splitlines (1), actual_ttx.splitlines (1)): + expected_ttx = io.StringIO () + try: + with TTFont (os.path.join (test_suite.get_output_directory (), test.get_font_name ())) as font: + font.saveXML (expected_ttx) + except Exception as e: + print (e) + return fail_test (test, cli_args, "ttx failed to parse the expected result") + + actual_ttx = io.StringIO () + try: + with TTFont (out_file) as font: + font.saveXML (actual_ttx) + except Exception as e: + print (e) + return fail_test (test, cli_args, "ttx failed to parse the actual result") + + expected_ttx_text = strip_check_sum (expected_ttx.getvalue ()) + expected_ttx.close () + actual_ttx_text = strip_check_sum (actual_ttx.getvalue ()) + actual_ttx.close () + + if not actual_ttx_text == expected_ttx_text: + for line in unified_diff (expected_ttx_text.splitlines (1), actual_ttx_text.splitlines (1)): sys.stdout.write (line) sys.stdout.flush () return fail_test (test, cli_args, 'ttx for expected and actual does not match.') @@ -101,50 +90,43 @@ def run_test (test, should_check_ots): return 0 -def run_ttx (file): - print ("fonttools ttx %s" % file) - return cmd ([fonttools, "ttx", "-q", "-o-", file]) - def strip_check_sum (ttx_string): return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]', 'checkSumAdjustment value="0x00000000"', - ttx_string.decode ("utf-8"), count=1) + ttx_string, count=1) def has_ots (): if not ots_sanitize: - print("OTS is not present, skipping all ots checks.") + print ("OTS is not present, skipping all ots checks.") return False return True def check_ots (path): ots_report, returncode = cmd ([ots_sanitize, path]) if returncode: - print("OTS Failure: %s" % ots_report); + print ("OTS Failure: %s" % ots_report) return False return True args = sys.argv[1:] if not args or sys.argv[1].find ('hb-subset') == -1 or not os.path.exists (sys.argv[1]): - print ("First argument does not seem to point to usable hb-subset.") - sys.exit (1) + sys.exit ("First argument does not seem to point to usable hb-subset.") hb_subset, args = args[0], args[1:] if not len (args): - print ("No tests supplied.") - sys.exit (1) + sys.exit ("No tests supplied.") has_ots = has_ots() fails = 0 for path in args: - with io.open (path, mode="r", encoding="utf-8") as f: + with open (path, mode="r", encoding="utf-8") as f: print ("Running tests in " + path) test_suite = SubsetTestSuite (path, f.read ()) for test in test_suite.tests (): fails += run_test (test, has_ots) if fails != 0: - print (str (fails) + " test(s) failed.") - sys.exit(1) + sys.exit ("%d test(s) failed." % fails) else: print ("All tests passed.") diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py index 47664d0b6441b13b118cc97e7d4110511fdd5c62..b7fd10590aab958bc1dcfd213f64099dca2ecc6e 100644 --- a/test/subset/subset_test_suite.py +++ b/test/subset/subset_test_suite.py @@ -1,6 +1,5 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -import io import os # A single test in a subset test suite. Identifies a font @@ -18,8 +17,8 @@ class Test: return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset)) def get_profile_flags(self): - with io.open(self.profile_path, mode="r", encoding="utf-8") as f: - return f.read().splitlines(); + with open (self.profile_path, mode="r", encoding="utf-8") as f: + return f.read().splitlines() def get_font_name(self): font_base_name = os.path.basename(self.font_path) diff --git a/util/Makefile.am b/util/Makefile.am index 5298e7732843ac40afe535e706184f9afa01c2a3..cabb9eff53eca50c3a7a19cee6e5711afb0af2a3 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -6,6 +6,8 @@ CLEANFILES = DISTCLEANFILES = MAINTAINERCLEANFILES = +EXTRA_DIST += meson.build + include Makefile.sources # Convenience targets: @@ -23,6 +25,7 @@ AM_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(FREETYPE_CFLAGS) \ $(CAIRO_FT_CFLAGS) \ + $(CHAFA_CFLAGS) \ $(NULL) LDADD = \ $(top_builddir)/src/libharfbuzz.la \ @@ -40,6 +43,7 @@ hb_view_LDADD = \ $(LDADD) \ $(CAIRO_LIBS) \ $(CAIRO_FT_LIBS) \ + $(CHAFA_LIBS) \ $(NULL) bin_PROGRAMS += hb-view endif # HAVE_CAIRO_FT diff --git a/util/ansi-print.cc b/util/ansi-print.cc index 49a0477fcff0d174b7db5f23d2cc508940284f8c..80b3704ba077e971a84feaaa4ef99f9790c8b439 100644 --- a/util/ansi-print.cc +++ b/util/ansi-print.cc @@ -133,7 +133,7 @@ struct image_t for (unsigned int col = 0; col < w; col++) *q++ = *p++; else { - unsigned int limit = width - x; + unsigned int limit = width - x; for (unsigned int col = 0; col < limit; col++) *q++ = *p++; p--; @@ -171,17 +171,17 @@ struct biimage_t int freq[8] = {0}; for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { - color_t c = image (x, y); - freq[c.to_ansi ()]++; + color_t c = image (x, y); + freq[c.to_ansi ()]++; } bg = 0; for (unsigned int i = 1; i < 8; i++) if (freq[bg] < freq[i]) - bg = i; + bg = i; fg = 0; for (unsigned int i = 1; i < 8; i++) if (i != bg && freq[fg] < freq[i]) - fg = i; + fg = i; if (fg == bg || freq[fg] == 0) { fg = bg; unicolor = true; @@ -202,7 +202,7 @@ struct biimage_t int dd = diff.dot (diff); for (unsigned int y = 0; y < height; y++) for (unsigned int x = 0; x < width; x++) { - int d = diff.dot (image (x, y).diff (bgc)); + int d = diff.dot (image (x, y).diff (bgc)); (*this)(x, y) = d < 0 ? 0 : d > dd ? 255 : lround (d * 255. / dd); } } @@ -229,7 +229,7 @@ block_best (const biimage_t &bi, bool *inverse) assert (bi.width <= CELL_W); assert (bi.height <= CELL_H); - unsigned int score = (unsigned int) -1; + unsigned int score = UINT_MAX; unsigned int row_sum[CELL_H] = {0}; unsigned int col_sum[CELL_W] = {0}; unsigned int row_sum_i[CELL_H] = {0}; @@ -279,7 +279,7 @@ block_best (const biimage_t &bi, bool *inverse) /* Find best lower line */ if (1) { - unsigned int best_s = (unsigned int) -1; + unsigned int best_s = UINT_MAX; bool best_inv = false; int best_i = 0; for (unsigned int i = 0; i < bi.height - 1; i++) @@ -287,13 +287,13 @@ block_best (const biimage_t &bi, bool *inverse) unsigned int s; s = row_sum[i] + total_i - row_sum_i[i]; if (s < best_s) { - best_s = s; + best_s = s; best_i = i; best_inv = false; } s = row_sum_i[i] + total - row_sum[i]; if (s < best_s) { - best_s = s; + best_s = s; best_i = i; best_inv = true; } @@ -311,7 +311,7 @@ block_best (const biimage_t &bi, bool *inverse) /* Find best left line */ if (1) { - unsigned int best_s = (unsigned int) -1; + unsigned int best_s = UINT_MAX; bool best_inv = false; int best_i = 0; for (unsigned int i = 0; i < bi.width - 1; i++) @@ -319,13 +319,13 @@ block_best (const biimage_t &bi, bool *inverse) unsigned int s; s = col_sum[i] + total_i - col_sum_i[i]; if (s < best_s) { - best_s = s; + best_s = s; best_i = i; best_inv = true; } s = col_sum_i[i] + total - col_sum[i]; if (s < best_s) { - best_s = s; + best_s = s; best_i = i; best_inv = false; } @@ -396,15 +396,15 @@ ansi_print_image_rgb24 (const uint32_t *data, image.copy_sub_image (cell, col * CELL_W, row * CELL_H, CELL_W, CELL_H); bi.set (cell); if (bi.unicolor) { - if (last_bg != bi.bg) { + if (last_bg != bi.bg) { printf ("%c[%dm", ESC_E, 40 + bi.bg); last_bg = bi.bg; } printf (" "); } else { - /* Figure out the closest character to the biimage */ + /* Figure out the closest character to the biimage */ bool inverse = false; - const char *c = block_best (bi, &inverse); + const char *c = block_best (bi, &inverse); if (inverse) { if (last_bg != bi.fg || last_fg != bi.bg) { printf ("%c[%d;%dm", ESC_E, 30 + bi.bg, 40 + bi.fg); diff --git a/util/hb-fc-list.c b/util/hb-fc-list.c index 573d11e7c5fc2679388593ab05e9738004c47ecd..40c6b32b6209e32a4a8cac0960fdd2b97d490b96 100644 --- a/util/hb-fc-list.c +++ b/util/hb-fc-list.c @@ -171,7 +171,7 @@ main (int argc, char **argv) os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_FILE, (char *) 0); FcObjectSetAdd (os, FC_CHARSET); if (!format) - format = (const FcChar8 *) "%{=fclist}\n"; + format = (const FcChar8 *) "%{=fclist}\n"; fs = FcFontList (0, pat, os); if (os) FcObjectSetDestroy (os); @@ -199,7 +199,7 @@ main (int argc, char **argv) } else { - FcChar8 *s; + FcChar8 *s; s = FcPatternFormat (fs->fonts[j], format); if (s) diff --git a/util/hb-fc.cc b/util/hb-fc.cc index 2fe014699f6ce1870304115f5b89d554238f735f..9042346803e4d6ad6f898177bf46e1af21e6b6ec 100644 --- a/util/hb-fc.cc +++ b/util/hb-fc.cc @@ -55,9 +55,9 @@ hb_fc_get_glyph (hb_font_t *font /*HB_UNUSED*/, { unsigned int var_num = 0; if (variation_selector - 0xFE00u < 16) - var_num = variation_selector - 0xFE00 + 1; + var_num = variation_selector - 0xFE00 + 1; else if (variation_selector - 0xE0100u < (256 - 16)) - var_num = variation_selector - 0xE0100 + 17; + var_num = variation_selector - 0xE0100 + 17; *glyph = (var_num << 21) | unicode; } else diff --git a/util/hb-shape.cc b/util/hb-shape.cc index 3ae3fa1bebd04f31d7e7339db9890d16716cb802..01b3d4551507b7ab35dd16debb12dc8b48f0bead 100644 --- a/util/hb-shape.cc +++ b/util/hb-shape.cc @@ -137,7 +137,7 @@ struct output_buffer_t g_string_set_size (gs, 0); format.serialize_line_no (line_no, gs); g_string_append_printf (gs, "trace: %s buffer: ", message); - format.serialize_glyphs (buffer, font, output_format, format_flags, gs); + format.serialize (buffer, font, output_format, format_flags, gs); g_string_append_c (gs, '\n'); fprintf (options.fp, "%s", gs->str); } @@ -170,18 +170,21 @@ main (int argc, char **argv) argc = 0; char *p = buf, *e; args[argc++] = p; - while ((e = strchr (p, ' ')) && argc < (int) (int) ARRAY_LENGTH (args)) + unsigned start_offset = 0; + while ((e = strchr (p + start_offset, ':')) && argc < (int) ARRAY_LENGTH (args)) { *e++ = '\0'; - while (*e == ' ') + while (*e == ':') e++; args[argc++] = p = e; + /* Skip 2 first bytes on first argument if is Windows path, "C:\..." */ + start_offset = argc == 2 && p[0] != '\0' && p[0] != ':' && p[1] == ':' && (p[2] == '\\' || p[2] == '/') ? 2 : 0; } ret |= driver.main (argc, args); fflush (stdout); if (ret) - break; + break; } return ret; } diff --git a/util/hb-subset.cc b/util/hb-subset.cc index 6d87c563c7bb860befd687a889b95e6285771f62..97a3a2f3249d2f4b8e88b128e5c7b38c88c8d51b 100644 --- a/util/hb-subset.cc +++ b/util/hb-subset.cc @@ -40,16 +40,16 @@ struct subset_consumer_t : failed (false), options (parser), subset_options (parser), font (nullptr), input (nullptr) {} void init (hb_buffer_t *buffer_, - const font_options_t *font_opts) + const font_options_t *font_opts) { font = hb_font_reference (font_opts->get_font ()); input = hb_subset_input_reference (subset_options.input); } void consume_line (const char *text, - unsigned int text_len, - const char *text_before, - const char *text_after) + unsigned int text_len, + const char *text_before, + const char *text_after) { // TODO(Q1) does this only get called with at least 1 codepoint? hb_set_t *codepoints = hb_subset_input_unicode_set (input); @@ -65,32 +65,32 @@ struct subset_consumer_t gunichar cp = g_utf8_get_char(c); hb_codepoint_t hb_cp = cp; hb_set_add (codepoints, hb_cp); - } while ((c = g_utf8_find_next_char(c, text + text_len)) != nullptr); + } while ((c = g_utf8_find_next_char(c, text + text_len))); } hb_bool_t write_file (const char *output_file, hb_blob_t *blob) { - unsigned int data_length; - const char* data = hb_blob_get_data (blob, &data_length); - - FILE *fp_out = fopen(output_file, "wb"); - if (fp_out == nullptr) { - fprintf(stderr, "Unable to open output file\n"); - return false; + unsigned int size; + const char* data = hb_blob_get_data (blob, &size); + + if (!output_file) + fail (true, "No output file was specified"); + + FILE *fp = fopen(output_file, "wb"); + if (!fp) + fail (false, "Cannot open output file `%s': %s", + g_filename_display_name (output_file), strerror (errno)); + + while (size) { + size_t ret = fwrite (data, 1, size, fp); + size -= ret; + data += ret; + if (size && ferror (fp)) + fail (false, "Failed to write output: %s", strerror (errno)); } - int bytes_written = fwrite(data, 1, data_length, fp_out); - fclose (fp_out); + fclose (fp); - if (bytes_written == -1) { - fprintf(stderr, "Unable to write output file\n"); - return false; - } - if ((unsigned int) bytes_written != data_length) { - fprintf(stderr, "Expected %u bytes written, got %d\n", data_length, - bytes_written); - return false; - } return true; } diff --git a/util/helper-cairo-ansi.cc b/util/helper-cairo-ansi.cc index 50f9eb4460c593e364fc4f9cc520ff84b75caeb7..3db833bfa49c96e6cab69fdeb391cd3103406c8e 100644 --- a/util/helper-cairo-ansi.cc +++ b/util/helper-cairo-ansi.cc @@ -26,9 +26,102 @@ #include "helper-cairo-ansi.hh" #include "options.hh" - #include "ansi-print.hh" +#ifdef HAVE_CHAFA +# include + +/* Similar to ansi-print.cc */ +# define CELL_W 8 +# define CELL_H (2 * CELL_W) + +static void +chafa_print_image_rgb24 (const void *data, int width, int height, int stride) +{ + ChafaTermInfo *term_info; + ChafaSymbolMap *symbol_map; + ChafaCanvasConfig *config; + ChafaCanvas *canvas; + GString *gs; + unsigned int cols = (width + CELL_W - 1) / CELL_W; + unsigned int rows = (height + CELL_H - 1) / CELL_H; + gchar **environ; + ChafaCanvasMode mode; + ChafaPixelMode pixel_mode; + + /* Adapt to terminal; use sixels if available, and fall back to symbols + * with as many colors as are supported */ + + environ = g_get_environ (); + term_info = chafa_term_db_detect (chafa_term_db_get_default (), + environ); + + pixel_mode = CHAFA_PIXEL_MODE_SYMBOLS; + + if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_BEGIN_SIXELS)) + { + pixel_mode = CHAFA_PIXEL_MODE_SIXELS; + mode = CHAFA_CANVAS_MODE_TRUECOLOR; + } +// else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_DIRECT)) +// mode = CHAFA_CANVAS_MODE_TRUECOLOR; + else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_256)) + mode = CHAFA_CANVAS_MODE_INDEXED_240; + else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_SET_COLOR_FGBG_16)) + mode = CHAFA_CANVAS_MODE_INDEXED_16; + else if (chafa_term_info_have_seq (term_info, CHAFA_TERM_SEQ_INVERT_COLORS)) + mode = CHAFA_CANVAS_MODE_FGBG_BGFG; + else + mode = CHAFA_CANVAS_MODE_FGBG; + + /* Create the configuration */ + + symbol_map = chafa_symbol_map_new (); + chafa_symbol_map_add_by_tags (symbol_map, + (ChafaSymbolTags) (CHAFA_SYMBOL_TAG_BLOCK + | CHAFA_SYMBOL_TAG_SPACE)); + + config = chafa_canvas_config_new (); + chafa_canvas_config_set_canvas_mode (config, mode); + chafa_canvas_config_set_pixel_mode (config, pixel_mode); + chafa_canvas_config_set_cell_geometry (config, 10, 20); + chafa_canvas_config_set_geometry (config, cols, rows); + chafa_canvas_config_set_symbol_map (config, symbol_map); + chafa_canvas_config_set_color_extractor (config, CHAFA_COLOR_EXTRACTOR_MEDIAN); + chafa_canvas_config_set_work_factor (config, 1.0f); + + /* Create canvas, draw to it and render output string */ + + canvas = chafa_canvas_new (config); + chafa_canvas_draw_all_pixels (canvas, + /* Cairo byte order is host native */ + G_BYTE_ORDER == G_LITTLE_ENDIAN + ? CHAFA_PIXEL_BGRA8_PREMULTIPLIED + : CHAFA_PIXEL_ARGB8_PREMULTIPLIED, + (const guint8 *) data, + width, + height, + stride); + gs = chafa_canvas_print (canvas, term_info); + + /* Print the string */ + + fwrite (gs->str, sizeof (char), gs->len, stdout); + + if (pixel_mode != CHAFA_PIXEL_MODE_SIXELS) + fputc ('\n', stdout); + + /* Free resources */ + + g_string_free (gs, TRUE); + chafa_canvas_unref (canvas); + chafa_canvas_config_unref (config); + chafa_symbol_map_unref (symbol_map); + chafa_term_info_unref (term_info); + g_strfreev (environ); +} + +#endif /* HAVE_CHAFA */ cairo_status_t helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface, @@ -71,7 +164,7 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface, unsigned int i; for (i = 0; i < width; i++) if (data[i] != bg_color) - break; + break; if (i < width) break; data += stride / 4; @@ -86,7 +179,7 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface, unsigned int i; for (i = 0; i < width; i++) if (row[i] != bg_color) - break; + break; if (i < width) break; height--; @@ -95,7 +188,14 @@ helper_cairo_surface_write_to_ansi_stream (cairo_surface_t *surface, height++; /* Add one last blank row for padding. */ if (width && height) - ansi_print_image_rgb24 (data, width, height, stride / 4); + { +#ifdef HAVE_CHAFA + if (true) + chafa_print_image_rgb24 (data, width, height, stride); + else +#endif + ansi_print_image_rgb24 (data, width, height, stride / 4); + } cairo_surface_destroy (surface); return CAIRO_STATUS_SUCCESS; diff --git a/util/helper-cairo.cc b/util/helper-cairo.cc index b4f94a98b34d0dc1c12969414311bd8621f9407e..deb9f0d2c1cc9aec4a5e40d3282a07d239cd3d86 100644 --- a/util/helper-cairo.cc +++ b/util/helper-cairo.cc @@ -97,7 +97,7 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts) if (FT_New_Memory_Face (ft_library, (const FT_Byte *) blob_data, - blob_length, + blob_length, font_opts->face_index, &ft_face)) fail (false, "FT_New_Memory_Face fail"); @@ -175,11 +175,18 @@ helper_cairo_scaled_font_has_color (cairo_scaled_font_t *scaled_font) } +enum class image_protocol_t { + NONE = 0, + ITERM2, + KITTY, +}; + struct finalize_closure_t { void (*callback)(finalize_closure_t *); cairo_surface_t *surface; cairo_write_func_t write_func; void *closure; + image_protocol_t protocol; }; static cairo_user_data_key_t finalize_closure_key; @@ -201,7 +208,8 @@ _cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width, double height, - cairo_content_t content) + cairo_content_t content, + image_protocol_t protocol HB_UNUSED) { cairo_surface_t *surface; int w = ceil (width); @@ -242,16 +250,90 @@ _cairo_ansi_surface_create_for_stream (cairo_write_func_t write_func, #ifdef CAIRO_HAS_PNG_FUNCTIONS +static cairo_status_t +byte_array_write_func (void *closure, + const unsigned char *data, + unsigned int size) +{ + g_byte_array_append ((GByteArray *) closure, data, size); + return CAIRO_STATUS_SUCCESS; +} + static void finalize_png (finalize_closure_t *closure) { cairo_status_t status; - status = cairo_surface_write_to_png_stream (closure->surface, - closure->write_func, - closure->closure); + GByteArray *bytes = nullptr; + GString *string; + gchar *base64; + size_t base64_len; + + if (closure->protocol == image_protocol_t::NONE) + { + status = cairo_surface_write_to_png_stream (closure->surface, + closure->write_func, + closure->closure); + } + else + { + bytes = g_byte_array_new (); + status = cairo_surface_write_to_png_stream (closure->surface, + byte_array_write_func, + bytes); + } + if (status != CAIRO_STATUS_SUCCESS) fail (false, "Failed to write output: %s", cairo_status_to_string (status)); + + if (closure->protocol == image_protocol_t::NONE) + return; + + base64 = g_base64_encode (bytes->data, bytes->len); + base64_len = strlen (base64); + + string = g_string_new (NULL); + if (closure->protocol == image_protocol_t::ITERM2) + { + /* https://iterm2.com/documentation-images.html */ + g_string_printf (string, "\033]1337;File=inline=1;size=%zu:%s\a\n", + base64_len, base64); + } + else if (closure->protocol == image_protocol_t::KITTY) + { +#define CHUNK_SIZE 4096 + /* https://sw.kovidgoyal.net/kitty/graphics-protocol.html */ + for (size_t pos = 0; pos < base64_len; pos += CHUNK_SIZE) + { + size_t len = base64_len - pos; + + if (pos == 0) + g_string_append (string, "\033_Ga=T,f=100,m="); + else + g_string_append (string, "\033_Gm="); + + if (len > CHUNK_SIZE) + { + g_string_append (string, "1;"); + g_string_append_len (string, base64 + pos, CHUNK_SIZE); + } + else + { + g_string_append (string, "0;"); + g_string_append_len (string, base64 + pos, len); + } + + g_string_append (string, "\033\\"); + } + g_string_append (string, "\n"); +#undef CHUNK_SIZE + } + + closure->write_func (closure->closure, (unsigned char *) string->str, string->len); + + g_byte_array_unref (bytes); + g_free (base64); + g_string_free (string, TRUE); } static cairo_surface_t * @@ -259,7 +341,8 @@ _cairo_png_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width, double height, - cairo_content_t content) + cairo_content_t content, + image_protocol_t protocol) { cairo_surface_t *surface; int w = ceil (width); @@ -287,6 +370,7 @@ _cairo_png_surface_create_for_stream (cairo_write_func_t write_func, png_closure->surface = surface; png_closure->write_func = write_func; png_closure->closure = closure; + png_closure->protocol = protocol; if (cairo_surface_set_user_data (surface, &finalize_closure_key, @@ -352,13 +436,36 @@ helper_cairo_create_context (double w, double h, void *closure, double width, double height, - cairo_content_t content) = nullptr; + cairo_content_t content, + image_protocol_t protocol) = nullptr; + image_protocol_t protocol = image_protocol_t::NONE; const char *extension = out_opts->output_format; if (!extension) { #if HAVE_ISATTY if (isatty (fileno (out_opts->get_file_handle ()))) + { +#ifdef CAIRO_HAS_PNG_FUNCTIONS + const char *name; + /* https://gitlab.com/gnachman/iterm2/-/issues/7154 */ + if ((name = getenv ("LC_TERMINAL")) != nullptr && + 0 == g_ascii_strcasecmp (name, "iTerm2")) + { + extension = "png"; + protocol = image_protocol_t::ITERM2; + } + else if ((name = getenv ("TERM")) != nullptr && + 0 == g_ascii_strcasecmp (name, "xterm-kitty")) + { + extension = "png"; + protocol = image_protocol_t::KITTY; + } + else + extension = "ansi"; +#else extension = "ansi"; +#endif + } else #endif { @@ -419,7 +526,7 @@ helper_cairo_create_context (double w, double h, if (constructor) surface = constructor (stdio_write_func, f, w, h); else if (constructor2) - surface = constructor2 (stdio_write_func, f, w, h, content); + surface = constructor2 (stdio_write_func, f, w, h, content, protocol); else fail (false, "Unknown output format `%s'; supported formats are: %s%s", extension, diff --git a/util/meson.build b/util/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..5aa7585e881ea070a8021489848b0a85165ee242 --- /dev/null +++ b/util/meson.build @@ -0,0 +1,67 @@ +hb_view_sources = [ + 'hb-view.cc', + 'options.cc', + 'ansi-print.cc', + 'helper-cairo.cc', + 'helper-cairo-ansi.cc', + 'view-cairo.cc', +] + +hb_shape_sources = [ + 'hb-shape.cc', + 'options.cc', +] + +hb_ot_shape_closure_sources = [ + 'hb-ot-shape-closure.cc', + 'options.cc', +] + +hb_subset_cli_sources = [ + 'hb-subset.cc', + 'options.cc', + 'options-subset.cc', +] + +util_deps = [freetype_dep, cairo_dep, cairo_ft_dep, glib_dep] + +if conf.get('HAVE_GLIB', 0) == 1 + if conf.get('HAVE_FREETYPE', 0) == 1 and conf.get('HAVE_CAIRO_FT', 0) == 1 + + hb_view = executable('hb-view', hb_view_sources, + cpp_args: cpp_args, + include_directories: [incconfig, incsrc], + dependencies: [util_deps, chafa_dep], + link_with: [libharfbuzz], + install: true, + ) + endif + + hb_shape = executable('hb-shape', hb_shape_sources, + cpp_args: cpp_args, + include_directories: [incconfig, incsrc], + dependencies: util_deps, + link_with: [libharfbuzz], + install: true, + ) + + hb_subset = executable('hb-subset', hb_subset_cli_sources, + cpp_args: cpp_args, + include_directories: [incconfig, incsrc], + dependencies: util_deps, + link_with: [libharfbuzz, libharfbuzz_subset], + install: true, + ) + + hb_ot_shape_closure = executable('hb-ot-shape-closure', hb_ot_shape_closure_sources, + cpp_args: cpp_args, + include_directories: [incconfig, incsrc], + dependencies: util_deps, + link_with: [libharfbuzz], + install: true, + ) +else + # Disable tests that use this + hb_shape = disabler() + hb_subset = disabler() +endif diff --git a/util/options-subset.cc b/util/options-subset.cc index b2f4db0875e77948a1e057887984807635a33e15..f1406c0259110bea4b876c807178143ba4f3a675 100644 --- a/util/options-subset.cc +++ b/util/options-subset.cc @@ -28,11 +28,71 @@ #include "hb-subset-input.hh" +static gboolean +parse_gids (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + subset_options_t *subset_opts = (subset_options_t *) data; + hb_set_t *gids = subset_opts->input->glyphs; + + char *s = (char *) arg; + char *p; + + while (s && *s) + { + while (*s && strchr (", ", *s)) + s++; + if (!*s) + break; + + errno = 0; + hb_codepoint_t start_code = strtoul (s, &p, 10); + if (s[0] == '-' || errno || s == p) + { + hb_set_destroy (gids); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing gids values at: '%s'", s); + return false; + } + + if (p && p[0] == '-') //gid ranges + { + s = ++p; + hb_codepoint_t end_code = strtoul (s, &p, 10); + if (s[0] == '-' || errno || s == p) + { + hb_set_destroy (gids); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing gids values at: '%s'", s); + return false; + } + + if (end_code < start_code) + { + hb_set_destroy (gids); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Invalid gids range value %u-%u", start_code, end_code); + return false; + } + hb_set_add_range (gids, start_code, end_code); + } + else + { + hb_set_add (gids, start_code); + } + s = p; + } + + return true; +} + static gboolean parse_nameids (const char *name, - const char *arg, - gpointer data, - GError **error G_GNUC_UNUSED) + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) { subset_options_t *subset_opts = (subset_options_t *) data; hb_set_t *name_ids = subset_opts->input->name_ids; @@ -46,7 +106,7 @@ parse_nameids (const char *name, { if (last_name_char == '-') hb_set_del_range (name_ids, 0, 0x7FFF); - else + else hb_set_add_range (name_ids, 0, 0x7FFF); return true; } @@ -67,7 +127,7 @@ parse_nameids (const char *name, { hb_set_destroy (name_ids); g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing nameID values at: '%s'", s); + "Failed parsing nameID values at: '%s'", s); return false; } @@ -84,11 +144,67 @@ parse_nameids (const char *name, return true; } +static gboolean +parse_name_languages (const char *name, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + subset_options_t *subset_opts = (subset_options_t *) data; + hb_set_t *name_languages = subset_opts->input->name_languages; + + char last_name_char = name[strlen (name) - 1]; + + if (last_name_char != '+' && last_name_char != '-') + hb_set_clear (name_languages); + + if (0 == strcmp (arg, "*")) + { + if (last_name_char == '-') + hb_set_del_range (name_languages, 0, 0x5FFF); + else + hb_set_add_range (name_languages, 0, 0x5FFF); + return true; + } + + char *s = (char *) arg; + char *p; + + while (s && *s) + { + while (*s && strchr (", ", *s)) + s++; + if (!*s) + break; + + errno = 0; + hb_codepoint_t u = strtoul (s, &p, 10); + if (errno || s == p) + { + hb_set_destroy (name_languages); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing name_languages values at: '%s'", s); + return false; + } + + if (last_name_char != '-') + { + hb_set_add (name_languages, u); + } else { + hb_set_del (name_languages, u); + } + + s = p; + } + + return true; +} + static gboolean parse_drop_tables (const char *name, - const char *arg, - gpointer data, - GError **error G_GNUC_UNUSED) + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) { subset_options_t *subset_opts = (subset_options_t *) data; hb_set_t *drop_tables = subset_opts->input->drop_tables; @@ -104,7 +220,7 @@ parse_drop_tables (const char *name, if (strlen (s) > 4) // Table tags are at most 4 bytes. { g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing table tag values at: '%s'", s); + "Failed parsing table tag values at: '%s'", s); return false; } @@ -128,8 +244,11 @@ subset_options_t::add_options (option_parser_t *parser) { {"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->input->drop_hints, "Whether to drop hints", nullptr}, {"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->input->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr}, + {"gids", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids, "Specify glyph IDs or ranges to include in the subset", "list of comma/whitespace-separated int numbers or ranges"}, {"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->input->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr}, {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers"}, + {"name-legacy", 0, 0, G_OPTION_ARG_NONE, &this->input->name_legacy, "Keep legacy (non-Unicode) 'name' table entries", nullptr}, + {"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs", "list of int numbers"}, {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."}, {"drop-tables+", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."}, {"drop-tables-", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."}, @@ -137,8 +256,8 @@ subset_options_t::add_options (option_parser_t *parser) {nullptr} }; parser->add_group (entries, - "subset", - "Subset options:", - "Options subsetting", - this); + "subset", + "Subset options:", + "Options subsetting", + this); } diff --git a/util/options.cc b/util/options.cc index f71a5a34dc6ac96335b30a97400d3fd258826032..caf8233f720d86cf68ae13e5f6e3d60bec9d5d0f 100644 --- a/util/options.cc +++ b/util/options.cc @@ -116,7 +116,7 @@ pre_parse (GOptionContext *context G_GNUC_UNUSED, { option_group_t *option_group = (option_group_t *) data; option_group->pre_parse (error); - return *error == nullptr; + return !*error; } static gboolean @@ -127,7 +127,7 @@ post_parse (GOptionContext *context G_GNUC_UNUSED, { option_group_t *option_group = static_cast(data); option_group->post_parse (error); - return *error == nullptr; + return !*error; } void @@ -152,15 +152,39 @@ option_parser_t::parse (int *argc, char ***argv) GError *parse_error = nullptr; if (!g_option_context_parse (context, argc, argv, &parse_error)) { - if (parse_error != nullptr) { + if (parse_error) + { fail (true, "%s", parse_error->message); //g_error_free (parse_error); - } else + } + else fail (true, "Option parse error"); } } +static gboolean +parse_font_extents (const char *name G_GNUC_UNUSED, + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) +{ + view_options_t *view_opts = (view_options_t *) data; + view_options_t::font_extents_t &e = view_opts->font_extents; + switch (sscanf (arg, "%lf%*[ ,]%lf%*[ ,]%lf", &e.ascent, &e.descent, &e.line_gap)) { + case 1: HB_FALLTHROUGH; + case 2: HB_FALLTHROUGH; + case 3: + view_opts->have_font_extents = true; + return true; + default: + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "%s argument should be one to three space-separated numbers", + name); + return false; + } +} + static gboolean parse_margin (const char *name G_GNUC_UNUSED, const char *arg, @@ -196,8 +220,8 @@ parse_shapers (const char *name G_GNUC_UNUSED, bool found = false; for (const char **hb_shaper = hb_shape_list_shapers (); *hb_shaper; hb_shaper++) { if (strcmp (*shaper, *hb_shaper) == 0) { - found = true; - break; + found = true; + break; } } if (!found) { @@ -228,9 +252,9 @@ list_shapers (const char *name G_GNUC_UNUSED, static gboolean parse_features (const char *name G_GNUC_UNUSED, - const char *arg, - gpointer data, - GError **error G_GNUC_UNUSED) + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) { shape_options_t *shape_opts = (shape_options_t *) data; char *s = (char *) arg; @@ -271,9 +295,9 @@ parse_features (const char *name G_GNUC_UNUSED, static gboolean parse_variations (const char *name G_GNUC_UNUSED, - const char *arg, - gpointer data, - GError **error G_GNUC_UNUSED) + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) { font_options_t *font_opts = (font_options_t *) data; char *s = (char *) arg; @@ -335,9 +359,9 @@ parse_text (const char *name G_GNUC_UNUSED, static gboolean parse_unicodes (const char *name G_GNUC_UNUSED, - const char *arg, - gpointer data, - GError **error G_GNUC_UNUSED) + const char *arg, + gpointer data, + GError **error G_GNUC_UNUSED) { text_options_t *text_opts = (text_options_t *) data; @@ -349,7 +373,7 @@ parse_unicodes (const char *name G_GNUC_UNUSED, } GString *gs = g_string_new (nullptr); - if (0 == strcmp (arg, "*")) + if (0 == strcmp (arg, "*")) { g_string_append_c (gs, '*'); } @@ -358,26 +382,26 @@ parse_unicodes (const char *name G_GNUC_UNUSED, char *s = (char *) arg; char *p; - + while (s && *s) { while (*s && strchr (DELIMITERS, *s)) - s++; + s++; if (!*s) - break; - + break; + errno = 0; hb_codepoint_t u = strtoul (s, &p, 16); if (errno || s == p) { - g_string_free (gs, TRUE); - g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, - "Failed parsing Unicode values at: '%s'", s); - return false; + g_string_free (gs, TRUE); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed parsing Unicode values at: '%s'", s); + return false; } - + g_string_append_unichar (gs, u); - + s = p; } } @@ -397,6 +421,7 @@ view_options_t::add_options (option_parser_t *parser) {"background", 0, 0, G_OPTION_ARG_STRING, &this->back, "Set background color (default: " DEFAULT_BACK ")", "rrggbb/rrggbbaa"}, {"foreground", 0, 0, G_OPTION_ARG_STRING, &this->fore, "Set foreground color (default: " DEFAULT_FORE ")", "rrggbb/rrggbbaa"}, {"line-space", 0, 0, G_OPTION_ARG_DOUBLE, &this->line_space, "Set space between lines (default: 0)", "units"}, + {"font-extents", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_extents, "Set font ascent/descent/line-gap (default: auto)","one to three numbers"}, {"margin", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_margin, "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"}, {nullptr} }; @@ -624,7 +649,7 @@ output_options_t::add_options (option_parser_t *parser) { const char *text; - if (nullptr == supported_formats) + if (!supported_formats) text = "Set output serialization format"; else { @@ -716,7 +741,7 @@ font_options_t::get_font () const GString *s = g_string_new (nullptr); for (unsigned int i = 0; i < ARRAY_LENGTH (supported_font_funcs); i++) { - if (i) + if (i) g_string_append_c (s, '/'); g_string_append (s, supported_font_funcs[i].name); } @@ -746,7 +771,7 @@ text_options_t::get_line (unsigned int *len) line = text; line_len = text_len; } - if (line_len == (unsigned int) -1) + if (line_len == UINT_MAX) line_len = strlen (line); if (!line_len) { @@ -877,55 +902,36 @@ format_options_t::add_options (option_parser_t *parser) parser->add_group (entries, "output-syntax", "Output syntax:\n" - " text: [=@,+,|...]\n" - " json: [{\"g\": , \"ax\": , \"ay\": , \"dx\": , \"dy\": , \"cl\": }, ...]\n" - "\nOutput syntax options:", + " text: [=@,+,|...]\n" + " json: [{\"g\": , \"ax\": , \"ay\": , \"dx\": , \"dy\": , \"cl\": }, ...]\n" + "\nOutput syntax options:", "Options for the syntax of the output", this); } void -format_options_t::serialize_unicode (hb_buffer_t *buffer, - GString *gs) -{ - unsigned int num_glyphs = hb_buffer_get_length (buffer); - hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr); - - g_string_append_c (gs, '<'); - for (unsigned int i = 0; i < num_glyphs; i++) - { - if (i) - g_string_append_c (gs, ','); - g_string_append_printf (gs, "U+%04X", info->codepoint); - info++; - } - g_string_append_c (gs, '>'); -} - -void -format_options_t::serialize_glyphs (hb_buffer_t *buffer, +format_options_t::serialize (hb_buffer_t *buffer, hb_font_t *font, hb_buffer_serialize_format_t output_format, hb_buffer_serialize_flags_t flags, GString *gs) { - g_string_append_c (gs, '['); unsigned int num_glyphs = hb_buffer_get_length (buffer); unsigned int start = 0; while (start < num_glyphs) { - char buf[1024]; + char buf[32768]; unsigned int consumed; - start += hb_buffer_serialize_glyphs (buffer, start, num_glyphs, + start += hb_buffer_serialize (buffer, start, num_glyphs, buf, sizeof (buf), &consumed, font, output_format, flags); if (!consumed) break; g_string_append (gs, buf); } - g_string_append_c (gs, ']'); } + void format_options_t::serialize_line_no (unsigned int line_no, GString *gs) @@ -953,7 +959,7 @@ format_options_t::serialize_buffer_of_text (hb_buffer_t *buffer, if (show_unicode) { serialize_line_no (line_no, gs); - serialize_unicode (buffer, gs); + serialize (buffer, font, HB_BUFFER_SERIALIZE_FORMAT_TEXT, HB_BUFFER_SERIALIZE_FLAG_DEFAULT, gs); g_string_append_c (gs, '\n'); } } @@ -978,6 +984,6 @@ format_options_t::serialize_buffer_of_glyphs (hb_buffer_t *buffer, GString *gs) { serialize_line_no (line_no, gs); - serialize_glyphs (buffer, font, output_format, format_flags, gs); + serialize (buffer, font, output_format, format_flags, gs); g_string_append_c (gs, '\n'); } diff --git a/util/options.hh b/util/options.hh index 63360ca5f95058fb0789fc3c5adce8de34a68230..30b8f5b0048b449d885e5cb2587627d610064463 100644 --- a/util/options.hh +++ b/util/options.hh @@ -125,6 +125,8 @@ struct view_options_t : option_group_t fore = nullptr; back = nullptr; line_space = 0; + have_font_extents = false; + font_extents.ascent = font_extents.descent = font_extents.line_gap = 0; margin.t = margin.r = margin.b = margin.l = DEFAULT_MARGIN; add_options (parser); @@ -141,6 +143,10 @@ struct view_options_t : option_group_t char *fore; char *back; double line_space; + bool have_font_extents; + struct font_extents_t { + double ascent, descent, line_gap; + } font_extents; struct margin_t { double t, r, b, l; } margin; @@ -242,7 +248,7 @@ struct shape_options_t : option_group_t if (!hb_shape_full (font, buffer, features, num_features, shapers)) { if (error) - *error = "all shapers failed."; + *error = "all shapers failed."; goto fail; } @@ -341,7 +347,7 @@ struct shape_options_t : option_group_t /* Shape segment corresponding to glyphs start..end. */ if (end == num_glyphs) { - if (forward) + if (forward) text_end = num_chars; else text_start = 0; @@ -372,9 +378,9 @@ struct shape_options_t : option_group_t /* TODO: Add pre/post context text. */ hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); if (0 < text_start) - flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); if (text_end < num_chars) - flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); hb_buffer_set_flags (fragment, flags); hb_buffer_append (fragment, text_buffer, text_start, text_end); @@ -517,7 +523,7 @@ struct text_options_t : option_group_t fp = nullptr; gs = nullptr; line = nullptr; - line_len = (unsigned int) -1; + line_len = UINT_MAX; add_options (parser); } @@ -629,9 +635,7 @@ struct format_options_t : option_group_t void add_options (option_parser_t *parser) override; - void serialize_unicode (hb_buffer_t *buffer, - GString *gs); - void serialize_glyphs (hb_buffer_t *buffer, + void serialize (hb_buffer_t *buffer, hb_font_t *font, hb_buffer_serialize_format_t format, hb_buffer_serialize_flags_t flags, diff --git a/util/view-cairo.cc b/util/view-cairo.cc index e8e334bebc0793c70c63c63c42fff3aecdd0f0bb..0db3306afcc5cb3e52148f5d7c23bdc8c3ee911a 100644 --- a/util/view-cairo.cc +++ b/util/view-cairo.cc @@ -40,17 +40,25 @@ view_cairo_t::render (const font_options_t *font_opts) int y_sign = font_opts->font_size_y < 0 ? -1 : +1; hb_font_t *font = font_opts->get_font(); - hb_font_extents_t extents; - hb_font_get_extents_for_direction (font, direction, &extents); - double ascent = y_sign * scalbn ((double) extents.ascender, scale_bits); - double descent = y_sign * -scalbn ((double) extents.descender, scale_bits); - double font_height = y_sign * scalbn ((double) extents.ascender - extents.descender + extents.line_gap, scale_bits); - double leading = font_height + view_options.line_space; + view_options_t::font_extents_t extents = view_options.font_extents; + if (!view_options.have_font_extents) + { + hb_font_extents_t hb_extents; + hb_font_get_extents_for_direction (font, direction, &hb_extents); + extents.ascent = scalbn ((double) hb_extents.ascender, scale_bits); + extents.descent = -scalbn ((double) hb_extents.descender, scale_bits); + extents.line_gap = scalbn ((double) hb_extents.line_gap, scale_bits); + } + + double ascent = y_sign * extents.ascent; + double descent = y_sign * extents.descent; + double line_gap = y_sign * extents.line_gap + view_options.line_space; + double leading = ascent + descent + line_gap; /* Calculate surface size. */ double w = 0, h = 0; - (vertical ? w : h) = (int) lines->len * leading - view_options.line_space; + (vertical ? w : h) = (int) lines->len * leading - (extents.line_gap + view_options.line_space); (vertical ? h : w) = 0; for (unsigned int i = 0; i < lines->len; i++) { helper_cairo_line_t &line = g_array_index (lines, helper_cairo_line_t, i); @@ -79,8 +87,7 @@ view_cairo_t::render (const font_options_t *font_opts) cairo_translate (cr, view_options.margin.l, view_options.margin.t); if (vertical) cairo_translate (cr, - w /* We stack lines right to left */ - -font_height * .5 /* "ascent" for vertical */, + w - ascent, /* We currently always stack lines right to left */ y_sign < 0 ? h : 0); else {