Merge branch 'main' into simd

This commit is contained in:
Behdad Esfahbod 2023-05-04 12:24:13 -06:00
commit 112877a530
3772 changed files with 151790 additions and 82178 deletions

View file

@ -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

28
.ci/build-win32.sh Executable file
View file

@ -0,0 +1,28 @@
#!/bin/bash
set -e
meson --cross-file=.ci/win32-cross-file.txt \
--wrap-mode=default \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
win32build \
$@
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."

28
.ci/build-win64.sh Normal file
View file

@ -0,0 +1,28 @@
#!/bin/bash
set -e
meson --cross-file=.ci/win64-cross-file.txt \
--wrap-mode=default \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
win64build \
$@
ninja -Cwin64build -j3 # building with all the cores won't work fine with CricleCI for some reason
rm -rf win64build/harfbuzz-win64
mkdir win64build/harfbuzz-win64
cp win64build/util/hb-*.exe win64build/harfbuzz-win64
find win64build -name '*.dll' -exec cp {} win64build/harfbuzz-win64 \;
x86_64-w64-mingw32-strip win64build/harfbuzz-win64/*.{dll,exe}
rm -f harfbuzz-win64.zip
(cd win64build && zip -r ../harfbuzz-win64.zip harfbuzz-win64)
echo "harfbuzz-win64.zip is ready."

View file

@ -3,13 +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
REVISION=$(git rev-parse --short HEAD)
@ -17,20 +10,24 @@ 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"
git config user.email "travis@harfbuzz.org"
git branch -m main
git config user.name "CI"
git config user.email "harfbuzz-admin@googlegroups.com"
set +x
echo "git remote add upstream \"https://\$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git\""
git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git"
set -x
git fetch upstream
git reset upstream/master
git reset upstream/main
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:main
fi

View file

@ -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

23
.ci/publish_release_artifact.sh Executable file
View file

@ -0,0 +1,23 @@
#!/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
if ! hash ghr 2> /dev/null; then
_GHR_VER=v0.14.0
_GHR=ghr_${_GHR_VER}_linux_amd64
mkdir -p $HOME/.local/bin
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
fi
ghr -replace \
-u $CIRCLE_PROJECT_USERNAME \
-r $CIRCLE_PROJECT_REPONAME \
$CIRCLE_TAG \
$1

View file

@ -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

View file

@ -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

20
.ci/win32-cross-file.txt Normal file
View file

@ -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'

20
.ci/win64-cross-file.txt Normal file
View file

@ -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'

View file

@ -1,357 +1,216 @@
version: 2
version: 2.1
executors:
win32-executor:
docker:
- image: cimg/base:edge-20.04
win64-executor:
docker:
- image: cimg/base:edge-20.04
autotools-executor:
docker:
- image: cimg/base:edge-20.04
jobs:
macos-10.12.6-aat-fonts:
macos-aat-fonts:
macos:
xcode: "9.0.1"
xcode: "12.5.1"
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
macos-10.13.6-aat-fonts:
macos:
xcode: "10.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
macos-10.14.4-aat-fonts:
macos:
xcode: "11.1.0"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2 cmake
- 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: cmake -Bbuild -H. -DHB_HAVE_CORETEXT=1 -DHB_BUILD_TESTS=0 && cmake --build build
macos-10.15-aat-fonts:
macos:
xcode: "11.2.1"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2 cmake
- 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: cmake -Bbuild -H. -DHB_HAVE_CORETEXT=1 -DHB_BUILD_TESTS=0 && cmake --build build
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection ninja
- run: pip3 install meson --upgrade
- run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson setup build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Ddocs=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
- 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
alpine-O3-Os-NOMMAP:
publish-dist:
executor: autotools-executor
steps:
- checkout
- attach_workspace:
at: .
- run: |
.ci/publish_release_artifact.sh harfbuzz-$CIRCLE_TAG.tar.xz
fedora-valgrind:
docker:
- image: fedora:36
steps:
- checkout
- 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 setup build --buildtype=debugoptimized
- run: meson compile -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 --num-processes=$(($(nproc)/2 + 1))
alpine:
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
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
- run: pip3 install meson==0.56.0
- run: meson setup build --buildtype=minsize
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs
archlinux-py3-all:
asan-ubsan:
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
- image: ubuntu:20.04
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
- run: make -Csrc CPPFLAGS="-DHB_TINY -DHB_NO_OT_FONT" libharfbuzz-subset.la && make clean
- run: clang -c src/hb-*.cc -DHB_NO_MT
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: pip3 install meson==0.56.0
- run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
gcc-valgrind:
tsan:
docker:
- image: ubuntu:18.10
- image: ubuntu:20.04
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: HB_TEST_SHAPE_FUZZER_TIMEOUT=3 HB_TEST_SUBSET_FUZZER_TIMEOUT=30 RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
# informational for now
- run: make -Ctest/api check-symbols || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: pip3 install meson==0.56.0
- run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
clang-everything:
msan:
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 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 -DHB_WITH_WIN1256" 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 -DHB_WITH_WIN1256" 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
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: pip3 install meson==0.56.0
# msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
- run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
clang-asan:
clang-cxx2a:
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 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: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils
- run: clang -c src/harfbuzz-subset.cc -DHB_NO_MT -Werror -std=c++2a
clang-msan:
docker:
- image: ubuntu:18.10
crossbuild-win32:
executor: win32-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 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 HB_TEST_SUBSET_FUZZER_TIMEOUT=12 make check || .ci/fail.sh | asan_symbolize | c++filt
clang-tsan:
docker:
- image: ubuntu:18.10
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: HB_TEST_SUBSET_FUZZER_TIMEOUT=40 make check || .ci/fail.sh | asan_symbolize | c++filt
clang-ubsan:
docker:
- image: ubuntu:18.10
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 -fno-sanitize-recover=undefined" LDFLAGS="-fsanitize=undefined -fno-sanitize-recover=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: UBSAN_OPTIONS=print_stacktrace=1 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 diffutils glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true
- run: NOCONFIGURE=1 ./autogen.sh
- run: mkdir build && cd build && CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ../configure --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 && 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
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-i686 zip
- run: pip3 install meson==0.60.0
- run: .ci/build-win32.sh
- store_artifacts:
path: winbuild32/harfbuzz-win32.zip
destination: harfbuzz-win32.zip
path: harfbuzz-win32.zip
- persist_to_workspace:
root: .
paths: harfbuzz-win32.zip
publish-win32:
executor: win32-executor
steps:
- checkout
- attach_workspace:
at: .
- run: |
mv harfbuzz-win32{,-$CIRCLE_TAG}.zip
.ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip
crossbuild-win64:
executor: win64-executor
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-x86-64 zip
- run: pip3 install meson==0.60.0
- run: bash .ci/build-win64.sh
- store_artifacts:
path: winbuild64/harfbuzz-win64.zip
destination: harfbuzz-win64.zip
path: harfbuzz-win64.zip
- persist_to_workspace:
root: .
paths: harfbuzz-win64.zip
cmake-gcc:
docker:
- image: ubuntu:19.04
publish-win64:
executor: win64-executor
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
- attach_workspace:
at: .
- run: |
mv harfbuzz-win64{,-$CIRCLE_TAG}.zip
.ci/publish_release_artifact.sh harfbuzz-win64-$CIRCLE_TAG.zip
#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
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
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
workflows:
version: 2
build:
jobs:
# macOS
- macos-10.12.6-aat-fonts
- macos-10.13.6-aat-fonts
- macos-10.14.4-aat-fonts
- macos-10.15-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-aat-fonts
- distcheck:
filters: # must have filter or won't work as a dependency
tags:
only: /.*/
- publish-dist:
requires:
- distcheck
filters:
tags:
only: /^\d+\.\d+\.\d+$/
branches:
ignore: /.*/
- fedora-valgrind
- alpine
- asan-ubsan
- tsan
- msan
- clang-cxx2a
- crossbuild-win32:
filters: # must have filter or won't work as a dependency
tags:
only: /.*/
- crossbuild-win64:
filters: # must have filter or won't work as a dependency
tags:
only: /.*/
- publish-win32:
requires:
- crossbuild-win32
filters:
tags:
only: /^\d+\.\d+\.\d+$/
branches:
ignore: /.*/
- publish-win64:
requires:
- crossbuild-win64
filters:
tags:
only: /^\d+\.\d+\.\d+$/
branches:
ignore: /.*/

View file

@ -1,7 +1,10 @@
comment: off
comment: false
coverage:
status:
project:
default:
threshold: 1%
informational: true
patch:
default:
informational: true

View file

@ -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

6
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

25
.github/workflows/arm-ci.yml vendored Normal file
View file

@ -0,0 +1,25 @@
name: arm
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
arm-none-eabi:
runs-on: ubuntu-22.04
container:
image: devkitpro/devkitarm:latest
steps:
- uses: actions/checkout@v3
- name: Configure CMake
run: |
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake
- name: Build
run: make CXX_FLAGS="-w -DHB_NO_MT"
working-directory: build

28
.github/workflows/cifuzz.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: CIFuzz
on: [pull_request]
permissions:
contents: read
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'harfbuzz'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'harfbuzz'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v3
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

27
.github/workflows/configs-build.yml vendored Normal file
View file

@ -0,0 +1,27 @@
name: configs-ci
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: install dependencies
run: sudo apt-get install gcc
- name: HB_DISABLE_DEPRECATED
run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_DISABLE_DEPRECATED
- name: HB_MINI
run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_MINI
- name: HB_LEAN
run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_LEAN
- name: HB_TINY
run: g++ -std=c++11 -c src/harfbuzz.cc -DHB_TINY

42
.github/workflows/coverity-scan.yml vendored Normal file
View file

@ -0,0 +1,42 @@
name: coverity-scan
on:
schedule:
- cron: '0 10 * * *' # Daily at 10:00 UTC
permissions:
contents: read
jobs:
latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev
- name: Download Coverity
run: |
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=HarfBuzz" -O cov-analysis-linux64.tar.gz
mkdir cov-analysis-linux64
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
# ideally we should've used meson and ninja here but it complains about coverage or something
- run: cov-analysis-linux64/bin/cov-build --dir cov-int clang src/hb-*.cc -DHAVE_FREETYPE -DHAVE_GRAPHITE2 -DHAVE_GLIB -DHAVE_ICU `pkg-config --cflags freetype2 graphite2 glib-2.0 icu-uc` -DHAVE_ROUNDF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H -DHAVE_GETPAGESIZE -DHB_EXPERIMENTAL_API -c
- run: tar czvf harfbuzz.tgz cov-int
- name: submit to coverity
run: |
curl \
--form project=HarfBuzz \
--form token=$TOKEN \
--form email=harfbuzz-bots-chatter@googlegroups.com \
--form file=@harfbuzz.tgz \
--form version=trunk \
--form description="`git rev-parse --short HEAD`" \
https://scan.coverity.com/builds?project=HarfBuzz
env:
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}

71
.github/workflows/linux-ci.yml vendored Normal file
View file

@ -0,0 +1,71 @@
name: linux-ci
on:
push:
branches: [ main ]
tags: ["*.*.*"]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install \
gcc \
gobject-introspection \
gtk-doc-tools \
libcairo2-dev \
libfreetype6-dev \
libgirepository1.0-dev \
libglib2.0-dev \
libgraphite2-dev \
libicu-dev \
ninja-build \
pkg-config \
python3 \
python3-setuptools
- name: Install Python Dependencies
run: sudo pip3 install fonttools meson==0.56.0 gcovr==5.0
- name: Setup Meson
run: |
ccache --version
meson setup build \
-Dauto_features=enabled \
-Dchafa=disabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Db_coverage=true \
-Ddoc_tests=true \
-Dragel_subproject=true
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs -Cbuild
- name: Generate Documentations
run: ninja -Cbuild harfbuzz-doc
- name: Deploy Documentations
if: github.ref_type == 'tag'
run: .ci/deploy-docs.sh
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
REVISION: ${{ github.sha }}
- name: Generate Coverage
run: ninja -Cbuild coverage-xml
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
file: build/meson-logs/coverage.xml

60
.github/workflows/macos-ci.yml vendored Normal file
View file

@ -0,0 +1,60 @@
name: macos-ci
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- name: Install Dependencies
run: |
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install \
cairo \
freetype \
glib \
gobject-introspection \
graphite2 \
icu4c \
meson \
ninja \
pkg-config
- name: Install Python Dependencies
run: pip3 install fonttools gcovr==5.0
- name: Setup Meson
run: |
export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig"
ccache --version
meson setup build \
-Dauto_features=enabled \
-Ddocs=disabled \
-Dchafa=disabled \
-Dcoretext=enabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Db_coverage=true \
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs -Cbuild
- name: Generate Coverage
run: ninja -Cbuild coverage-xml
- name: Upload Coverage
uses: codecov/codecov-action@v3
with:
file: build/meson-logs/coverage.xml

61
.github/workflows/msvc-ci.yml vendored Normal file
View file

@ -0,0 +1,61 @@
name: msvc
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
msvc:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-2019, windows-latest]
include:
- name: msvc-2019-x86
os: windows-2019
ARCH: x86
- name: msvc-2019-amd64
os: windows-latest
ARCH: amd64
name: ${{ matrix.name }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
variant: sccache
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
with:
arch : ${{ matrix.ARCH }}
- name: Install Python Dependencies
run: |
pip install --upgrade meson ninja fonttools
- name: Setup Meson
run: |
sccache --version
meson setup build `
--wrap-mode=forcefallback `
--buildtype=release `
-Dglib=enabled `
-Dfreetype=enabled `
-Dgdi=enabled `
-Ddirectwrite=enabled
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild

73
.github/workflows/msys2-ci.yml vendored Normal file
View file

@ -0,0 +1,73 @@
name: msys2
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
msys2:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- MSYSTEM: MINGW32
MSYS2_ARCH: i686
- MSYSTEM: MINGW64
MSYS2_ARCH: x86_64
name: ${{ matrix.MSYSTEM }}
env:
# XXX: For some reason enabling jit debugging "fixes" random python crashes
# see https://github.com/msys2/MINGW-packages/issues/11864
MSYS: "winjitdebug"
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.MSYSTEM }}
update: true
install: >-
mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo
mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs
mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext
mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2
mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection
mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2
mingw-w64-${{ matrix.MSYS2_ARCH }}-icu
mingw-w64-${{ matrix.MSYS2_ARCH }}-meson
mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config
mingw-w64-${{ matrix.MSYS2_ARCH }}-python
mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip
- name: Install Python Dependencies
run: |
pip install --upgrade fonttools
- name: Setup Meson
run: |
meson setup build \
--wrap-mode=nodownload \
--auto-features=enabled \
-Ddocs=disabled \
-Ddirectwrite=enabled \
-Dgdi=enabled \
-Dgraphite=enabled \
-Dchafa=disabled
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild

View file

@ -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

View file

@ -1,50 +1,29 @@
On Linux, install the development packages for FreeType,
Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
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-devel
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. It is recommended to install CMake either manually
or via the Visual Studio installer when building with MSVC, using meson.
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.

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.8.0)
cmake_minimum_required(VERSION 3.12)
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)
@ -37,6 +37,10 @@ option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
option(HB_HAVE_GLIB "Enable glib unicode functions" OFF)
option(HB_HAVE_ICU "Enable icu unicode functions" OFF)
if (TARGET freetype)
set (HB_HAVE_FREETYPE ON)
add_definitions(-DHAVE_FREETYPE=1)
endif ()
if (APPLE)
option(HB_HAVE_CORETEXT "Enable CoreText shaper backend on macOS" ON)
set (CMAKE_MACOSX_RPATH ON)
@ -53,7 +57,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 +69,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
@ -96,6 +80,7 @@ include (FindPythonInterp)
## Functions and headers
include (CheckFunctionExists)
include (CheckIncludeFile)
include (CheckIncludeFiles)
macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
foreach (func_name ${ARGN})
string(TOUPPER ${func_name} definition_to_add)
@ -108,7 +93,7 @@ endmacro ()
if (UNIX)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
endif ()
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
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 +102,24 @@ 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 ()
# These will be used while making pkg-config .pc files
set(PC_REQUIRES_PRIV "")
set(PC_LIBS_PRIV "")
if (NOT MSVC)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
if (CMAKE_USE_PTHREADS_INIT)
add_definitions("-DHAVE_PTHREAD")
list(APPEND THIRD_PARTY_LIBS Threads::Threads)
list(APPEND PC_LIBS_PRIV -pthread)
endif ()
endif ()
if (MSVC)
add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
@ -147,7 +141,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}})
@ -200,7 +194,7 @@ set (project_headers ${HB_BASE_headers})
set (subset_project_headers ${HB_SUBSET_headers})
## Find and include needed header folders and libraries
if (HB_HAVE_FREETYPE)
if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
include (FindFreetype)
if (NOT FREETYPE_FOUND)
message(FATAL_ERROR "HB_HAVE_FREETYPE was set, but we failed to find it. Maybe add a CMAKE_PREFIX_PATH= to your Freetype2 install prefix")
@ -219,6 +213,10 @@ if (HB_HAVE_FREETYPE)
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
endif ()
if (HB_HAVE_FREETYPE)
list(APPEND PC_REQUIRES_PRIV "freetype2 >= 12.0.6")
endif ()
if (HB_HAVE_GRAPHITE2)
add_definitions(-DHAVE_GRAPHITE2)
@ -231,6 +229,8 @@ if (HB_HAVE_GRAPHITE2)
list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
list(APPEND PC_REQUIRES_PRIV "graphite2 >= 1.2.0")
mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
endif ()
@ -251,13 +251,15 @@ if (HB_HAVE_GLIB)
list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
list(APPEND PC_REQUIRES_PRIV "glib-2.0 >= 2.19.1")
mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
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)
@ -283,24 +285,28 @@ if (APPLE AND HB_HAVE_CORETEXT)
find_library(COREFOUNDATION CoreFoundation)
if (COREFOUNDATION)
list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
list(APPEND PC_LIBS_PRIV "-framework CoreFoundation")
endif ()
mark_as_advanced(COREFOUNDATION)
find_library(CORETEXT CoreText)
if (CORETEXT)
list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
list(APPEND PC_LIBS_PRIV "-framework CoreText")
endif ()
mark_as_advanced(CORETEXT)
find_library(COREGRAPHICS CoreGraphics)
if (COREGRAPHICS)
list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS})
list(APPEND PC_LIBS_PRIV "-framework CoreGraphics")
endif ()
mark_as_advanced(COREGRAPHICS)
else ()
find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
if (APPLICATION_SERVICES_FRAMEWORK)
list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
list(APPEND PC_LIBS_PRIV "-framework ApplicationServices")
endif ()
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
@ -311,21 +317,31 @@ if (WIN32 AND HB_HAVE_GDI)
add_definitions(-DHAVE_GDI)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
list(APPEND THIRD_PARTY_LIBS gdi32)
list(APPEND PC_LIBS_PRIV -lgdi32)
endif ()
if (WIN32 AND HB_HAVE_UNISCRIBE)
add_definitions(-DHAVE_UNISCRIBE)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
list(APPEND PC_LIBS_PRIV -lusp10 -lgdi32 -lrpcrt4)
endif ()
if (WIN32 AND HB_HAVE_DIRECTWRITE)
if (CMAKE_VERSION VERSION_GREATER 3.12)
check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H LANGUAGE CXX)
else ()
check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H)
endif ()
if (NOT HAVE_DWRITE_1_H)
message(FATAL_ERROR "DirectWrite was enabled explicitly, but required header is missing")
endif ()
add_definitions(-DHAVE_DIRECTWRITE)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
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 +445,16 @@ 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 <atomic.h>
/* This requires Solaris Studio 12.2 or newer: */
#include <mbarrier.h>
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
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
if (HB_HAVE_FREETYPE AND TARGET freetype)
target_link_libraries(harfbuzz freetype)
endif ()
## Define harfbuzz-icu library
@ -481,6 +472,7 @@ endif ()
## Define harfbuzz-subset library
if (HB_BUILD_SUBSET)
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-subset.h)
add_dependencies(harfbuzz-subset harfbuzz)
target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
@ -497,7 +489,9 @@ if (UNIX OR MINGW)
link_libraries(-Bsymbolic-functions)
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# As of CMake 3.0.0, the compiler id for Apple-provided Clang is now "AppleClang";
# thus we use MATCHES instead of STREQUAL to include either regular Clang or AppleClang
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Make sure we don't link to libstdc++
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm
@ -572,7 +566,7 @@ if (HB_HAVE_INTROSPECTION)
# We need to account for the varying output directories
# when we build using Visual Studio projects
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
else ()
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
endif ()
@ -628,12 +622,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
@ -724,6 +720,44 @@ if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
endif ()
endif ()
# get these variables in the required format
list(REMOVE_DUPLICATES PC_REQUIRES_PRIV)
string(REPLACE ";" ", " PC_REQUIRES_PRIV "${PC_REQUIRES_PRIV}")
list(REMOVE_DUPLICATES PC_LIBS_PRIV)
string(REPLACE ";" " " PC_LIBS_PRIV "${PC_LIBS_PRIV}")
# Macro to write pkg-config .pc configuration files
macro ( make_pkgconfig_pc_file name )
file(READ "${PROJECT_SOURCE_DIR}/src/${name}.pc.in" FSTR)
string(REPLACE "%prefix%" "${CMAKE_INSTALL_PREFIX}" FSTR ${FSTR})
string(REPLACE "%exec_prefix%" "\${prefix}" FSTR ${FSTR})
if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
string(REPLACE "%includedir%" "${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
else ()
string(REPLACE "%includedir%" "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
endif ()
if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
string(REPLACE "%libdir%" "${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
else ()
string(REPLACE "%libdir%" "\${prefix}/${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
endif ()
string(REPLACE "%VERSION%" "${HB_VERSION}" FSTR ${FSTR})
string(REPLACE "%requires_private%" "${PC_REQUIRES_PRIV}" FSTR ${FSTR})
string(REPLACE "%libs_private%" "${PC_LIBS_PRIV}" FSTR ${FSTR})
file(WRITE "${PROJECT_BINARY_DIR}/${name}.pc" ${FSTR})
install(
FILES "${PROJECT_BINARY_DIR}/${name}.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
COMPONENT pkgconfig
)
endmacro ( make_pkgconfig_pc_file )
if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS harfbuzz
EXPORT harfbuzzConfig
@ -732,6 +766,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz")
install(EXPORT harfbuzzConfig
NAMESPACE harfbuzz::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
@ -743,6 +778,13 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz-icu")
endif ()
if (HB_BUILD_SUBSET)
install(TARGETS harfbuzz-subset
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
make_pkgconfig_pc_file("harfbuzz-subset")
endif ()
if (HB_BUILD_UTILS)
if (WIN32 AND BUILD_SHARED_LIBS)
@ -771,9 +813,10 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
make_pkgconfig_pc_file("harfbuzz-gobject")
if (HB_HAVE_INTROSPECTION)
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
else ()
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
endif ()
@ -788,54 +831,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 ()

View file

@ -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
@ -101,15 +100,16 @@ This is very rarely what you need. Make sure you understand exactly what you
are doing.
Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless. That removes the
(unused) "fallback" shaper.
(unused) "fallback" shaper. This is defined by the `HB_TINY` profile already
(more below).
## Thread-safety
By default HarfBuzz builds as a thread-safe library. The exception is that
the `HB_TINY` predefined configuring (more below) disables thread-safety.
the `HB_TINY` predefined configuration (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`.
@ -136,16 +136,23 @@ The pre-defined configurations are:
Most of the time, one of the pre-defined configuration is exactly what one needs.
Sometimes, however, the pre-defined configuration cuts out features that might
be desired in the library. Unfortunately there is no quick way to undo those
configurations from the command-line. But one can add a header file called
`config-override.h` to undefine certain `HB_NO_*` symbols as desired. Then
define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
overrides at the end.
configurations from the command-line.
However, configuration can still be overridden from a file. To do that, add your
override instructions (mostly `undef` instructions) to a header file and define
the macro `HB_CONFIG_OVERRIDE_H` to the string containing to that header file's
name. HarfBuzz will then include that file at the appropriate place during
configuration.
Up until HarfBuzz 3.1.2 the the configuration override header file's name was
fixed and called `config-override.h`, and was activated by defining the macro
`HAVE_CONFIG_OVERRIDE_H`. That still works.
## 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
for CFF fonts.
This option disables (among other things) the code to calculate glyph extents
for CFF fonts, which many clients might not need.

21
COPYING
View file

@ -2,18 +2,23 @@ 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 © 2012 Mozilla Foundation
Copyright © 2010-2022 Google, Inc.
Copyright © 2015-2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012,2015 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2011 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2006 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
Copyright © 1998-2005 David Turner and Werner Lemberg
Copyright © 2016 Igalia S.L.
Copyright © 2022 Matthias Clasen
Copyright © 2018,2021 Khaled Hosny
Copyright © 2018,2019,2020 Adobe, Inc
Copyright © 2013-2015 Alexei Podtelezhnikov
For full copyright notices consult the individual files in the package.

View file

@ -4,13 +4,12 @@ NULL =
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src util test docs
SUBDIRS = src util test perf docs
EXTRA_DIST = \
autogen.sh \
harfbuzz.doap \
README.md \
README.mingw.md \
README.python.md \
BUILD.md \
CONFIG.md \
@ -18,10 +17,15 @@ EXTRA_DIST = \
TESTING.md \
CMakeLists.txt \
replace-enum-strings.cmake \
meson.build \
meson_options.txt \
subprojects/cairo.wrap \
subprojects/freetype2.wrap \
subprojects/glib.wrap \
subprojects/google-benchmark.wrap \
subprojects/ragel.wrap \
subprojects/packagefiles/ragel/meson.build \
mingw-configure.sh \
mingw-ldd.py \
mingw32.sh \
mingw64.sh \
$(NULL)
MAINTAINERCLEANFILES = \
@ -75,29 +79,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

931
NEWS
View file

@ -1,3 +1,928 @@
Overview of changes leading to 7.2.0
Thursday, April 27, 2023
====================================
- Add Tifinagh to the list of scripts that can natively be either right-to-left
or left-to-right, to improve handling of its glyph positioning.
(Simon Cozens)
- Return also single substitution from hb_ot_layout_lookup_get_glyph_alternates()
(Behdad Esfahbod)
- Fix 4.2.0 regression in applying across syllables in syllabic scripts.
(Behdad Esfahbod)
- Add flag to avoid glyph substitution closure during subsetting, and the
corresponding “--no-layout-closure” option to “hb-subset” command line tool.
(Garret Rieger)
- Support instancing COLRv1 table. (Qunxin Liu)
- Dont drop used user-defined name table entries during subsetting.
(Qunxin Liu)
- Optimize handling of “gvar” table. (Behdad Esfahbod)
- Various subsetter bug fixes and improvements. (Garret Rieger, Qunxin Liu)
- Various documentation improvements. (Behdad Esfahbod, Josef Friedrich)
- New API:
+HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE
+HB_UNICODE_COMBINING_CLASS_CCC132
- Deprecated API:
+HB_UNICODE_COMBINING_CLASS_CCC133
Overview of changes leading to 7.1.0
Friday, March 3, 2023
====================================
- New experimental hb_shape_justify() API that uses font variations to expand
or shrink the text to a given advance. (Behdad Esfahbod)
- Various build and bug fixes. (Behdad Esfahbod, Garret Rieger, Qunxin Liu)
- New API:
+hb_font_set_variation()
Overview of changes leading to 7.0.1
Monday, February 20, 2023
====================================
- Various build and bug fixes.
Overview of changes leading to 7.0.0
Saturday, February 11, 2023
====================================
- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be
also used as a unified API to paint any of the glyph representations
supported by HarfBuzz (B/W outlines, color layers, or color bitmaps).
(Behdad Esfahbod, Matthias Clasen)
- New hb-cairo API for integrating with cairo graphics library. This is provided
as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen)
- Support for instancing “CFF2” table. (Behdad Esfahbod)
- Support font emboldening. (Behdad Esfahbod)
- Support feature ranges with AAT shaping. (Behdad Esfahbod)
- Experimental support to cubic curves in “glyf” table, see
https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md
for spec. (Behdad Esfahbod)
- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
- Various documentation improvements.
(Behdad Esfahbod, Matthias Clasen, Khaled Hosny)
- Significantly reduced memory use during shaping. (Behdad Esfahbod)
- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod)
- New command line utility, hb-info, for querying various font information.
(Behdad Esfahbod, Matthias Clasen)
- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold,
--font-grade, and --named-instance. (Behdad Esfahbod)
- Miscellaneous fixes and improvements.
(Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan,
Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen,
Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich)
- New API:
+HB_FONT_NO_VAR_NAMED_INSTANCE
+HB_PAINT_IMAGE_FORMAT_BGRA
+HB_PAINT_IMAGE_FORMAT_PNG
+HB_PAINT_IMAGE_FORMAT_SVG
+hb_cairo_font_face_create_for_face
+hb_cairo_font_face_create_for_font
+hb_cairo_font_face_get_face
+hb_cairo_font_face_get_font
+hb_cairo_font_face_get_scale_factor
+hb_cairo_font_face_set_font_init_func
+hb_cairo_font_face_set_scale_factor
+hb_cairo_font_init_func_t
+hb_cairo_glyphs_from_buffer
+hb_cairo_scaled_font_get_font
+hb_color_line_get_color_stops
+hb_color_line_get_color_stops_func_t
+hb_color_line_get_extend
+hb_color_line_get_extend_func_t
+hb_color_line_t
+hb_color_stop_t
+hb_draw_funcs_get_empty
+hb_draw_funcs_get_user_data
+hb_draw_funcs_set_user_data
+hb_face_collect_nominal_glyph_mapping
+hb_font_draw_glyph
+hb_font_draw_glyph_func_t
+hb_font_funcs_set_draw_glyph_func
+hb_font_funcs_set_paint_glyph_func
+hb_font_get_synthetic_bold
+hb_font_get_var_named_instance
+hb_font_paint_glyph
+hb_font_paint_glyph_func_t
+hb_font_set_synthetic_bold
+hb_map_keys
+hb_map_next
+hb_map_update
+hb_map_values
+hb_ot_color_glyph_has_paint
+hb_ot_color_has_paint
+hb_ot_layout_script_select_language2
+hb_ot_name_id_predefined_t
+hb_paint_color
+hb_paint_color_func_t
+hb_paint_composite_mode_t
+hb_paint_custom_palette_color
+hb_paint_custom_palette_color_func_t
+hb_paint_extend_t
+hb_paint_funcs_create
+hb_paint_funcs_destroy
+hb_paint_funcs_get_empty
+hb_paint_funcs_get_user_data
+hb_paint_funcs_is_immutable
+hb_paint_funcs_make_immutable
+hb_paint_funcs_reference
+hb_paint_funcs_set_color_func
+hb_paint_funcs_set_custom_palette_color_func
+hb_paint_funcs_set_image_func
+hb_paint_funcs_set_linear_gradient_func
+hb_paint_funcs_set_pop_clip_func
+hb_paint_funcs_set_pop_group_func
+hb_paint_funcs_set_pop_transform_func
+hb_paint_funcs_set_push_clip_glyph_func
+hb_paint_funcs_set_push_clip_rectangle_func
+hb_paint_funcs_set_push_group_func
+hb_paint_funcs_set_push_transform_func
+hb_paint_funcs_set_radial_gradient_func
+hb_paint_funcs_set_sweep_gradient_func
+hb_paint_funcs_set_user_data
+hb_paint_funcs_t
+hb_paint_image
+hb_paint_image_func_t
+hb_paint_linear_gradient
+hb_paint_linear_gradient_func_t
+hb_paint_pop_clip
+hb_paint_pop_clip_func_t
+hb_paint_pop_group
+hb_paint_pop_group_func_t
+hb_paint_pop_transform
+hb_paint_pop_transform_func_t
+hb_paint_push_clip_glyph
+hb_paint_push_clip_glyph_func_t
+hb_paint_push_clip_rectangle
+hb_paint_push_clip_rectangle_func_t
+hb_paint_push_group
+hb_paint_push_group_func_t
+hb_paint_push_transform
+hb_paint_push_transform_func_t
+hb_paint_radial_gradient
+hb_paint_radial_gradient_func_t
+hb_paint_sweep_gradient
+hb_paint_sweep_gradient_func_t
+hb_set_is_inverted
+hb_subset_input_keep_everything
- Deprecated API:
+hb_font_funcs_set_glyph_shape_func
+hb_font_get_glyph_shape_func_t
+hb_font_get_glyph_shape
Overview of changes leading to 6.0.0
Friday, December 16, 2022
====================================
- A new API have been added to pre-process the face and speed up future
subsetting operations on that face. Provides up to a 95% reduction in
subsetting times when the same face is subset more than once.
For more details and benchmarks, see:
https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md
(Garret Rieger, Behdad Esfahbod)
- Shaping have been speedup by skipping entire lookups when the buffer contents
don't intersect with the lookup. Shows up to a 10% speedup in shaping some
fonts. (Behdad Esfahbod)
- A new experimental feature, “Variable Composites” (enabled by passing
-Dexperimental_api=true to meson), is also featured in this release.
This technology enables drastic compression of fonts in the Chinese,
Japanese, Korean, and other writing systems, by reusing the OpenType Font
Variations technology for encoding “smart components” into the font.
The specification for these extensions to the font format can be found in:
https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md
A test variable-font with ~7160 Hangul syllables derived from the
NotoSerifKR-VF font has been built, with existing OpenType technology, as
well as with the new Variable Composites (VarComposites) technology. The
VarComposites font is over 90% smaller than the OpenType version of the font!
Both fonts can be obtained from the “smarties” repository:
https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif
When building HarfBuzz with experimental features enabled, you can test
the “smarties” font with a sample character like this:
$ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700
(Behdad Esfahbod)
- The HarfBuzz subsetter can now drop axes by pinning them to specific values
(also referred to as instancing). There are a couple of restrictions
currently:
- Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet
supported.
- Only supports the case where all axes in a font are pinned.
(Garret Rieger, Qunxin Liu)
- Miscellaneous fixes and improvements.
(Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret
Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg,
Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik)
- New API
+hb_subset_input_pin_axis_location()
+hb_subset_input_pin_axis_to_default()
+hb_subset_preprocess()
Overview of changes leading to 5.3.1
Wednesday, October 19, 2022
====================================
- Subsetter repacker fixes. (Garret Rieger)
- Adjust Grapheme clusters for Katakana voiced sound marks. (Behdad Esfahbod)
- New “hb-subset” option “--preprocess-face”. (Garret Rieger)
Overview of changes leading to 5.3.0
Saturday, October 8, 2022
"Women, Life, Freedom" #MahsaAmini
====================================
- Dont add glyphs from dropped MATH or COLR tables to the subset glyphs.
(Khaled Hosny)
- Map “rlig” to appropriate AAT feature selectors. (Jonathan Kew)
- Update USE data files to latest version. (David Corbett)
- Check “CBDT” extents first before outline tables, to help with fonts that
also include an empty “glyf” table. (Khaled Hosny)
- More work towards variable font instancing in the subsetter. (Qunxin Liu)
- Subsetter repacker improvements. (Garret Rieger)
- New API:
+hb_ot_layout_lookup_get_optical_bound()
+hb_face_builder_sort_tables()
Overview of changes leading to 5.2.0
Saturday, September 17, 2022
====================================
- Fix regressions in hb-ft font functions for FT_Faces with transformation
matrix. (Behdad Esfahbod)
- The experimental hb-repacker API now supports splitting several GPOS subtable
types when needed. (Garret Rieger)
- The HarfBuzz extensions to OpenType font format are now opt-in behind
build-time flags. (Behdad Esfahbod)
- The experimental hb-subset variable fonts instantiation API can now
instantiate more font tables and arbitrary axis locations. (Qunxin Liu)
- Unicode 15 support. (David Corbett)
- Various documentation improvements. (Behdad Esfahbod, Matthias Clasen)
- The hb-view command line tool now detects WezTerm inline images support.
(Wez Furlong)
- Fix FreeType and ICU dependency lookup with meson. (Xavier Claessens)
- New API:
+HB_SCRIPT_KAWI
+HB_SCRIPT_NAG_MUNDARI
Overview of changes leading to 5.1.0
Sunday, July 31, 2022
====================================
- More extensive buffer tracing messages. (Behdad Esfahbod)
- Fix hb-ft regression in bitmap fonts rendering. (Behdad Esfahbod)
- Support extension promotion of lookups in hb-subset-repacker. (Garret Rieger)
- A new HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL for scripts that use elongation
(e.g. Arabic) to signify where it is safe to insert tatweel glyph without
interrupting shaping. (Behdad Esfahbod)
- Add “--safe-to-insert-tatweel” to “hb-shape” tool. (Behdad Esfahbod)
- New API
+HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
+HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL
Overview of changes leading to 5.0.1
Saturday, July 23, 2022
====================================
- Fix version 2 “avar” table with hb-ft. (Behdad Esfahbod)
Overview of changes leading to 5.0.0
Saturday, July 23, 2022
====================================
- Support fonts with more than 65535 glyphs in “GDEF”, “GSUB”, and “GPOS”
tables. This is part of https://github.com/be-fonts/boring-expansion-spec to
extend OpenType in a backward-compatible way.
(Behdad Esfahbod, Garret Rieger)
- Complete support for more than 65535 glyphs in “glyf” table that started in
4.0.0 release. Part of boring-expansion-spec. (Behdad Esfahbod)
- Support version 2 of “avar” table. Part of boring-expansion-spec.
(Behdad Esfahbod)
- Fix mark attachment on multiple substitutions in some cases.
(Behdad Esfahbod)
- Fix application of “calt”, “rclt”, and “ccmp” features to better match
Uniscribe behaviour with some Arabic fonts. (Behdad Esfahbod)
- Improvement to interaction between multiple cursive attachments.
(Behdad Esfahbod)
- Improve multiple mark interactions in Hebrew. (Behdad Esfahbod)
- Implement language-specific forms in AAT shaping. (Behdad Esfahbod)
- Fix variation of “VORG” table. (Behdad Esfahbod)
- Support for specific script tags to be retained in the subsetter, and add
“--layout-scripts” option to “hb-subset” tool. (Garret Rieger)
- Accept space as delimiter for --features/--variations in command line tools.
- Improve subsetting of “COLR” table. (Qunxin Liu)
- Improved fuzzing coverage for ot-math API. (Frédéric Wang)
- Fix “kern” table version 2 (AAT) sanitization on 32-bit systems.
(Behdad Esfahbod)
- Allow negative glyph advances from “graphite2” shaper. (Stephan Bergmann)
- Implement loading (color) bitmap fonts with hb-ft. (Behdad Esfahbod)
- Fix regression in hb-ft when changing font size. (Behdad Esfahbod)
- Fix build on GCC < 7. (Kleis Auke Wolthuizen)
- Dynamically load dwrite.dll on windows if “directwrite” shaper is enabled.
(Luca Bacci)
- Provide a single-file harfbuzz-subset.cc file for easier alternate building
of hb-subset library, similar to harfbuzz.cc. (Khaled Hosny)
- New API
+HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG
+hb_language_matches()
Overview of changes leading to 4.4.1
Wednesday, June 29, 2022
====================================
- Fix test failure with some compilers.
- Fix Telugu and Kannada kerning regression.
Overview of changes leading to 4.4.0
Monday, June 27, 2022
====================================
- Caching of variable fonts shaping, in particular when using HarfBuzzs own
font loading functions (ot). Bringing performance of variable shaping in par
with non-variable fonts shaping. (Behdad Esfahbod)
- Caching of format 2 “Contextual Substitution” and “Chained Contexts
Substitution” lookups. Resulting in up to 20% speedup of lookup-heavy fonts
like Gulzar or Noto Nastaliq Urdu. (Behdad Esfahbod)
- Improved ANSI output from hb-view. (Behdad Esfahbod)
- Support for shaping legacy, pre-OpenType Windows 3.1-era, Arabic fonts that
relied on a fixed PUA encoding. (Khaled Hosny, Behdad Esfahbod)
- Sinhala script is now shaped by the USE shaper instead of “indic” one.
(Behdad Esfahbod, David Corbett)
- Thai shaper improvements. (David Corbett)
- hb-ot-name API supports approximate BCP-47 language matching, for example
asking for “en_US” in a font that has only “en” names will return them.
(Behdad Esfahbod)
- Optimized TrueType glyph shape loading. (Behdad Esfahbod)
- Fix subsetting of HarfBuzz faces created via hb_face_create_for_tables().
(Garret Rieger)
- Add 32 bit var store support to the subsetter. (Garret Rieger)
- New API
+HB_BUFFER_FLAG_DEFINED
+HB_BUFFER_SERIALIZE_FLAG_DEFINED
+hb_font_changed()
+hb_font_get_serial()
+hb_ft_hb_font_changed()
+hb_set_hash()
+hb_map_copy()
+hb_map_hash()
Overview of changes leading to 4.3.0
Friday, May 20, 2022
====================================
- Major speed up in loading and subsetting fonts, especially in
handling CFF table. Subsetting some fonts is now 3 times faster.
(Behdad Esfahbod, Garret Rieger)
- Speed up blending CFF2 table. (Behdad Esfahbod)
- Speed up hb_ot_tags_from_language(). (Behdad Esfahbod, David Corbett)
- Fix USE classification of U+10A38 to fix multiple marks on single Kharoshthi
base. (David Corbett)
- Fix parsing of empty CFF Index. (Behdad Esfahbod)
- Fix subsetting CPAL table with partial palette overlaps. (Garret Rieger)
- New API
+hb_map_is_equal() (Behdad Esfahbod)
Overview of changes leading to 4.2.1
Sunday, April 24, 2022
====================================
- Make sure hb_blob_create_from_file_or_fail() always returns nullptr in case
of failure and not empty blob sometimes. (Khaled Hosny)
- Add --passthrough-tables option to hb-subset. (Cosimo Lupo)
- Reinstate a pause after basic features in Khmer shaper, fixing a regression
introduced in previous release. (Behdad Esfahbod)
- Better handling of Regional_Indicator when shaped with RTL-native scripts,
reverting earlier fix that caused regressions in AAT shaping. (Behdad Esfahbod)
Overview of changes leading to 4.2.0
Wednesday, March 30, 2022
====================================
- Source code reorganization, splitting large hb-ot-layout files into smaller,
per-subtable ones under OT/Layout/*. Code for more tables will follow suit in
later releases. (Garret Rieger, Behdad Esfahbod)
- Revert Indic shaper change in previous release that broke some fonts and
instead make per-syllable restriction of “GSUB” application limited to
script-specific Indic features, while applying them and discretionary
features in one go. (Behdad Esfahbod)
- Fix decoding of private in gvar table. (Behdad Esfahbod)
- Fix handling of contextual lookups that delete too many glyphs. (Behdad Esfahbod)
- Make “morx” deleted glyphs dont block “GPOS” application. (Behdad Esfahbod)
- Various build fixes. (Chun-wei Fan, Khaled Hosny)
- New API
+hb_set_next_many() (Andrew John)
Overview of changes leading to 4.1.0
Wednesday, March 23, 2022
====================================
- Various OSS-Fuzz fixes. (Behdad Esfahbod)
- Make fallback vertical-origin match FreeTypes. (Behdad Esfahbod)
- Treat visible viramas like dependent vowels in USE shaper. (David Corbett)
- Apply presentation forms features and discretionary features in one go in
Indic shaper, which seems to match Uniscribe and CoreText behaviour.
(Behdad Esfahbod, David Corbett)
- Various bug fixes.
- New API
+hb_set_add_sorted_array() (Andrew John)
Overview of changes leading to 4.0.1
Friday, March 11, 2022
====================================
- Update OpenType to AAT mappings for “hist” and “vrtr” features.
(Florian Pircher)
- Update IANA Language Subtag Registry to 2022-03-02. (David Corbett)
- Update USE shaper to allow any non-numeric tail in a symbol cluster, and
remove obsolete data overrides. (David Corbett)
- Fix handling of baseline variations to return correctly scaled values.
(Matthias Clasen)
- A new experimental hb_subset_repack_or_fail() to repack an array of objects,
eliminating offset overflows. The API is not available unless HarfBuzz is
built with experimental APIs enabled. (Qunxin Liu)
- New experimental API
+hb_link_t
+hb_object_t
+hb_subset_repack_or_fail()
Overview of changes leading to 4.0.0
Tuesday, March 1, 2022
====================================
- New public API to create subset plan and gather information on things like
glyph mappings in the final subset. The plan can then be passed on to perform
the subsetting operation. (Garret Rieger)
- Draw API for extracting glyph shapes have been extended and finalized and is
no longer an experimental API. The draw API supports glyf, CFF and CFF2
glyph outlines tables, and applies variation settings set on the font as well
as synthetic slant. The new public API is not backward compatible with the
previous, non-public, experimental API. (Behdad Esfahbod)
- The hb-view tool will use HarfBuzz draw API to render the glyphs instead of
cairo-ft when compiled with Cairo 1.17.5 or newer, setting HB_DRAW
environment variable to 1 or 0 will force using or not use the draw API,
respectively. (Behdad Esfahbod)
- The hb-shape and hb-view tools now default to using HarfBuzzs own font
loading functions (ot) instead of FreeType ones (ft). They also have a new
option, --font-slant, to apply synthetic slant to the font. (Behdad Esfahbod)
- HarfBuzz now supports more than 65535 (the OpenType limit) glyph shapes and
metrics. See https://github.com/be-fonts/boring-expansion-spec/issues/6 and
https://github.com/be-fonts/boring-expansion-spec/issues/7 for details.
(Behdad Esfahbod)
- New API to get the dominant horizontal baseline tag for a given script.
(Behdad Esfahbod)
- New API to get the baseline positions from the font, and synthesize missing
ones. As well as new API to get font metrics and synthesize missing ones.
(Matthias Clasen)
- Improvements to finding dependencies on Windows when building with Visual
Studio. (Chun-wei Fan)
- New buffer flag, HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT, that must be set
during shaping for HB_GLYPH_FLAG_UNSAFE_TO_CONCAT flag to be reliably
produced. This is to limit the performance hit of producing this flag to when
it is actually needed. (Behdad Esfahbod)
- Documentation improvements. (Matthias Clasen)
- New API
- General:
+HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT
+hb_var_num_t
- Draw:
+hb_draw_funcs_t
+hb_draw_funcs_create()
+hb_draw_funcs_reference()
+hb_draw_funcs_destroy()
+hb_draw_funcs_is_immutable()
+hb_draw_funcs_make_immutable()
+hb_draw_move_to_func_t
+hb_draw_funcs_set_move_to_func()
+hb_draw_line_to_func_t
+hb_draw_funcs_set_line_to_func()
+hb_draw_quadratic_to_func_t
+hb_draw_funcs_set_quadratic_to_func()
+hb_draw_cubic_to_func_t
+hb_draw_funcs_set_cubic_to_func()
+hb_draw_close_path_func_t
+hb_draw_funcs_set_close_path_func()
+hb_draw_state_t
+HB_DRAW_STATE_DEFAULT
+hb_draw_move_to()
+hb_draw_line_to()
+hb_draw_quadratic_to()
+hb_draw_cubic_to()
+hb_draw_close_path()
+hb_font_get_glyph_shape_func_t
+hb_font_funcs_set_glyph_shape_func()
+hb_font_get_glyph_shape()
- OpenType layout
+HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL
+HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL
+hb_ot_layout_get_horizontal_baseline_tag_for_script()
+hb_ot_layout_get_baseline_with_fallback()
- Metrics:
+hb_ot_metrics_get_position_with_fallback()
- Subset:
+hb_subset_plan_t
+hb_subset_plan_create_or_fail()
+hb_subset_plan_reference()
+hb_subset_plan_destroy()
+hb_subset_plan_set_user_data()
+hb_subset_plan_get_user_data()
+hb_subset_plan_execute_or_fail()
+hb_subset_plan_unicode_to_old_glyph_mapping()
+hb_subset_plan_new_to_old_glyph_mapping()
+hb_subset_plan_old_to_new_glyph_mapping()
Overview of changes leading to 3.4.0
Sunday, February 13, 2022
====================================
- Perform sanity checks on shaping results is now part of “harfbuzz” library
and can be enabled by setting the buffer flag HB_BUFFER_FLAG_VERIFY.
(Behdad Esfahbod)
- Arabic Mark Transient Reordering Algorithm have been updated to revision 6.
(Khaled Hosny)
- ISO 15924 code for mathematical notation, Zmth, now maps to the OpenType
math tag. (Alexis King)
- It is now possible to get at once all math kerning values for a given glyph
at a given corner. (Alexis King)
- Fix locale_t portability issues on systems the typedefs it to a void
pointer. (Behdad Esfahbod)
- New API:
+HB_BUFFER_FLAG_VERIFY
+HB_OT_TAG_MATH_SCRIPT
+HB_SCRIPT_MATH
+hb_ot_math_kern_entry_t
+hb_ot_math_get_glyph_kernings()
- Deprecated API
+HB_OT_MATH_SCRIPT
Overview of changes leading to 3.3.2
Sunday, February 6, 2022
====================================
- Revert splitting of pair positioning values introduced in 3.3.0 as it proved
problematic. (Behdad Esfahbod)
Overview of changes leading to 3.3.1
Monday, January 31, 2022
====================================
- Fix heap-use-after-free in harfbuzz-subset introduced in previous release.
(Garret Rieger)
Overview of changes leading to 3.3.0
Monday, January 31, 2022
====================================
- Improved documentation. (Matthias Clasen)
- Internal code cleanup, using C++ standard library more. (Behdad Esfahbod)
- The low 16-bits of face index will be used by hb_face_create() to select a
face inside a font collection file format, while the high 16-bits will be
used by hb_font_create() to load the named instance. (Behdad Esfahbod)
- Glyph positions and other font metrics now apply synthetic slant set by
hb_font_set_synthetic_slant(), for improved positioning for synthetically
slanted fonts. (Behdad Esfahbod)
- Fixed unintentional locale dependency in hb_variation_to_string() for decimal
point representation. (Matthias Clasen)
- When applying pair positioning (kerning) the positioning value is split
between the two sides of the pair for improved cursor positioning between
such pairs. (Behdad Esfahbod)
- Introduced new HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, to be used in conjunction
with HB_GLYPH_FLAG_UNSAFE_TO_BREAK for optimizing re-shaping during line
breaking. Check the documentation for further details. (Behdad Esfahbod)
- Improved handling of macrolanguages when mapping BCP 47 codes to OpenType
tags. (David Corbett)
- New API:
+HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
+hb_segment_properties_overlay()
+hb_buffer_create_similar()
+hb_font_set_synthetic_slant()
+hb_font_get_synthetic_slant()
+hb_font_get_var_coords_design()
Overview of changes leading to 3.2.0
Friday, November 26, 2021
====================================
“harfbuzz” library improvements:
- Fixed shaping of Apple Color Emoji flags in right-to-left context. (Behdad Esfahbod)
- Fixed positioning of CFF fonts in HB_TINY profile. (Behdad Esfahbod)
- OpenType 1.9 language tags update. (David Corbett)
- Add HB_NO_VERTICAL config option.
- Add HB_CONFIG_OVERRIDE_H for easier configuration. (Behdad Esfahbod)
“harfbuzz-subset” library improvements:
- Improved packing of cmap, loca, and Ligature tables. (Garret Rieger)
- Significantly improved overflow-resolution strategy in the repacker. (Garret Rieger)
Overview of changes leading to 3.1.2
Friday, November 26, 2021
====================================
- hb-shape / hb-view: revert treating text on the commandline as single
paragraph (was introduced in 3.0.0); add new --single-par to do that.
(Behdad Esfahbod)
- Subsetter bug fixes. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
Overview of changes leading to 3.1.1
Wednesday, November 8, 2021
====================================
- Work around GCC cast-align error/warning on some platforms. (Behdad Esfahbod)
- Documentation improvements. (Matthias Clasen)
Overview of changes leading to 3.1.0
Wednesday, November 3, 2021
====================================
- Better offset-overflow handling in the subsetter library. (Garret Rieger)
- Improved Unicode 14 properties in the USE shaper, and various other USE
shaper fixes. (David Corbett)
- MATH and COLR v1 tables subsetting support, and various other subsetter fixes.
(Qunxin Liu)
- Support for Pwo Karen / Ason Chin medial la. (Simon Cozens)
- Apply GPOS positioning when substituting with morx table, if kerx is missing.
(Behdad Esfahbod)
- Apply calt and clig features across syllable boundaries in Indic shaper.
(Behdad Esfahbod)
- meson option for enabling Graphite 2 has been renamed to graphite2.
- Build and documentation fixes.
- New API:
+hb_buffer_set_not_found_glyph()
+hb_buffer_get_not_found_glyph()
Overview of changes leading to 3.0.0
Friday, September 17, 2021
====================================
- Unicode 14.0 support (David Corbett).
- The hb-subset API and the harfbuzz-subset library's ABI are now declared
stable. The harfbuzz-subset library would not have been possible without the
work of Garret Rieger and Qunxin Liu from Google Fonts, and the earlier work
of Michiharu Ariza from Adobe.
- The hb-style API is now stable and no longer experimental.
- New API:
+hb_style_tag_t
+hb_style_get_value()
+hb_subset_input_t
+hb_subset_flags_t
+hb_subset_sets_t
+hb_subset_input_create_or_fail()
+hb_subset_input_reference()
+hb_subset_input_destroy()
+hb_subset_input_set_user_data()
+hb_subset_input_get_user_data()
+hb_subset_input_unicode_set()
+hb_subset_input_glyph_set()
+hb_subset_input_set()
+hb_subset_input_get_flags()
+hb_subset_input_set_flags()
+hb_subset_or_fail()
- Removed old unstable harfbuzz-subset API:
-hb_subset_input_nameid_set()
-hb_subset_input_namelangid_set()
-hb_subset_input_layout_features_set()
-hb_subset_input_no_subset_tables_set()
-hb_subset_input_drop_tables_set()
-hb_subset_input_set_drop_hints()
-hb_subset_input_get_drop_hints()
-hb_subset_input_set_desubroutinize()
-hb_subset_input_get_desubroutinize()
-hb_subset_input_set_retain_gids()
-hb_subset_input_get_retain_gids()
-hb_subset_input_set_name_legacy()
-hb_subset_input_get_name_legacy()
-hb_subset_input_set_overlaps_flag()
-hb_subset_input_get_overlaps_flag()
-hb_subset_input_set_notdef_outline()
-hb_subset_input_get_notdef_outline()
-hb_subset_input_set_no_prune_unicode_ranges()
-hb_subset_input_get_no_prune_unicode_ranges()
-hb_subset()
Overview of changes leading to 2.9.1
Tuesday, September 7, 2021
====================================
- Final subset API is in place and if no issues are discovered, it will be the
stable subset API of HarfBuzz 3.0.0. Old API is kept to ease transition, but
will be removed in 3.0.0.
- Various fuzzer-found bug fixes.
- hb_buffer_append() now handles the pre- and post-context which previously
were left unchanged in the destination buffer.
- hb-view / hb-shape now accept following new arguments:
o --unicodes-before/after: takes a list of hex numbers that represent Unicode
codepoints.
- Undeprecated API:
hb_set_invert()
Overview of changes leading to 2.9.0
Wednesday, August 18, 2021
History Repeats Itself (Afghanistan)
====================================
- Subsetter API is being stabilized, with the first stable API to happen in
3.0.0 release (https://github.com/harfbuzz/harfbuzz/issues/3078).
- Support multiple variation axes with same tag, aka HOI.
- The “coretext” testing shaper now passes font variations to CoreText.
- hb-shape/hb-view does not break line at new lines unless text is read from
file.
- hb-view and hb-subset has a --batch now, similar to hb-shape.
- The --batch mode now uses ; as argument separator instead of : used previously.
- The --batch in hb-shape does not expect 0th argument anymore. That is, the
lines read are interpreted as argv[1:], instead of argv[0:].
- The --batch option has been undocumented. We are ready to document it; send
feedback if you find it useful.
- hb-subset got arguments revamps. Added much-requested --gids-file, --glyphs,
--glyphs-file, --unicodes-file, supporting ranges in --unicodes.
- Various bug fixes.
Overview of changes leading to 2.8.2
Tuesday, July 8, 2021
====================================
- Shaping LTR digits for RTL scripts now makes the native direction of the
digits LTR, applying shaping and positioning rules on the same glyph order as
Uniscribe. (Jonathan Kew, Khaled Hosny).
- Subsetting COLR v1 and CPAL tables is now supported. (Garret Rieger, Qunxin Liu)
- Various fixes and improvements to the subsetter. (Garret Rieger, Qunxin Liu, Behdad)
- When applying morx table, mark glyph widths should not be zeroed. (Jonathan Kew)
- GPOS is preferred over kerx, if GSUB was applied. (Behdad)
- Regional_Indicator pairs are grouped together when clustering. (Behdad)
- New API:
+hb_blob_create_or_fail()
+hb_blob_create_from_file_or_fail()
+hb_set_copy()
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.
- Dont 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
====================================
@ -90,7 +1015,7 @@ Friday, May 24, 2019
code-base changes. We now require C++11. Support for gcc 4.8 and earlier has been
dropped.
- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
- New Unicode Character Databse implementation that is half the size of previously-used
- New Unicode Character Database implementation that is half the size of previously-used
UCDN.
- Subsetter improvements.
- Improved documentation, thanks to Nathan Willis.
@ -938,7 +1863,7 @@ Thursday, February 25, 2016
due to bug in glyph class of ASCII double-quote character. This should
address "regression" introduced in 1.2.0 when we switched mark zeroing
in most shapers from BY_UNICODE_LATE to BY_GDEF_LATE.
This fourth release in a week should finally stablize things...
This fourth release in a week should finally stabilize things...
- hb-ot-font's get_glyph() implementation saw some optimizations. Though,
might be really hard to measure in real-world situations.
@ -1986,7 +2911,7 @@ o Changed API:
- hb_buffer_create() takes zero arguments now.
Use hb_buffer_pre_allocate() to pre-allocate.
- hb_buffer_add_utf*() now accept -1 for length parameteres,
- hb_buffer_add_utf*() now accept -1 for length parameters,
meaning "nul-terminated".
- hb_direction_t enum values changed.

View file

@ -1,15 +1,17 @@
[![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)
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
[![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/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![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)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;utm_campaign=Badge_Grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/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.
# HarfBuzz
HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt,
XeTeX, and other places.
For bug reports, mailing list, and other information please visit:
@ -17,18 +19,81 @@ For bug reports, mailing list, and other information please visit:
For license information, see [COPYING](COPYING).
## Documentation
For user manual as well as API documentation, check: https://harfbuzz.github.io
## Download
For tarball releases of HarfBuzz, look [here][3]. At the same place you
will also find Win32/Win64 binary bundles that include libharfbuzz DLL,
hb-view.exe, hb-shape.exe, and all dependencies.
The canonical source tree is available on [github][4].
The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
headers are more likely to go through minor modifications, but again, we do our
best to never change API in an incompatible way. We will never break the ABI.
If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
HarfBuzz][5].
## Development
For build information, see [BUILD.md](BUILD.md).
For custom configurations, see [CONFIG.md](CONFIG.md).
For test execution, see [TESTING.md](TESTING.md).
For testing and profiling, see [TESTING.md](TESTING.md).
Documentation: https://harfbuzz.github.io
To get a better idea of where HarfBuzz stands in the text rendering stack you
may want to read [State of Text Rendering][6], though, that document is many
years old. Here are a few presentation slides about HarfBuzz at the
Internationalization and Unicode Conference over the years:
* November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
* October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
* October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
Both development and user support discussion around HarfBuzz happens on the
[github][4].
To report bugs or submit patches please use [github][4] issues and
pull-requests.
For a comparison of old vs new HarfBuzz memory consumption see [this][10].
<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
## Name
HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
transliterated using the Latin script. It sports a second meaning, but that
aint translatable.
> Background: Originally there was this font format called TrueType. People and
> companies started calling their type engines all things ending in Type:
> FreeType, CoolType, ClearType, etc. And then came OpenType, which is the
> successor of TrueType. So, for my OpenType implementation, I decided to stick
> with the concept but use the Persian translation. Which is fitting given that
> Persian is written in the Arabic script, and OpenType is an extension of
> TrueType that adds support for complex script rendering, and HarfBuzz is an
> implementation of OpenType complex text shaping.
<details>
<summary>Packaging status of HarfBuzz</summary
<summary>Packaging status of HarfBuzz</summary>
[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
</details>
[1]: https://docs.microsoft.com/en-us/typography/opentype/spec/
[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
[3]: https://github.com/harfbuzz/harfbuzz/releases
[4]: https://github.com/harfbuzz/harfbuzz
[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
[6]: http://behdad.org/text/
[7]: https://goo.gl/FSIQuC
[8]: https://goo.gl/2wSRu
[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
[10]: https://goo.gl/woyty

View file

@ -4,28 +4,41 @@ 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,
c) Build as usual:
- make
8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
d) Configure your wine to find system mingw libraries. See:
https://fedoraproject.org/wiki/MinGW/Configure_wine
Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)`
but if you like to shape with the Microsoft Uniscribe:
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 +48,11 @@ 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)
When you have built that, you can test HarfBuzz's native shaper against Uniscribe
following these instructions:
[^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.
https://github.com/harfbuzz/harfbuzz/issues/3671

View file

@ -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.

View file

@ -1,72 +1,37 @@
HarfBuzz release walk-through checklist:
# HarfBuzz release walk-through checklist:
1. Open gitk and review changes since last release.
- [ ] Open gitk and review changes since last release.
* `git diff $(git describe | sed 's/-.*//').. src/*.h` prints all public API
changes.
- [ ] Print all public API changes:
`git diff $(git describe | sed 's/-.*//').. src/*.h`
Document them in NEWS. All API and API semantic changes should be clearly
marked as API additions, API changes, or API deletions. Document
deprecations. Ensure all new API / deprecations are in listed correctly in
docs/harfbuzz-sections.txt. If release added new API, add entry for new
API index at the end of docs/harfbuzz-docs.xml.
- [ ] Document them in NEWS.
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
If there's a backward-incompatible API change (including deletions for API
used anywhere), that's a release blocker. Do NOT release.
- [ ] Document deprecations.
Ensure all new API / deprecations are in listed correctly in docs/harfbuzz-sections.txt.
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
2. Based on severity of changes, decide whether it's a minor or micro release
number bump,
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
Do NOT release.
3. Search for REPLACEME on the repository and replace it with the chosen version
for the release.
- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
4. Make sure you have correct date and new version at the top of NEWS file,
- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
5. Bump version in configure.ac line 3,
- [ ] Make sure you have correct date and new version at the top of NEWS file.
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.
- [ ] Bump version in line 3 of meson.build and configure.ac.
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"
- [ ] 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).
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.
- [ ] 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, e. g. "1.4.7"
9. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your
GPG password again.
- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest committed changes.
If doesn't pass, something fishy is going on, reset the repo and start over.
10. Build win32 bundle.
- [ ] Tag the release and sign it: e.g. `git tag -s 1.4.7 -m 1.4.7`.
Enter your GPG password.
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.
- [ ] Push the commit and tag out: `git push --follow-tags`.

20
SECURITY.md Normal file
View file

@ -0,0 +1,20 @@
# Security Policy
If you have discovered a security vulnerability in this project, please report it
privately. **Do not disclose it as a public issue.** This gives me time to work with you
to fix the issue before public exposure, reducing the chance that the exploit will be
used before a patch is released.
You may submit the report in the following ways:
- send an email to behdad@behdad.org and harfbuzz-admin@googlegroups.com; and/or
- send me a [private vulnerability report](https://github.com/harfbuzz/harfbuzz/security/advisories/new)
Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
This project is mostly maintained by two developers, working on a reasonable effort
basis. As such, we ask that you give us 90 days to work on a fix before public
disclosure.

View file

@ -1,86 +1,47 @@
## Build & Run
## Build and Test
```shell
meson build
ninja -Cbuild
meson test -Cbuild
```
### Debug with GDB
```shell
meson test -Cbuild --gdb testname
```
## Build and Run
Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
Values defined in `hb-debug.hh`.
```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)
# confirm you didn't break anything else
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
&& make -j4 check)
# often catches files you didn't add, e.g. test fonts to EXTRA_DIST
make distcheck
CPPFLAGS='-DHB_DEBUG_SUBSET=100' meson setup build --reconfigure
meson test -C build
```
### Run tests with asan
**NOTE**: this sometimes yields harder to read results than the full fuzzer
```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
```
### Debug with GDB
```
cd ./util
../libtool --mode=execute gdb --args ./hb-subset ...
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 build
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
# Do this periodically
sudo python infra/helper.py build_image harfbuzz
# 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
```
FOr fuzzing, see `test/fuzzing/README.md`.
## Profiling
```
make clean
./configure CXXFLAGS="-fno-omit-frame-pointer -g"
make
perf record -o <perf output file> -g <command to run>
perf report -i<perf output file>
```
For profiling, see `perf/README.md`.

28
TODO
View file

@ -1,28 +0,0 @@
API issues:
===========
- API to accept a list of languages?
- Remove hb_ot_shape_glyphs_closure()?
API additions
=============
- Language to/from script.
- Add hb-cairo glue
- Add sanitize API.
- Add query / enumeration API for aalt-like features?
- Add segmentation API
- Add hb-fribidi glue?
hb-view / hb-shape enhancements:
===============================
- Add --width, --height, --auto-size, --ink-box, --align, etc?

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[2.6.4],
[7.2.0],
[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])
@ -45,17 +45,8 @@ 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
m4_eval(60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro))
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 roundf)
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale sincosf)
AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h)
# Compiler flags
AC_CANONICAL_HOST
@ -203,6 +194,10 @@ AC_ARG_WITH(cairo,
have_cairo=false
if test "x$with_cairo" = "xyes" -o "x$with_cairo" = "xauto"; then
PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, :)
save_libs=$LIBS
LIBS="$LIBS $CAIRO_LIBS"
AC_CHECK_FUNCS(cairo_user_font_face_set_render_color_glyph_func)
LIBS=$save_libs
fi
if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then
AC_MSG_ERROR([cairo support requested but not found])
@ -223,21 +218,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 +243,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])
@ -332,7 +308,7 @@ if $have_freetype; then
AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
save_libs=$LIBS
LIBS="$LIBS $FREETYPE_LIBS"
AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
LIBS=$save_libs
fi
AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@ -390,17 +366,13 @@ AC_ARG_WITH(directwrite,
have_directwrite=false
AC_LANG_PUSH([C++])
if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
AC_CHECK_HEADERS(dwrite.h, have_directwrite=true)
AC_CHECK_HEADERS(dwrite_1.h, have_directwrite=true)
fi
AC_LANG_POP([C++])
if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
AC_MSG_ERROR([directwrite support requested but not found])
fi
if $have_directwrite; then
DIRECTWRITE_CXXFLAGS=
DIRECTWRITE_LIBS=
AC_SUBST(DIRECTWRITE_CXXFLAGS)
AC_SUBST(DIRECTWRITE_LIBS)
AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
fi
AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
@ -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 <atomic.h>
/* This requires Solaris Studio 12.2 or newer: */
#include <mbarrier.h>
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
@ -492,13 +425,16 @@ util/Makefile
test/Makefile
test/api/Makefile
test/fuzzing/Makefile
test/shaping/Makefile
test/shaping/data/Makefile
test/shaping/data/aots/Makefile
test/shaping/data/in-house/Makefile
test/shaping/data/text-rendering-tests/Makefile
test/shape/Makefile
test/shape/data/Makefile
test/shape/data/aots/Makefile
test/shape/data/in-house/Makefile
test/shape/data/text-rendering-tests/Makefile
test/subset/Makefile
test/subset/data/Makefile
test/subset/data/repack_tests/Makefile
test/threads/Makefile
perf/Makefile
docs/Makefile
docs/version.xml
])
@ -510,6 +446,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 +468,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):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -1,277 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="682.66669"
height="682.66669"
viewBox="0 0 682.66669 682.66669"
sodipodi:docname="harfbuzz2.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
inkscape:export-filename="harfbuzz2.png"
inkscape:export-xdpi="72"
inkscape:export-ydpi="72">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6">
<g
id="g50">
<symbol
id="glyph0-0"
overflow="visible"
style="overflow:visible">
<path
id="path26"
d="M 32,0 V -192 H 224 V 0 Z M 48,-16 H 208 V -176 H 48 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-1"
overflow="visible"
style="overflow:visible">
<path
id="path29"
d="m 52.5,-64.875 c -0.08594,2.25 -0.9375,6.335938 -2.5625,12.25 -1.625,5.917969 -3.75,12.375 -6.375,19.375 -2.625,7 -4.9375,12.292969 -6.9375,15.875 -2,3.585938 -4.1875,6.3125 -6.5625,8.1875 -2.375,1.875 -6.210938,3.585938 -11.5,5.125 -5.292969,1.542969 -9.542969,2.585938 -12.75,3.125 -3.210938,0.542969 -5.230469,0.8125 -6.0625,0.8125 -0.832031,-0.082031 -1.332031,-0.414062 -1.5,-1 -0.164062,-0.582031 0.085938,-1.332031 0.75,-2.25 0.9179688,-1.414062 3.226562,-3.269531 6.9375,-5.5625 3.707031,-2.289062 8.019531,-5.164062 12.9375,-8.625 4.914062,-3.457031 8.414062,-6.476562 10.5,-9.0625 2.082031,-2.582031 4.4375,-6.457031 7.0625,-11.625 2.625,-5.164062 5,-10.375 7.125,-15.625 2.125,-5.25 3.644531,-8.832031 4.5625,-10.75 0.914062,-1.914062 1.914062,-2.832031 3,-2.75 0.914062,0.167969 1.375,1 1.375,2.5 z M 41.75,-117.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-2"
overflow="visible"
style="overflow:visible">
<path
id="path32"
d="m 19.75,-47.125 c -0.167969,3.167969 -0.5,6.023438 -1,8.5625 -0.5,2.542969 -1.167969,4.710938 -2,6.5 -0.835938,1.792969 -1.898438,3.125 -3.1875,4 -1.292969,0.875 -2.855469,1.1875 -4.6875,0.9375 0.082031,-6.5 0.769531,-15.5625 2.0625,-27.1875 1.289062,-11.625 3.226562,-24.476562 5.8125,-38.5625 1.332031,-4.082031 4.039062,-11.28906 8.125,-21.625 0.414062,-1 0.851562,-1.41406 1.3125,-1.25 0.457031,0.16797 0.6875,0.58594 0.6875,1.25 -0.25,5.08594 -1.292969,14.792969 -3.125,29.125 -1.835938,14.335938 -2.960938,24.167969 -3.375,29.5 -0.417969,5.335938 -0.625,8.25 -0.625,8.75 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-3"
overflow="visible"
style="overflow:visible">
<path
id="path35"
d="m -10.875,-27.25 c 1.667969,-7.164062 3.5625,-12.457031 5.6875,-15.875 2.125,-3.414062 3.855469,-5.289062 5.1875,-5.625 v 5.5 c 0,7 1.875,11.875 5.625,14.625 2.25,1.5 4.5,2 6.75,1.5 2.25,-0.5 3.976562,-1.664062 5.1875,-3.5 1.207031,-1.832031 2.226562,-3.976562 3.0625,-6.4375 0.832031,-2.457031 1.625,-3.6875 2.375,-3.6875 0.914062,0 1.289062,0.875 1.125,2.625 -0.08594,3 -1.023438,7.875 -2.8125,14.625 C 19.519531,-16.75 17.082031,-11.207031 14,-6.875 10.914062,-2.539062 7.164062,-0.25 2.75,0 c -4.5,-0.164062 -8,-2.707031 -10.5,-7.625 -2.25,-4.832031 -3.289062,-11.082031 -3.125,-18.75 z m 6.625,111.5 c 0,-1.835938 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.644531 8,4.1875 3.5,3.539062 5.375,6.3125 5.625,8.3125 0,2.664062 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 C 8.875,94.375 7.144531,93.269531 4.1875,91.3125 1.226562,89.351562 -0.957031,87.875 -2.375,86.875 -3.625,86.039062 -4.25,85.164062 -4.25,84.25 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-4"
overflow="visible"
style="overflow:visible">
<path
id="path38"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-5"
overflow="visible"
style="overflow:visible">
<path
id="path41"
d="m 118.5,-33 c 15.33203,-3.914062 27.375,-8.289062 36.125,-13.125 7.5,-4.082031 11.25,-7.5 11.25,-10.25 0,-0.832031 -0.5625,-1.894531 -1.6875,-3.1875 -1.125,-1.289062 -1.9375,-1.9375 -2.4375,-1.9375 -0.83594,0 -2.02344,0.148438 -3.5625,0.4375 -1.54297,0.292969 -2.64844,0.4375 -3.3125,0.4375 -2.91797,0 -4.98047,-0.769531 -6.1875,-2.3125 -1.21094,-1.539062 -1.8125,-3.601562 -1.8125,-6.1875 0,-1.5 2.16406,-6.539062 6.5,-15.125 1.66406,-3.414062 3.0625,-5.8125 4.1875,-7.1875 1.125,-1.375 2.76953,-2.0625 4.9375,-2.0625 3.58203,0 6.91406,1.9375 10,5.8125 3.08203,3.875 4.625,8.855469 4.625,14.9375 0,6 -0.8125,11.4375 -2.4375,16.3125 -1.625,4.875 -4.14844,9.605469 -7.5625,14.1875 -3.41797,4.585938 -7.83594,9.042969 -13.25,13.375 -8.08594,6.085938 -17.625,11.230469 -28.625,15.4375 -11,4.210938 -23.83594,7.5 -38.5,9.875 C 72.082031,-1.1875 58.082031,0 44.75,0 37.082031,0 30.082031,-0.375 23.75,-1.125 17.414062,-1.875 12.582031,-3.289062 9.25,-5.375 3.082031,-8.789062 0.25,-14.5 0.75,-22.5 c 0.332031,-4.082031 0.832031,-8.4375 1.5,-13.0625 0.664062,-4.625 1.351562,-8.3125 2.0625,-11.0625 0.707031,-2.75 1.5625,-4.125 2.5625,-4.125 0.832031,0 1.332031,1.75 1.5,5.25 0.164062,3.5 0.6875,6.0625 1.5625,7.6875 0.875,1.625 2.207031,3 4,4.125 1.789062,1.125 4.6875,2.210938 8.6875,3.25 4,1.042969 8.6875,1.855469 14.0625,2.4375 5.375,0.585938 12.519531,0.875 21.4375,0.875 12.414062,0 23.019531,-0.4375 31.8125,-1.3125 C 98.726562,-29.3125 108.25,-30.832031 118.5,-33 Z m -38.75,-86.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.46094,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-6"
overflow="visible"
style="overflow:visible">
<path
id="path44"
d="m 78,-56.875 c -1.335938,2.25 -2.25,3.875 -2.75,4.875 -1.417969,2.335938 -2.875,4.210938 -4.375,5.625 -1.75,1.75 -4.042969,3.292969 -6.875,4.625 -6.085938,2.917969 -10.460938,5.75 -13.125,8.5 -1.75,1.75 -3.792969,4.960938 -6.125,9.625 -4.25,8.585938 -8.417969,14.292969 -12.5,17.125 -4.085938,2.917969 -11.417969,5 -22,6.25 C 9.414062,-0.0820312 8.414062,0 7.25,0 H 4.375 c -1.5,0 -2.25,-0.164062 -2.25,-0.5 0,-1.914062 2.539062,-4.5 7.625,-7.75 4,-2.414062 7,-4.207031 9,-5.375 6,-3.414062 10.414062,-6.125 13.25,-8.125 4,-2.914062 6.625,-5.75 7.875,-8.5 4.164062,-8.5 7.625,-14.414062 10.375,-17.75 3.082031,-3.664062 6.625,-6.5 10.625,-8.5 C 67.289062,-60.082031 71,-62.207031 72,-62.875 l 10,2.375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-7"
overflow="visible"
style="overflow:visible">
<path
id="path47"
d="m 13,-17.625 c -1,1.75 -2.0625,3.480469 -3.1875,5.1875 C 8.6875,-10.726562 7.539062,-9.082031 6.375,-7.5 5.207031,-5.914062 4.0625,-4.476562 2.9375,-3.1875 1.8125,-1.894531 0.832031,-0.832031 0,0 c -0.5,-2.582031 -0.832031,-5.125 -1,-7.625 -0.164062,-2.5 0.167969,-5.039062 1,-7.625 1.25,-0.75 2.207031,-1.414062 2.875,-2 1.664062,-1.5 5.375,-6.582031 11.125,-15.25 -0.667969,-0.664062 -2.585938,-1.601562 -5.75,-2.8125 -3.167969,-1.207031 -6.167969,-1.894531 -9,-2.0625 -2.582031,-0.164062 -4.726562,0.3125 -6.4375,1.4375 -1.707031,1.125 -3.25,2.710938 -4.625,4.75 -1.375,2.042969 -2.5625,2.980469 -3.5625,2.8125 -0.332031,-0.164062 -0.375,-0.851562 -0.125,-2.0625 0.25,-1.207031 0.625,-2.394531 1.125,-3.5625 2.085938,-4.832031 4.480469,-8.4375 7.1875,-10.8125 2.710938,-2.375 5.9375,-3.5625 9.6875,-3.5625 2.75,0 6.164062,0.667969 10.25,2 2.582031,0.917969 4.789062,1.375 6.625,1.375 3.832031,0 7.625,-1.375 11.375,-4.125 0.832031,0 1.125,0.542969 0.875,1.625 -0.25,1.085938 -0.605469,2.355469 -1.0625,3.8125 -0.460938,1.460938 -0.773438,2.4375 -0.9375,2.9375 -0.835938,2.585938 -1.5,4.085938 -2,4.5 -0.5,0.417969 -1.960938,1.5 -4.375,3.25 -1.335938,1 -2.480469,2.148438 -3.4375,3.4375 -0.960938,1.292969 -1.9375,2.835938 -2.9375,4.625 -1,1.792969 -2.292969,4.230469 -3.875,7.3125 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
</g>
<g
id="g184">
<symbol
id="glyph0-0-3"
overflow="visible"
style="overflow:visible">
<path
id="path163"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-1-6"
overflow="visible"
style="overflow:visible">
<path
id="path166"
d="m 79.625,-103.25 c -3.585938,22 -6.8125,38.417969 -9.6875,49.25 -2.875,10.835938 -5.480469,19.105469 -7.8125,24.8125 -2.335938,5.710938 -4.898438,10.0625 -7.6875,13.0625 -2.792969,3 -7.917969,5.855469 -15.375,8.5625 -7.460938,2.710938 -13.6875,4.605469 -18.6875,5.6875 -5,1.085938 -8.125,1.667969 -9.375,1.75 C 9.75,-0.207031 8.957031,-0.4375 8.625,-0.8125 8.289062,-1.1875 8.582031,-2.082031 9.5,-3.5 c 1.582031,-2.25 4.894531,-5.332031 9.9375,-9.25 5.039062,-3.914062 11,-8.789062 17.875,-14.625 6.875,-5.832031 12.019531,-10.976562 15.4375,-15.4375 3.414062,-4.457031 6.4375,-10.539062 9.0625,-18.25 C 64.4375,-68.769531 67,-76.832031 69.5,-85.25 c 2.5,-8.414062 4.3125,-14.125 5.4375,-17.125 1.125,-3 2.269531,-4.45703 3.4375,-4.375 1.332031,0.25 1.75,1.41797 1.25,3.5 z m 8.875,-68.625 c 0.664062,2.41797 0.644531,4.91797 -0.0625,7.5 -0.710938,2.58594 -2.023438,5.29297 -3.9375,8.125 -1.167969,1.91797 -2.398438,3.64844 -3.6875,5.1875 -1.292969,1.54297 -2.648438,3.02344 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.960938,1.14844 -2.875,1.4375 -0.917969,0.29297 -1.585938,0.1875 -2,-0.3125 -3,-2.41406 -5.960938,-4.875 -8.875,-7.375 -2.917969,-2.5 -6.125,-4.83203 -9.625,-7 -0.585938,-0.41406 -0.855469,-0.8125 -0.8125,-1.1875 0.03906,-0.375 0.269531,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.83203 1.164062,-1.22656 1.75,-1.1875 0.582031,0.043 1.207031,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-2-7"
overflow="visible"
style="overflow:visible">
<path
id="path169"
d="m 29.625,-70.625 c -0.667969,8.335938 -2.542969,15.417969 -5.625,21.25 -3.085938,5.835938 -6.585938,8.75 -10.5,8.75 0,-3.164062 1.019531,-13 3.0625,-29.5 2.039062,-16.5 3.582031,-28.3125 4.625,-35.4375 1.039062,-7.125 2.226562,-14.6875 3.5625,-22.6875 1.332031,-8 2.625,-14.45703 3.875,-19.375 1.414062,-4.08203 2.9375,-8.20703 4.5625,-12.375 1.625,-4.16406 3.3125,-8.28906 5.0625,-12.375 1.164062,-1.83203 1.914062,-1.53906 2.25,0.875 -2.085938,13.83594 -4,28.1875 -5.75,43.0625 -1.75,14.875 -2.9375,25.52344 -3.5625,31.9375 -0.625,6.417969 -0.9375,10.167969 -0.9375,11.25 -0.417969,6.835938 -0.625,11.710938 -0.625,14.625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-3-5"
overflow="visible"
style="overflow:visible">
<path
id="path172"
d="m -16.125,-40.625 c 1.25,-5.332031 2.625,-10 4.125,-14 1.5,-4 2.960938,-7.3125 4.375,-9.9375 1.417969,-2.625 2.792969,-4.644531 4.125,-6.0625 1.335938,-1.414062 2.5,-2.25 3.5,-2.5 v 8.25 c 0,10.5 2.789062,17.835938 8.375,22 3.414062,2.25 6.8125,3 10.1875,2.25 3.375,-0.75 5.957031,-2.5 7.75,-5.25 1.789062,-2.75 3.3125,-5.976562 4.5625,-9.6875 1.25,-3.707031 2.457031,-5.5625 3.625,-5.5625 1.332031,0 1.875,1.335938 1.625,4 -0.08594,4.5 -1.480469,11.8125 -4.1875,21.9375 -2.710938,10.125 -6.375,18.4375 -11,24.9375 -4.625,6.5 -10.230469,9.917969 -16.8125,10.25 -6.75,-0.25 -12,-4.039062 -15.75,-11.375 -3.414062,-7.25 -4.914062,-16.625 -4.5,-28.125 z M 28.5,82.125 c 0.664062,2.414062 0.644531,4.914062 -0.0625,7.5 -0.710938,2.582031 -2.023438,5.289062 -3.9375,8.125 -1.167969,1.914062 -2.398438,3.64453 -3.6875,5.1875 -1.292969,1.53906 -2.648438,3.01953 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.45703 -2.875,2.125 -1,0.66406 -1.960938,1.14453 -2.875,1.4375 C 8.082031,113.10156 7.414062,113 7,112.5 c -3,-2.41797 -5.960938,-4.875 -8.875,-7.375 -2.914062,-2.5 -6.125,-4.83594 -9.625,-7 -0.582031,-0.417969 -0.851562,-0.8125 -0.8125,-1.1875 0.04297,-0.375 0.273438,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.835938 1.164062,-1.230469 1.75,-1.1875 0.582031,0.03906 1.207031,0.269531 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.601562 4.875,4.0625 1.5,1.457031 2.8125,3.039062 3.9375,4.75 1.125,1.707031 1.9375,3.601562 2.4375,5.6875 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-4-3"
overflow="visible"
style="overflow:visible">
<path
id="path175"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-5-5"
overflow="visible"
style="overflow:visible">
<path
id="path178"
d="M 72.125,0.125 C 58.039062,0.0390625 47.164062,-0.582031 39.5,-1.75 26.164062,-3.832031 16.664062,-7.832031 11,-13.75 5.914062,-18.332031 3.375,-24.582031 3.375,-32.5 c 0,-3.082031 0.289062,-7.5 0.875,-13.25 0.582031,-5.75 1.375,-11.5 2.375,-17.25 0.414062,-2.414062 0.789062,-4.582031 1.125,-6.5 0.25,-1.332031 0.582031,-2.414062 1,-3.25 0.414062,-0.832031 0.875,-1.3125 1.375,-1.4375 0.5,-0.125 0.976562,0.210938 1.4375,1 0.457031,0.792969 0.894531,2.148438 1.3125,4.0625 0.332031,2.085938 0.789062,4.25 1.375,6.5 1.332031,5.417969 4.957031,9.460938 10.875,12.125 15,6.417969 37.914062,9.75 68.75,10 12.75,-0.164062 24.58203,-0.625 35.5,-1.375 11.16406,-0.832031 23.75,-2.789062 37.75,-5.875 14,-3.082031 25.14453,-6.457031 33.4375,-10.125 8.28906,-3.664062 15.35156,-7.625 21.1875,-11.875 4.58203,-3.332031 6.875,-6.539062 6.875,-9.625 0,-1.25 -1.1875,-2.726562 -3.5625,-4.4375 -2.375,-1.707031 -3.9375,-2.5625 -4.6875,-2.5625 -1.41797,0.667969 -3.08594,1.1875 -5,1.5625 -1.91797,0.375 -3.66797,0.480469 -5.25,0.3125 -4.41797,-0.5 -7.71094,-1.875 -9.875,-4.125 -2.16797,-2.25 -3.25,-5.289062 -3.25,-9.125 0,-2.41406 3.20703,-10 9.625,-22.75 2.58203,-5.16406 4.85156,-8.76953 6.8125,-10.8125 1.95703,-2.03906 4.64453,-3.0625 8.0625,-3.0625 5.41406,0 10.4375,2.91797 15.0625,8.75 4.625,5.83594 6.9375,13.29297 6.9375,22.375 0,9 -1.21094,16.792969 -3.625,23.375 -3,9 -7.08594,17.335938 -12.25,25 -6.5,9.25 -13.625,16.5625 -21.375,21.9375 -7.75,5.375 -15.58594,9.648438 -23.5,12.8125 -7.08594,3.5 -16.23047,6.773438 -27.4375,9.8125 -11.21094,3.042969 -24.8125,5.523438 -40.8125,7.4375 -15.835938,1.917969 -29.960938,2.9140625 -42.375,3 z m 82.375,-172 c 0.66406,2.41797 0.64453,4.91797 -0.0625,7.5 -0.71094,2.58594 -2.02344,5.29297 -3.9375,8.125 -1.16797,1.91797 -2.39844,3.64844 -3.6875,5.1875 -1.29297,1.54297 -2.64844,3.02344 -4.0625,4.4375 -0.41797,0.5 -1.08594,1.125 -2,1.875 -0.91797,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.96094,1.14844 -2.875,1.4375 -0.91797,0.29297 -1.58594,0.1875 -2,-0.3125 -3,-2.41406 -5.96094,-4.875 -8.875,-7.375 -2.91797,-2.5 -6.125,-4.83203 -9.625,-7 -0.58594,-0.41406 -0.85547,-0.8125 -0.8125,-1.1875 0.0391,-0.375 0.26953,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.58203,-0.83203 1.16406,-1.22656 1.75,-1.1875 0.58203,0.043 1.20703,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-6-6"
overflow="visible"
style="overflow:visible">
<path
id="path181"
d="m 115,-102.5 c -1.83594,3.25 -3.75,6.523438 -5.75,9.8125 -2,3.292969 -4.23047,6.398438 -6.6875,9.3125 -2.46094,2.917969 -5.167969,5.5625 -8.125,7.9375 -2.960938,2.375 -6.3125,4.273438 -10.0625,5.6875 -3.085938,1.25 -5.710938,2.648438 -7.875,4.1875 -2.167969,1.542969 -3.960938,3.1875 -5.375,4.9375 -2.167969,2.335938 -4.042969,5.5625 -5.625,9.6875 -1.585938,4.125 -3.230469,8.480469 -4.9375,13.0625 -1.710938,4.585938 -3.585938,9.0625 -5.625,13.4375 -2.042969,4.375 -4.605469,7.980469 -7.6875,10.8125 C 43,-9.125 36.707031,-6.082031 28.375,-4.5 L 5.5,-0.625 C 4.832031,-0.539062 4.019531,-0.476562 3.0625,-0.4375 2.101562,-0.394531 1.414062,-0.414062 1,-0.5 -0.914062,-1.082031 -1.5,-2.351562 -0.75,-4.3125 0,-6.269531 1.957031,-8.25 5.125,-10.25 c 6.414062,-4.25 11.539062,-7.6875 15.375,-10.3125 3.832031,-2.625 6.957031,-4.769531 9.375,-6.4375 2.414062,-1.664062 4.351562,-3.039062 5.8125,-4.125 1.457031,-1.082031 3.019531,-2.289062 4.6875,-3.625 6.75,-5.082031 11.414062,-10.414062 14,-16 1.5,-2.914062 2.875,-5.75 4.125,-8.5 1.25,-2.75 2.5625,-5.457031 3.9375,-8.125 1.375,-2.664062 2.851562,-5.3125 4.4375,-7.9375 1.582031,-2.625 3.414062,-5.269531 5.5,-7.9375 2.164062,-2.664062 5.082031,-5.269531 8.75,-7.8125 3.664062,-2.539062 8.082031,-5.0625 13.25,-7.5625 0.582031,-0.25 1.539062,-0.8125 2.875,-1.6875 1.332031,-0.875 2.95703,-2.26953 4.875,-4.1875 1.91406,-1.91406 4.10156,-4.51953 6.5625,-7.8125 2.45703,-3.28906 5.0625,-7.47656 7.8125,-12.5625 -1,-1 -3.875,-2.375 -8.625,-4.125 -4.75,-1.83203 -9.25,-2.875 -13.5,-3.125 -3.917969,-0.25 -7.148438,0.46094 -9.6875,2.125 -2.542969,1.66797 -4.855469,4.04297 -6.9375,7.125 -2.085938,3.08594 -3.875,4.5 -5.375,4.25 -0.5,-0.25 -0.585938,-1.28906 -0.25,-3.125 0.414062,-1.83203 1,-3.625 1.75,-5.375 3.164062,-7.25 6.75,-12.625 10.75,-16.125 4.082031,-3.58203 8.957031,-5.375 14.625,-5.375 4.08203,0 9.20703,1 15.375,3 3.83203,1.33594 7.125,2 9.875,2 5.75,0 11.45703,-2.03906 17.125,-6.125 1.25,0 1.6875,0.8125 1.3125,2.4375 -0.375,1.625 -0.9375,3.52344 -1.6875,5.6875 -0.66797,2.16797 -1.125,3.625 -1.375,4.375 -1.25,3.91797 -2.25,6.21094 -3,6.875 -0.75,0.58594 -2.91797,2.16797 -6.5,4.75 -2,1.5 -3.73047,3.23047 -5.1875,5.1875 -1.46094,1.96094 -2.9375,4.27344 -4.4375,6.9375 -1.5,2.66797 -3.41797,6.33594 -5.75,11 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
</g>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1471"
id="namedview4"
showgrid="false"
inkscape:zoom="0.59454973"
inkscape:cx="-165.7731"
inkscape:cy="361.75575"
inkscape:window-x="0"
inkscape:window-y="55"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path871"
d="m 205.59223,196.11402 c -5.97657,36.66667 -11.35417,64.02995 -16.14583,82.08333 -4.79167,18.0599 -9.13412,31.84245 -13.02084,41.35417 -3.89323,9.51823 -8.16406,16.77083 -12.8125,21.77083 -4.65495,5 -13.19661,9.75912 -25.625,14.27083 -12.43489,4.51823 -22.8125,7.67579 -31.14583,9.47917 -8.333331,1.8099 -13.541664,2.77995 -15.624997,2.91667 -2.083334,-0.13672 -3.404949,-0.52084 -3.958334,-1.14584 -0.559896,-0.625 -0.07161,-2.11588 1.458334,-4.47916 2.636718,-3.75 8.157551,-8.88672 16.562497,-15.41667 8.39844,-6.52344 18.33333,-14.64844 29.79167,-24.375 11.45833,-9.72005 20.03255,-18.29427 25.72916,-25.72916 5.69011,-7.42839 10.72917,-17.56511 15.10417,-30.41667 4.375,-12.84505 8.64583,-26.28255 12.8125,-40.3125 4.16667,-14.02343 7.1875,-23.54166 9.0625,-28.54166 1.875,-5 3.78255,-7.42839 5.72916,-7.29167 2.22006,0.41667 2.91667,2.36328 2.08334,5.83333 z M 220.38389,81.739028 c 1.10677,4.02995 1.07422,8.196616 -0.10416,12.5 -1.1849,4.309899 -3.3724,8.821612 -6.5625,13.541662 -1.94662,3.19662 -3.9974,6.08074 -6.14584,8.64584 -2.15494,2.57161 -4.41406,5.03906 -6.77083,7.39583 -0.69661,0.83333 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.4349 -4.79167,3.54167 -1.66666,1.11328 -3.26823,1.91406 -4.79166,2.39583 -1.52995,0.48828 -2.64323,0.3125 -3.33334,-0.52083 -5,-4.02344 -9.93489,-8.125 -14.79166,-12.29167 -4.86329,-4.16667 -10.20834,-8.05338 -16.04167,-11.66667 -0.97656,-0.6901 -1.42578,-1.35416 -1.35417,-1.97916 0.0651,-0.625 0.44922,-1.5625 1.14584,-2.8125 l 33.33333,-50.833334 c 0.97005,-1.386717 1.9401,-2.044267 2.91667,-1.979167 0.97005,0.07167 2.01171,0.455734 3.125,1.145834 2.91666,1.666666 5.83333,3.541666 8.74999,5.624999 2.91667,2.083334 5.625,4.34245 8.125,6.770833 2.5,2.4349 4.6875,5.071617 6.5625,7.916667 1.875,2.851566 3.22917,6.009116 4.0625,9.479166 z m 0,0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
d="m 256.21722,250.48902 c -1.11328,13.89323 -4.23828,25.69662 -9.375,35.41667 -5.14323,9.72656 -10.97656,14.58333 -17.5,14.58333 0,-5.27344 1.69922,-21.66667 5.10417,-49.16667 3.39843,-27.49999 5.97005,-47.18749 7.70833,-59.06249 1.73177,-11.875 3.71094,-24.47917 5.9375,-37.8125 2.22005,-13.33333 4.375,-24.09505 6.45833,-32.29167 2.35677,-6.80338 4.89583,-13.67838 7.60417,-20.625 2.70833,-6.940096 5.52083,-13.815095 8.4375,-20.624995 1.9401,-3.053383 3.1901,-2.5651 3.75,1.458333 -3.47657,23.059902 -6.66667,46.979162 -9.58334,71.770832 -2.91666,24.79166 -4.89583,42.53906 -5.9375,53.22916 -1.04166,10.69662 -1.5625,16.94662 -1.5625,18.75 -0.69661,11.39323 -1.04166,19.51823 -1.04166,24.375 z m 0,0"
id="path875" />
<path
id="path945"
d="m 229.34222,300.48902 c 2.08333,-8.88672 4.375,-16.66667 6.875,-23.33333 2.5,-6.66667 4.9349,-12.1875 7.29167,-16.5625 2.36328,-4.375 4.65495,-7.74089 6.875,-10.10417 2.22656,-2.35677 4.16666,-3.75 5.83333,-4.16667 v 13.75 c 0,17.5 4.64844,29.72657 13.95833,36.66667 5.69011,3.75 11.35417,5 16.97917,3.75 5.625,-1.25 9.92838,-4.16667 12.91666,-8.75 2.98177,-4.58333 5.52084,-9.96094 7.60417,-16.14583 2.08333,-6.17839 4.09505,-9.27084 6.04167,-9.27084 2.22005,0 3.125,2.22657 2.70833,6.66667 -0.14323,7.5 -2.46745,19.6875 -6.97917,36.5625 -4.51823,16.875 -10.625,30.72916 -18.33333,41.5625 -7.70833,10.83333 -17.05078,16.52995 -28.02083,17.08333 -11.25,-0.41667 -20,-6.73177 -26.25,-18.95833 -5.6901,-12.08334 -8.1901,-27.70833 -7.5,-46.875 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
id="path943"
d="m 286.78334,583.03989 c 1.10677,4.02343 1.07422,8.1901 -0.10416,12.5 -1.1849,4.30338 -3.3724,8.8151 -6.5625,13.54167 -1.94662,3.1901 -3.9974,6.07421 -6.14584,8.64583 -2.15495,2.5651 -4.41406,5.03255 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.42839 -4.79167,3.54167 -1.66667,1.10677 -3.26823,1.90755 -4.79167,2.39583 -1.52994,0.48177 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02995 -9.9349,-8.125 -14.79167,-12.29167 -4.85677,-4.16666 -10.20833,-8.0599 -16.04166,-11.66666 -0.97005,-0.69662 -1.41927,-1.35417 -1.35417,-1.97917 0.0716,-0.625 0.45573,-1.5625 1.14583,-2.8125 l 33.33334,-50.83333 c 0.97005,-1.39323 1.9401,-2.05078 2.91666,-1.97917 0.97006,0.0652 2.01172,0.44922 3.125,1.14584 2.91667,1.66666 5.83334,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.33593 8.125,6.77083 2.5,2.42838 4.6875,5.0651 6.5625,7.91667 1.875,2.84505 3.22917,6.00259 4.0625,9.47916 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
id="path879"
d="M 303.71722,505.07234"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path925"
d="m 168.42167,500.82557 c -23.47656,-0.14323 -41.60156,-1.17838 -54.375,-3.125 -22.226562,-3.47005 -38.059894,-10.13671 -47.499997,-20 -8.476563,-7.63671 -12.708333,-18.05338 -12.708333,-31.24999 0,-5.13672 0.48177,-12.5 1.458333,-22.08334 0.970052,-9.58333 2.291667,-19.16666 3.958333,-28.75 0.690104,-4.02343 1.315104,-7.63671 1.875,-10.83333 0.416667,-2.22005 0.970052,-4.02344 1.666667,-5.41667 0.690103,-1.38671 1.458333,-2.1875 2.291666,-2.39583 0.833334,-0.20833 1.627604,0.35156 2.395834,1.66667 0.761718,1.32161 1.490885,3.58073 2.187499,6.77083 0.553385,3.47656 1.315104,7.08333 2.291667,10.83333 2.220052,9.02995 8.261718,15.76823 18.124999,20.20834 25.000002,10.69661 63.190102,16.25 114.583332,16.66666 21.25,-0.27343 40.97005,-1.04166 59.16666,-2.29166 18.60677,-1.38672 39.58333,-4.64844 62.91667,-9.79167 23.33333,-5.13672 41.90754,-10.76172 55.72916,-16.875 13.8151,-6.10677 25.58593,-12.70833 35.3125,-19.79167 7.63671,-5.55338 11.45833,-10.89843 11.45833,-16.04166 0,-2.08333 -1.97917,-4.54427 -5.9375,-7.39583 -3.95833,-2.84506 -6.5625,-4.27084 -7.8125,-4.27084 -2.36328,1.11328 -5.14323,1.97917 -8.33333,2.60417 -3.19662,0.625 -6.11328,0.80078 -8.75,0.52083 -7.36328,-0.83333 -12.85157,-3.125 -16.45833,-6.875 -3.61329,-3.75 -5.41667,-8.8151 -5.41667,-15.20833 0,-4.02343 5.34505,-16.66667 16.04167,-37.91667 4.30338,-8.60676 8.08593,-14.61588 11.35416,-18.02083 3.26172,-3.39843 7.74089,-5.10416 13.4375,-5.10416 9.02343,0 17.39583,4.86328 25.10417,14.58333 7.70833,9.72656 11.5625,22.15495 11.5625,37.29166 0,15 -2.01824,27.98828 -6.04167,38.95834 -5,14.99999 -11.8099,28.89322 -20.41667,41.66666 -10.83333,15.41667 -22.70833,27.60417 -35.62499,36.5625 -12.91667,8.95833 -25.97657,16.08073 -39.16667,21.35416 -11.8099,5.83334 -27.05078,11.28907 -45.72916,16.35417 -18.6849,5.07162 -41.35417,9.20573 -68.02083,12.39583 -26.39323,3.19662 -49.9349,4.85677 -70.625,5 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
<path
inkscape:connector-curvature="0"
id="path923"
d="m 430.22191,133.16177 c 1.10676,4.02995 1.07421,8.19662 -0.10417,12.5 -1.1849,4.3099 -3.3724,8.82162 -6.5625,13.54167 -1.94661,3.19661 -3.9974,6.08073 -6.14583,8.64583 -2.15495,2.57162 -4.41407,5.03907 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33334,3.125 -1.52995,1.25 -3.125,2.4349 -4.79166,3.54167 -1.66667,1.11328 -3.26824,1.91407 -4.79167,2.39583 -1.52995,0.48829 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02343 -9.9349,-8.125 -14.79167,-12.29167 -4.86328,-4.16666 -10.20833,-8.05338 -16.04167,-11.66666 -0.97656,-0.6901 -1.42578,-1.35417 -1.35416,-1.97917 0.0652,-0.625 0.44921,-1.5625 1.14583,-2.8125 l 33.33333,-50.83333 c 0.97005,-1.38672 1.9401,-2.04427 2.91667,-1.97917 0.97005,0.0717 2.01172,0.45574 3.125,1.14584 2.91667,1.66666 5.83333,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.34245 8.125,6.77083 2.5,2.4349 4.6875,5.07162 6.5625,7.91667 1.875,2.85156 3.22916,6.00911 4.0625,9.47916 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
<path
inkscape:connector-curvature="0"
id="path883"
d="M 305.71333,214.15892"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
<path
id="path887"
d="m 599.12998,319.78391 c -3.0599,5.41667 -6.25,10.8724 -9.58333,16.35417 -3.33334,5.48828 -7.05079,10.66406 -11.14584,15.52083 -4.10156,4.86328 -8.61328,9.27084 -13.54166,13.22917 -4.9349,3.95833 -10.52084,7.12239 -16.77084,9.47916 -5.14323,2.08334 -9.51823,4.41407 -13.125,6.97917 -3.61328,2.57162 -6.60156,5.3125 -8.95833,8.22917 -3.61328,3.89323 -6.73828,9.27083 -9.375,16.14583 -2.64323,6.875 -5.38411,14.13411 -8.22916,21.77083 -2.85157,7.64323 -5.97657,15.10417 -9.375,22.39583 -3.40495,7.29167 -7.67579,13.30079 -12.8125,18.02084 -7.08334,7.5 -17.57162,12.57161 -31.45834,15.20833 l -38.12499,6.45833 c -1.11329,0.14323 -2.46745,0.2474 -4.0625,0.3125 -1.60157,0.0716 -2.7474,0.0391 -3.4375,-0.10416 -3.19011,-0.97005 -4.16667,-3.08594 -2.91667,-6.35417 1.25,-3.26172 4.51172,-6.5625 9.79167,-9.89583 10.6901,-7.08334 19.23177,-12.8125 25.625,-17.1875 6.38671,-4.375 11.59505,-7.94922 15.62499,-10.72917 4.02344,-2.77343 7.25261,-5.0651 9.6875,-6.875 2.42839,-1.80338 5.03256,-3.8151 7.8125,-6.04166 11.25,-8.47006 19.02344,-17.35677 23.33334,-26.66667 2.5,-4.85677 4.79166,-9.58333 6.875,-14.16667 2.08333,-4.58333 4.27083,-9.09505 6.5625,-13.54166 2.29166,-4.44011 4.7526,-8.85417 7.39583,-13.22917 2.63672,-4.375 5.6901,-8.78255 9.16667,-13.22916 3.60677,-4.44011 8.47005,-8.78256 14.58333,-13.02084 6.10677,-4.23177 13.47005,-8.4375 22.08333,-12.60416 0.97005,-0.41667 2.5651,-1.35417 4.79167,-2.8125 2.22005,-1.45834 4.92838,-3.78255 8.125,-6.97917 3.1901,-3.1901 6.83593,-7.53255 10.9375,-13.02083 4.09505,-5.48177 8.4375,-12.46094 13.02083,-20.9375 -1.66667,-1.66667 -6.45833,-3.95833 -14.375,-6.875 -7.91667,-3.05338 -15.41667,-4.79167 -22.5,-5.20833 -6.52995,-0.41667 -11.91406,0.76823 -16.14583,3.54166 -4.23828,2.77995 -8.09245,6.73829 -11.5625,11.875 -3.47657,5.14323 -6.45833,7.5 -8.95833,7.08333 -0.83334,-0.41666 -0.97657,-2.14843 -0.41667,-5.20833 0.6901,-3.05338 1.66667,-6.04166 2.91667,-8.95833 5.27343,-12.08333 11.24999,-21.04167 17.91666,-26.875 6.80339,-5.97005 14.92839,-8.95833 24.375,-8.95833 6.80338,0 15.34505,1.66666 25.625,5 6.38672,2.22656 11.875,3.33333 16.45833,3.33333 9.58333,0 19.09505,-3.39843 28.54167,-10.20833 2.08333,0 2.8125,1.35416 2.1875,4.0625 -0.625,2.70833 -1.5625,5.8724 -2.8125,9.47916 -1.11329,3.61329 -1.875,6.04167 -2.29167,7.29167 -2.08333,6.52995 -3.75,10.35157 -5,11.45833 -1.25,0.97657 -4.86328,3.61329 -10.83333,7.91667 -3.33334,2.5 -6.21745,5.38411 -8.64584,8.64583 -2.43489,3.26823 -4.89583,7.1224 -7.39583,11.5625 -2.5,4.44662 -5.69661,10.5599 -9.58333,18.33333 z m 0,0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<use
style="fill:#000000;fill-opacity:1"
id="use62"
y="291"
x="119.25"
xlink:href="#glyph0-4"
width="100%"
height="100%"
transform="matrix(1.3333333,0,0,1.3333333,72.589732,-189.32751)" />
<use
style="fill:#000000;fill-opacity:1"
id="use196"
y="391"
x="168.375"
xlink:href="#glyph0-4-3"
width="100%"
height="100%"
transform="matrix(1.3333333,0,0,1.3333333,-861.41828,-631.73483)" />
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 682.667 682.667">
<!-- Harf -->
<path d="M168.422 500.826c-23.477-.144-41.602-1.179-54.375-3.125-22.227-3.47-38.06-10.137-47.5-20-8.477-7.637-12.709-18.054-12.709-31.25 0-5.137.482-12.5 1.459-22.084a406.941 406.941 0 013.958-28.75c.69-4.023 1.315-7.636 1.875-10.833.417-2.22.97-4.024 1.667-5.417.69-1.386 1.458-2.187 2.291-2.396.834-.208 1.628.352 2.396 1.667.762 1.322 1.491 3.58 2.188 6.77a114.35 114.35 0 002.291 10.834c2.22 9.03 8.262 15.768 18.125 20.209 25 10.696 63.19 16.25 114.584 16.666 21.25-.273 40.97-1.041 59.166-2.291 18.607-1.387 39.584-4.649 62.917-9.792 23.333-5.137 41.908-10.762 55.73-16.875 13.814-6.107 25.585-12.708 35.312-19.792 7.636-5.553 11.458-10.898 11.458-16.041 0-2.084-1.98-4.545-5.938-7.396-3.958-2.845-6.562-4.271-7.812-4.271-2.363 1.113-5.143 1.98-8.333 2.604-3.197.625-6.114.8-8.75.52-7.364-.832-12.852-3.124-16.459-6.874-3.613-3.75-5.416-8.815-5.416-15.208 0-4.024 5.345-16.667 16.041-37.917 4.304-8.607 8.086-14.616 11.354-18.02 3.262-3.4 7.741-5.105 13.438-5.105 9.023 0 17.396 4.863 25.104 14.583 7.708 9.727 11.563 22.155 11.563 37.292 0 15-2.019 27.988-6.042 38.958-5 15-11.81 28.893-20.417 41.667-10.833 15.417-22.708 27.604-35.625 36.562-12.916 8.959-25.976 16.081-39.166 21.355-11.81 5.833-27.051 11.289-45.73 16.354-18.684 5.071-41.354 9.205-68.02 12.396-26.394 3.196-49.935 4.856-70.625 5zM430.222 133.162c1.107 4.03 1.074 8.196-.104 12.5-1.185 4.31-3.373 8.821-6.563 13.541-1.946 3.197-3.997 6.081-6.146 8.646a114.073 114.073 0 01-6.77 7.396c-.697.833-1.81 1.875-3.334 3.125a60.28 60.28 0 01-4.791 3.542c-1.667 1.113-3.269 1.914-4.792 2.396-1.53.488-2.643.312-3.333-.521-5-4.024-9.935-8.125-14.792-12.292-4.863-4.167-10.208-8.053-16.042-11.667-.976-.69-1.426-1.354-1.354-1.979.065-.625.45-1.562 1.146-2.812l33.333-50.834c.97-1.386 1.94-2.044 2.917-1.979.97.072 2.012.456 3.125 1.146a102.942 102.942 0 018.75 5.625 70.208 70.208 0 018.125 6.77 47.58 47.58 0 016.562 7.918c1.875 2.851 3.23 6.009 4.063 9.479zM599.13 319.784a589.994 589.994 0 01-9.583 16.354 123.488 123.488 0 01-11.146 15.52 97.741 97.741 0 01-13.542 13.23c-4.935 3.958-10.52 7.122-16.77 9.48-5.144 2.083-9.519 4.413-13.126 6.978-3.613 2.572-6.601 5.313-8.958 8.23-3.613 3.893-6.738 9.27-9.375 16.145a2240.458 2240.458 0 00-8.23 21.771 307.032 307.032 0 01-9.374 22.396c-3.405 7.292-7.676 13.3-12.813 18.02-7.083 7.5-17.571 12.573-31.458 15.21l-38.125 6.458c-1.113.143-2.467.247-4.063.312-1.601.072-2.747.04-3.437-.104-3.19-.97-4.167-3.086-2.917-6.354 1.25-3.262 4.512-6.563 9.792-9.896 10.69-7.083 19.232-12.813 25.625-17.188a6164.29 6164.29 0 0015.625-10.729c4.023-2.773 7.253-5.065 9.687-6.875a271.19 271.19 0 007.813-6.041c11.25-8.47 19.023-17.357 23.333-26.667 2.5-4.857 4.792-9.583 6.875-14.167a305.502 305.502 0 016.563-13.541 226.164 226.164 0 017.396-13.23c2.636-4.375 5.69-8.782 9.166-13.229 3.607-4.44 8.47-8.782 14.584-13.02 6.106-4.232 13.47-8.438 22.083-12.605.97-.416 2.565-1.354 4.792-2.812 2.22-1.459 4.928-3.783 8.125-6.98 3.19-3.19 6.836-7.532 10.937-13.02 4.095-5.482 8.438-12.461 13.021-20.938-1.667-1.666-6.458-3.958-14.375-6.875-7.917-3.053-15.417-4.791-22.5-5.208-6.53-.417-11.914.768-16.146 3.542-4.238 2.78-8.092 6.738-11.562 11.875-3.477 5.143-6.459 7.5-8.959 7.083-.833-.417-.976-2.149-.416-5.208a51.587 51.587 0 012.916-8.959c5.274-12.083 11.25-21.041 17.917-26.875 6.803-5.97 14.928-8.958 24.375-8.958 6.803 0 15.345 1.667 25.625 5 6.387 2.226 11.875 3.333 16.458 3.333 9.584 0 19.095-3.398 28.542-10.208 2.083 0 2.812 1.354 2.187 4.062-.625 2.709-1.562 5.873-2.812 9.48-1.113 3.613-1.875 6.041-2.292 7.291-2.083 6.53-3.75 10.352-5 11.459-1.25.976-4.863 3.613-10.833 7.916a42.505 42.505 0 00-8.646 8.646c-2.435 3.268-4.896 7.122-7.396 11.563-2.5 4.446-5.696 10.56-9.583 18.333zm0 0"/>
<!-- B -->
<path d="M229.342 300.489c2.084-8.887 4.375-16.667 6.875-23.333 2.5-6.667 4.935-12.188 7.292-16.563 2.363-4.375 4.655-7.74 6.875-10.104 2.226-2.357 4.167-3.75 5.833-4.167v13.75c0 17.5 4.649 29.727 13.959 36.667 5.69 3.75 11.354 5 16.979 3.75s9.928-4.167 12.916-8.75c2.982-4.583 5.521-9.96 7.605-16.146 2.083-6.178 4.095-9.27 6.041-9.27 2.22 0 3.125 2.226 2.709 6.666-.144 7.5-2.468 19.688-6.98 36.563-4.518 16.875-10.625 30.729-18.333 41.562-7.708 10.833-17.05 16.53-28.02 17.083-11.25-.416-20-6.731-26.25-18.958-5.69-12.083-8.19-27.708-7.5-46.875zM286.783 583.04c1.107 4.023 1.075 8.19-.104 12.5-1.185 4.303-3.372 8.815-6.562 13.542-1.947 3.19-3.998 6.074-6.146 8.645a117.59 117.59 0 01-6.771 7.396c-.697.834-1.81 1.875-3.333 3.125a61.927 61.927 0 01-4.792 3.542c-1.667 1.107-3.268 1.907-4.792 2.396-1.53.481-2.643.312-3.333-.521-5-4.03-9.935-8.125-14.792-12.292-4.856-4.166-10.208-8.06-16.041-11.666-.97-.697-1.42-1.355-1.354-1.98.071-.625.455-1.562 1.145-2.812l33.334-50.833c.97-1.394 1.94-2.051 2.916-1.98.97.066 2.012.45 3.125 1.146a102.94 102.94 0 018.75 5.625 69.555 69.555 0 018.125 6.771 47.057 47.057 0 016.563 7.917c1.875 2.845 3.229 6.002 4.062 9.479z"/>
<!-- uzz -->
<path d="M205.592 196.114c-5.976 36.667-11.354 64.03-16.146 82.083-4.791 18.06-9.134 31.843-13.02 41.355-3.894 9.518-8.164 16.77-12.813 21.77-4.655 5-13.197 9.76-25.625 14.271-12.435 4.518-22.812 7.676-31.146 9.48-8.333 1.81-13.541 2.78-15.625 2.916-2.083-.137-3.405-.52-3.958-1.146-.56-.625-.072-2.116 1.458-4.479 2.637-3.75 8.158-8.887 16.563-15.417 8.398-6.523 18.333-14.648 29.791-24.375 11.459-9.72 20.033-18.294 25.73-25.729 5.69-7.428 10.729-17.565 15.104-30.416 4.375-12.846 8.646-26.283 12.812-40.313 4.167-14.023 7.188-23.542 9.063-28.542 1.875-5 3.782-7.428 5.729-7.291 2.22.416 2.917 2.363 2.083 5.833zm14.792-114.375c1.107 4.03 1.074 8.197-.104 12.5-1.185 4.31-3.373 8.822-6.563 13.542-1.946 3.196-3.997 6.08-6.146 8.646a114.072 114.072 0 01-6.77 7.395c-.697.834-1.81 1.875-3.334 3.125a60.279 60.279 0 01-4.791 3.542c-1.667 1.113-3.269 1.914-4.792 2.396-1.53.488-2.643.312-3.333-.521-5-4.023-9.935-8.125-14.792-12.292-4.863-4.166-10.208-8.053-16.042-11.666-.976-.69-1.426-1.354-1.354-1.98.065-.624.45-1.562 1.146-2.812l33.333-50.833c.97-1.387 1.94-2.045 2.917-1.98.97.072 2.012.456 3.125 1.146a102.945 102.945 0 018.75 5.625 70.208 70.208 0 018.125 6.771 47.58 47.58 0 016.562 7.917c1.875 2.851 3.23 6.009 4.063 9.479zm0 0M256.217 250.489c-1.113 13.893-4.238 25.697-9.375 35.417-5.143 9.726-10.976 14.583-17.5 14.583 0-5.273 1.7-21.667 5.104-49.167 3.399-27.5 5.97-47.187 7.709-59.062 1.731-11.875 3.71-24.48 5.937-37.813 2.22-13.333 4.375-24.095 6.459-32.291a574.618 574.618 0 017.604-20.625 683.688 683.688 0 018.437-20.625c1.94-3.054 3.19-2.565 3.75 1.458-3.476 23.06-6.666 46.98-9.583 71.77-2.917 24.793-4.896 42.54-5.938 53.23-1.041 10.697-1.562 16.947-1.562 18.75-.697 11.393-1.042 19.518-1.042 24.375zm0 0"/>
</svg>

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -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|HB_DEPRECATED_FOR()'
# 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,9 +80,10 @@ 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
# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files
# e.g. expand_content_files=running.sgml
expand_content_files=
@ -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

259
docs/features.dot Normal file
View file

@ -0,0 +1,259 @@
digraph {
graph [outputorder=edgefirst];
node [shape="record", fontname="Noto Sans Mono SemiBold", fontsize=15];
edge [fontname="Verdana", fontsize=12,labeldistance=7.5 ];
fontname="Verdana";
ranksep=0.02; nodesep=0.5;
subgraph {
ranksep="0.02 equally";
preprocessing[style=filled,fillcolor="lightgreen",fontname="Verdana",label="Glyph pre-processing"];
orthographic[style=filled,fillcolor="lightblue",fontname="Verdana",label="Orthographic Unit Shaping"];
reordering[style=filled, fillcolor="lightcoral",fontname="Verdana",label="Reordering group (USE)"];
topographic[style=filled,fillcolor="lightgoldenrod",fontname="Verdana",label="Topographical Features‡"];
typographic[style=filled,fillcolor="lightpink",fontname="Verdana",label="Typographic Presentation"];
positioning[style=filled,fillcolor="lightsalmon",fontname="Verdana",label="Positioning"];
preprocessing->reordering->orthographic->topographic->typographic->positioning;
}
decision1 [shape="diamond", label="Script\ndirection?",fontname="Verdana"];
rvrn->decision1;
ltrfeatures [label="{ltra|ltrm}", fillcolor="lightgreen",style="filled"];
{
rtlfeatures [label="{rtla|rtlm¹}", fillcolor="lightgreen",style="filled"];
}
{
rank=same;
fracfeatures [label="frac²|numr³|dnom⁴", fillcolor="lightpink",style="filled"];
fracnotes [fontname="Verdana",shape=plaintext,label=<<table border="0" cellborder="0" cellspacing="0">
<tr><td align="left">¹ rtlm is scoped to characters with a Unicode mirroring property</td></tr>
<tr><td align="left">² frac is scoped to numr + the slash + dnom</td></tr>
<tr><td align="left">³ numr is scoped to all decimal numbers before a U+2044 FRACTION SLASH.</td></tr>
<tr><td align="left">⁴ dnom is scoped to all decimal numbers after a U+2044 FRACTION SLASH.</td></tr>
</table>
>];
}
rand [fillcolor="lightpink",style="filled"];
decision1 -> ltrfeatures [label="Left-to-right"];
decision1 -> rtlfeatures [label="Right-to-left"];
decision1 -> fracfeatures [label="Other"];
ltrfeatures -> fracfeatures;
rtlfeatures -> fracfeatures;
fracfeatures->rand;
decision2 [shape="diamond", label="Script?",fontname="Verdana"];
{rank=same; HARF [label="{Harf|HARF}"]; notes;}
rand -> trak -> HARF -> decision2;
commonfeatures [shape=none,label=<<table border="0" cellspacing="0">
<tr>
<td border="1" bgcolor="lightsalmon">abvm</td>
<td border="1" bgcolor="lightsalmon">blwm</td>
<td border="1" bgcolor="lightgreen">ccmp</td>
<td border="1" bgcolor="lightgreen">locl</td>
<td border="1" bgcolor="lightsalmon">mark</td>
<td border="1" bgcolor="lightsalmon">mkmk</td>
<td border="1" bgcolor="lightpink">rlig</td>
</tr>
</table>>
];
decision3 [shape="diamond", label="Script\ndirection?",fontname="Verdana"];
BUZZ [label="{Buzz|BUZZ}"];
BUZZ -> commonfeatures -> decision3;
horizontalfeatures [
shape=none,label=<<table border="0" cellspacing="0">
<tr><td border="1" bgcolor="lightpink">calt <font face="Verdana">(not Hangul)</font></td></tr>
<tr><td border="1" bgcolor="lightpink">clig <font face="Verdana">(not Khmer)</font></td></tr>
<tr><td border="1" bgcolor="lightsalmon">curs</td></tr>
<tr><td border="1" bgcolor="lightsalmon">dist</td></tr>
<tr><td border="1" bgcolor="lightsalmon">kern</td></tr>
<tr><td border="1" bgcolor="lightpink">liga <font face="Verdana">(not Khmer)</font></td></tr>
<tr><td border="1" bgcolor="lightpink">rclt</td></tr>
</table>>
];
vert [label="vert",style=filled,fillcolor="lightpink"];
decision3 -> horizontalfeatures [label="Horizontal"];
decision3 -> vert [label="Vertical"];
discretionary [label="User-selected\ndiscretionary\nfeatures",fontname="Verdana"];
horizontalfeatures -> discretionary;
vert -> discretionary;
decision2->stch;
BUZZ;
subgraph shapers {
subgraph cluster_arabic {
bgcolor="lightyellow"
label="Arabic, Syriac";
stch [ style="filled", fillcolor="lightgreen",label="stch"];
ccmplocl [ style="filled", label="ccmp|locl", fillcolor="lightgreen"];
arabicfeatures [label="isol|fina|fin2|fin3|medi|med2|init", style="filled", fillcolor="lightgoldenrod"];
arabicfeatures2 [label="rclt|calt", style="filled",fillcolor="lightpink"];
rlig[style="filled",fillcolor="lightpink"];
mset [fillcolor="lightpink",style="filled"]
stch->ccmplocl->arabicfeatures->rlig->arabicfeatures2->mset;
}
mset->BUZZ:n;
subgraph cluster_hangul {
bgcolor="lightyellow"
label="Hangul";
hangulfeatures [label="ljmo|vjmo|tjmo", style="filled",fillcolor="lightgoldenrod"]
}
hangulfeatures->BUZZ:n;
subgraph cluster_indic {
label="Indic";
bgcolor="lightyellow"
// Preprocessing
loclccmpindic [label="locl†|ccmp†",style=filled,fillcolor="lightgreen"];
node[style=filled,fillcolor="lightgreen"];
nukt [label="nukt†"];
akhn [label="akhn†"];
loclccmpindic->indic_reorder_1->nukt->akhn;
indic_reorder_1[label="Initial reordering", fontname="Verdana",fillcolor="lightgrey",shape=ellipse,style=filled]
// Orthographic
node[style=filled,fillcolor="lightblue"]
rphf [label="rphf⁵"];
rkpf [label="rkpf†"];
pref [label="pref⁶"];
blwf [label="blwf⁷"];
abvf [label="abvf⁸"];
half [label="half⁹"];
pstf [label="pstf⁸"];
vatu [label="vatu†"];
cjct [label="cjct†"];
akhn ->rphf -> rkpf -> pref -> blwf -> abvf -> half -> pstf -> vatu -> cjct;
// Typographic presentation
indic_typographic[style=filled,fillcolor="lightpink",label="init|pres|abvs|blws|psts|haln"]
indic_reorder_2[label="Final reordering",fillcolor="lightgrey",fontname="Verdana", shape=ellipse,style=filled]
cjct->indic_reorder_2->indic_typographic;
notes2 [fontname="Verdana",shape=plaintext,style="",label=<<table border="0" cellborder="0" cellspacing="0">
<tr><td align="right">⁵ rphf is scoped to pre-base ra+halant sequences</td></tr>
<tr><td align="right">⁶ pref is scoped to the two glyphs after the base; outputs are reordered</td></tr>
<tr><td align="right">⁷ blwf is usually scoped to the whole syllable, except in Telugu and Kannada where it is post-base</td></tr>
<tr><td align="right">⁸ abvf and pstf are scoped to post-base</td></tr>
<tr><td align="right">⁹ half is scoped to pre-base</td></tr>
</table>
>];
indic_typographic -> notes2 [style=invis];
}
subgraph cluster_khmer {
label="Khmer";
bgcolor="lightyellow"
khmerbasic [style=filled,fillcolor="lightgreen",label="locl†|ccmp†|pref†|bwlf†|abvf†|pstf†|cfar†"]
khmerother [style=filled,fillcolor="lightpink",label="pres|abvs|blws|psts"]
khmerbasic -> khmerother -> khmerclig;
khmerclig [label="clig",style=filled,fillcolor="lightpink"];
}
subgraph cluster_myanmar {
label="Myanmar";
bgcolor="lightyellow"
loclccmpmyanmar [label="locl†|ccmp†",style=filled,fillcolor="lightgreen"];
rphfmymr [label="rphf†",style=filled,fillcolor="lightblue"]
prefmymr [label="pref†",style=filled,fillcolor="lightblue"]
blwfmymr [label="blwf†",style=filled,fillcolor="lightblue"]
pstfmymr [label="pstf†",style=filled,fillcolor="lightblue"]
myanmarother [label="pres|abvs|blws|psts",style=filled,fillcolor="lightpink"];
reorder_myanmar[label="Reordering", shape=ellipse,style=filled,fontname="Verdana"]
loclccmpmyanmar -> reorder_myanmar-> rphfmymr -> prefmymr -> blwfmymr -> pstfmymr -> myanmarother;
}
subgraph cluster_use {
label="Universal Shaping Engine"
bgcolor="lightyellow"
use_preprocessing [style=filled, label="locl†|ccmp†|nukt†|akhn†", fillcolor="lightgreen"];
// Reoredering
rphfuse [label="rphf¹⁰", style=filled, fillcolor="lightcoral"];
prefuse [label="pref¹¹", style=filled, fillcolor="lightcoral"];
// Orthographic
orthographicuse [label="rkrf†|abvf†|blwf†|half†|pstf†|vatu†|cjct†", style="filled", fillcolor="lightblue"];
topographicaluse [label="isol|init|medi|fina", style="filled", fillcolor="lightgoldenrod"];
typographicaluse [label="abvs|blws|haln|pres|psts", style="filled", fillcolor="lightpink"];
reorder_use[label="Reordering", shape=ellipse,style=filled,fontname="Verdana"]
use_preprocessing -> rphfuse -> prefuse->orthographicuse ->reorder_use -> topographicaluse -> typographicaluse;
notes3 [fontname="Verdana",shape=plaintext,label=<<table border="0" cellborder="0" cellspacing="0">
<tr><td align="left">¹⁰ Outputs are reordered as category R</td></tr>
<tr><td align="left">¹¹ Outputs are reordered to before base</td></tr>
</table>
>];
typographicaluse -> notes3 [style=invis];
}
}
indic_typographic->BUZZ:n;
typographicaluse->BUZZ:n;
khmerclig -> BUZZ:n;
myanmarother -> BUZZ:n;
decision2->hangulfeatures;
decision2->loclccmpindic;
decision2->khmerbasic;
decision2->loclccmpmyanmar;
decision2->use_preprocessing;
decision2->BUZZ [label=" Hebrew, Thai,\n Lao, other"];
notes [fontname="Verdana",shape=box,label=<<table border="0" cellborder="0" cellspacing="0">
<tr><td align="left">
<b>Indic</b> scripts are: Bengali, Devanagari,
Gujarati, Gurmukhi, Kannada,
Malayalam, Oriya, Tamil,
Telugu
</td></tr>
<tr><td align="left">
<b>USE</b> scripts are:
Adlam, Ahom, Balinese, Batak, Bhaiksuki, Brahmi, Buginese,
Buhid, Chakma, Cham, Chorasmian, Dives Akuru, Dogra, Duployan,
</td></tr>
<tr><td align="left">
Egyptian hieroglyphs, Elymaic, Grantha, Gunjala Ggondi, Hanifi Rohingya,
Hanunoo, Javanese, Kaithi, Kayah li, Kharoshthi, Khojki,
</td></tr>
<tr><td align="left">
Khudawadi, Lepcha, Limbu, Mahajani, Makasar, Mandaic, Manichaean,
Marchen, Masaram Gondi, Medefaidrin, Meetei Mayek, Miao, Modi,
</td></tr>
<tr><td align="left">
Mongolian, Multani, Nandinagari, Newa, Nko, Nyiakeng Puachue Hmong,
Old Sogdian, Pahawh Hmong, Phags Pa, Psalter Pahlavi, Rejang,
</td></tr>
<tr><td align="left">
Saurashtra, Sharada, Siddham, Sinhala, Sogdian, Soyombo, Sundanese,
Syloti Nagri, Tagalog, Tagbanwa, Tai Le, Tai Tham, Tai Viet,
</td></tr>
<tr><td align="left">
Takri, Tibetan, Tifinagh, Tirhuta, Wancho, Zanabazar square,
</td></tr>
</table>>]
footnote[fontname="Verdana",label=<<table border="0" cellborder="0" cellspacing="0">
<tr><td align="left">† Feature is scoped to each syllable</td></tr>
<tr><td align="left">‡ All topographic features are scoped based on topographic position</td></tr>
</table>>];
notes3->footnote[style=invis];
}

View file

@ -11,8 +11,7 @@
<title>HarfBuzz</title>
<graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
<para>
HarfBuzz is an <ulink url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>
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&mdash;for any writing
system and language.
@ -27,7 +26,7 @@
</abstract>
</bookinfo>
<part>
<part id="user-manual">
<title>User's manual</title>
<xi:include href="usermanual-what-is-harfbuzz.xml"/>
<xi:include href="usermanual-install-harfbuzz.xml"/>
@ -39,9 +38,10 @@
<xi:include href="usermanual-opentype-features.xml"/>
<xi:include href="usermanual-clusters.xml"/>
<xi:include href="usermanual-utilities.xml"/>
<xi:include href="usermanual-integration.xml"/>
</part>
<part>
<part id="reference-manual">
<partinfo>
<releaseinfo>
This document is for HarfBuzz &version;.
@ -50,43 +50,15 @@
</releaseinfo>
</partinfo>
<note>
<para>
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.
</para>
<para>
Prior to 2012, the original HarfBuzz codebase (which, these
days, is referred to as <emphasis>harfbuzz-old</emphasis>) was
derived from code in <ulink
url="http://freetype.org/">FreeType</ulink>, <ulink
url="http://pango.org/">Pango</ulink>, and
<ulink url="http://qt-project.org/">Qt</ulink>.
It is <emphasis>not</emphasis> 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.
</para>
<para>
To make this distinction clearer in discussions, the current
HarfBuzz codebase is sometimes referred to as
<emphasis>harfbuzz-ng</emphasis>.
</para>
<para>
For reference purposes, the harfbuzz-old source tree is archived
<ulink
url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>. There
are no release tarballs of harfbuzz-old whatsoever.
</para>
</note>
<title>Reference manual</title>
<chapter>
<chapter id="core-api">
<title>Core API</title>
<xi:include href="xml/hb-blob.xml"/>
<xi:include href="xml/hb-buffer.xml"/>
<xi:include href="xml/hb-common.xml"/>
<xi:include href="xml/hb-features.xml"/>
<xi:include href="xml/hb-draw.xml"/>
<xi:include href="xml/hb-paint.xml"/>
<xi:include href="xml/hb-deprecated.xml"/>
<xi:include href="xml/hb-face.xml"/>
<xi:include href="xml/hb-font.xml"/>
@ -98,80 +70,150 @@
<xi:include href="xml/hb-version.xml"/>
</chapter>
<chapter>
<chapter id="opentype-api">
<title>OpenType API</title>
<xi:include href="xml/hb-ot-color.xml"/>
<xi:include href="xml/hb-ot-font.xml"/>
<xi:include href="xml/hb-ot-layout.xml"/>
<xi:include href="xml/hb-ot-math.xml"/>
<xi:include href="xml/hb-ot-meta.xml"/>
<xi:include href="xml/hb-ot-metrics.xml"/>
<xi:include href="xml/hb-ot-name.xml"/>
<xi:include href="xml/hb-ot-shape.xml"/>
<xi:include href="xml/hb-ot-var.xml"/>
</chapter>
<chapter>
<chapter id="apple-advanced-typography-api">
<title>Apple Advanced Typography API</title>
<xi:include href="xml/hb-aat-layout.xml"/>
</chapter>
<chapter>
<chapter id="integration-api">
<title>Integration API</title>
<xi:include href="xml/hb-coretext.xml"/>
<xi:include href="xml/hb-ft.xml"/>
<xi:include href="xml/hb-glib.xml"/>
<xi:include href="xml/hb-gobject.xml"/>
<xi:include href="xml/hb-graphite2.xml"/>
<xi:include href="xml/hb-icu.xml"/>
<xi:include href="xml/hb-uniscribe.xml"/>
<xi:include href="xml/hb-gdi.xml"/>
<xi:include href="xml/hb-directwrite.xml"/>
<xi:include href="xml/hb-cairo.xml"/>
</chapter>
<chapter id="style-api">
<title>Style API</title>
<xi:include href="xml/hb-style.xml"/>
</chapter>
<chapter id="subset-api">
<title>Subset API</title>
<xi:include href="xml/hb-subset.xml"/>
</chapter>
<!--chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter-->
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
<index id="deprecated-api-index"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-6-0" role="2.6.0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-5-0" role="2.5.0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-4-0" role="2.4.0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-3-0" role="2.3.0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-2-0" role="2.2.0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-6" role="1.8.6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-5" role="1.8.5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-1" role="1.8.1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-0" role="1.8.0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-7" role="1.7.7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-5" role="1.7.5"><title>Index of new symbols in 1.7.5</title><xi:include href="xml/api-index-1.7.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-6-0" role="1.6.0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-2" role="1.1.2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-0-5" role="1.0.5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-42" role="0.9.42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-41" role="0.9.41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-39" role="0.9.39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-38" role="0.9.38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-31" role="0.9.31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-30" role="0.9.30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-28" role="0.9.28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-22" role="0.9.22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-20" role="0.9.20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-11" role="0.9.11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-10" role="0.9.10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-8" role="0.9.8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-7" role="0.9.7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-5" role="0.9.5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-2" role="0.9.2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-7-1-0"><title>Index of new symbols in 7.1.0</title><xi:include href="xml/api-index-7.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-7-0-0"><title>Index of new symbols in 7.0.0</title><xi:include href="xml/api-index-7.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-6-0-0"><title>Index of new symbols in 6.0.0</title><xi:include href="xml/api-index-6.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-5-3-0"><title>Index of new symbols in 5.3.0</title><xi:include href="xml/api-index-5.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-5-0-0"><title>Index of new symbols in 5.0.0</title><xi:include href="xml/api-index-5.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-4-0"><title>Index of new symbols in 4.4.0</title><xi:include href="xml/api-index-4.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-3-0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-2-0"><title>Index of new symbols in 4.2.0</title><xi:include href="xml/api-index-4.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-1-0"><title>Index of new symbols in 4.1.0</title><xi:include href="xml/api-index-4.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-0-0"><title>Index of new symbols in 4.0.0</title><xi:include href="xml/api-index-4.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-4-0"><title>Index of new symbols in 3.4.0</title><xi:include href="xml/api-index-3.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-3-0"><title>Index of new symbols in 3.3.0</title><xi:include href="xml/api-index-3.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-1-0"><title>Index of new symbols in 3.1.0</title><xi:include href="xml/api-index-3.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-0-0"><title>Index of new symbols in 3.0.0</title><xi:include href="xml/api-index-3.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-1"><title>Index of new symbols in 2.9.1</title><xi:include href="xml/api-index-2.9.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-0"><title>Index of new symbols in 2.9.0</title><xi:include href="xml/api-index-2.9.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-8-2"><title>Index of new symbols in 2.8.2</title><xi:include href="xml/api-index-2.8.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-7-3"><title>Index of new symbols in 2.7.3</title><xi:include href="xml/api-index-2.7.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-6-8"><title>Index of new symbols in 2.6.8</title><xi:include href="xml/api-index-2.6.8.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-6-5"><title>Index of new symbols in 2.6.5</title><xi:include href="xml/api-index-2.6.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-6-3"><title>Index of new symbols in 2.6.3</title><xi:include href="xml/api-index-2.6.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-6-0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-5-0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-4-0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-3-0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-2-0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-1-0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-0-0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-9-0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-2"><title>Index of new symbols in 1.7.2</title><xi:include href="xml/api-index-1.7.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-6-0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-5-0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-3-3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-2-3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-0-5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-33"><title>Index of new symbols in 0.9.33</title><xi:include href="xml/api-index-0.9.33.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-26"><title>Index of new symbols in 0.9.26</title><xi:include href="xml/api-index-0.9.26.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-21"><title>Index of new symbols in 0.9.21</title><xi:include href="xml/api-index-0.9.21.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-6-0"><title>Index of new symbols in 0.6.0</title><xi:include href="xml/api-index-0.6.0.xml"><xi:fallback /></xi:include></index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</part>
<note>
<para>
The current HarfBuzz codebase 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.
</para>
<para>
Prior to 2012, the original HarfBuzz codebase (which, these days, is
referred to as <emphasis>harfbuzz-old</emphasis>) was derived from code
in <ulink url="http://freetype.org/">FreeType</ulink>,
<ulink url="http://pango.org/">Pango</ulink>, and
<ulink url="http://qt-project.org/">Qt</ulink>.
It is <emphasis>not</emphasis> 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.
</para>
<para>
To make this distinction clearer in discussions, the current HarfBuzz
codebase is sometimes referred to as <emphasis>harfbuzz-ng</emphasis>.
</para>
<para>
For reference purposes, the harfbuzz-old source tree is archived
<ulink url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>.
There are no release tarballs of harfbuzz-old whatsoever.
</para>
</note>
</book>

File diff suppressed because it is too large Load diff

64
docs/meson.build Normal file
View file

@ -0,0 +1,64 @@
if not find_program('gtkdoc-scan', required: get_option('docs')).found()
message('Not building documentation as gtk-doc was not found')
subdir_done()
endif
conf.set('HAVE_GTK_DOC', 1)
gnome = import('gnome')
docconf = configuration_data()
docconf.set('HB_VERSION', meson.project_version())
version_xml = configure_file(input: 'version.xml.in',
output: 'version.xml',
configuration: docconf)
content_files = [
'usermanual-what-is-harfbuzz.xml',
'usermanual-install-harfbuzz.xml',
'usermanual-getting-started.xml',
'usermanual-glyph-information.xml',
'usermanual-shaping-concepts.xml',
'usermanual-object-model.xml',
'usermanual-buffers-language-script-and-direction.xml',
'usermanual-fonts-and-faces.xml',
'usermanual-opentype-features.xml',
'usermanual-clusters.xml',
'usermanual-utilities.xml',
'usermanual-integration.xml',
version_xml,
]
html_images = [
'HarfBuzz.png',
'HarfBuzz.svg',
]
ignore_headers = [
'hb-features.h',
'hb-gobject.h',
'hb-gobject-enums.h',
'hb-gobject-enums-tmp.h',
'hb-gobject-structs.h',
]
gnome.gtkdoc('harfbuzz',
main_sgml: 'harfbuzz-docs.xml',
src_dir: [meson.current_source_dir() / '..' / 'src',
meson.current_build_dir() / '..' / 'src',
],
scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED',
'--ignore-decorators=HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()',
],
mkdb_args: ['--source-suffixes=h,cc',
'--xml-mode',
'--output-format=xml',
],
content_files: content_files,
html_assets: html_images,
ignore_headers: ignore_headers,
dependencies: [libharfbuzz_dep],
install: true,
check: get_option('doc_tests'),
)

294
docs/repacker.md Normal file
View file

@ -0,0 +1,294 @@
# Introduction
Several tables in the opentype format are formed internally by a graph of subtables. Parent node's
reference their children through the use of positive offsets, which are typically 16 bits wide.
Since offsets are always positive this forms a directed acyclic graph. For storage in the font file
the graph must be given a topological ordering and then the subtables packed in serial according to
that ordering. Since 16 bit offsets have a maximum value of 65,535 if the distance between a parent
subtable and a child is more then 65,535 bytes then it's not possible for the offset to encode that
edge.
For many fonts with complex layout rules (such as Arabic) it's not unusual for the tables containing
layout rules ([GSUB/GPOS](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub)) to be
larger than 65kb. As a result these types of fonts are susceptible to offset overflows when
serializing to the binary font format.
Offset overflows can happen for a variety of reasons and require different strategies to resolve:
* Simple overflows can often be resolved with a different topological ordering.
* If a subtable has many parents this can result in the link from furthest parent(s)
being at risk for overflows. In these cases it's possible to duplicate the shared subtable which
allows it to be placed closer to it's parent.
* If subtables exist which are themselves larger than 65kb it's not possible for any offsets to point
past them. In these cases the subtable can usually be split into two smaller subtables to allow
for more flexibility in the ordering.
* In GSUB/GPOS overflows from Lookup subtables can be resolved by changing the Lookup to an extension
lookup which uses a 32 bit offset instead of 16 bit offset.
In general there isn't a simple solution to produce an optimal topological ordering for a given graph.
Finding an ordering which doesn't overflow is a NP hard problem. Existing solutions use heuristics
which attempt a combination of the above strategies to attempt to find a non-overflowing configuration.
The harfbuzz subsetting library
[includes a repacking algorithm](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh)
which is used to resolve offset overflows that are present in the subsetted tables it produces. This
document provides a deep dive into how the harfbuzz repacking algorithm works.
Other implementations exist, such as in
[fontTools](https://github.com/fonttools/fonttools/blob/7af43123d49c188fcef4e540fa94796b3b44e858/Lib/fontTools/ttLib/tables/otBase.py#L72), however these are not covered in this document.
# Foundations
There's four key pieces to the harfbuzz approach:
* Subtable Graph: a table's internal structure is abstracted out into a lightweight graph
representation where each subtable is a node and each offset forms an edge. The nodes only need
to know how many bytes the corresponding subtable occupies. This lightweight representation can
be easily modified to test new ordering's and strategies as the repacking algorithm iterates.
* [Topological sorting algorithm](https://en.wikipedia.org/wiki/Topological_sorting): an algorithm
which given a graph gives a linear sorting of the nodes such that all offsets will be positive.
* Overflow check: given a graph and a topological sorting it checks if there will be any overflows
in any of the offsets. If there are overflows it returns a list of (parent, child) tuples that
will overflow. Since the graph has information on the size of each subtable it's straightforward
to calculate the final position of each subtable and then check if any offsets to it will
overflow.
* Content Aware Preprocessing: if the overflow resolver is aware of the format of the underlying
tables (eg. GSUB, GPOS) then in some cases preprocessing can be done to increase the chance of
successfully packing the graph. For example for GSUB and GPOS we can preprocess the graph and
promote lookups to extension lookups (upgrades a 16 bit offset to 32 bits) or split large lookup
subtables into two or more pieces.
* Offset resolution strategies: given a particular occurrence of an overflow these strategies
modify the graph to attempt to resolve the overflow.
# High Level Algorithm
```
def repack(graph):
graph.topological_sort()
if (graph.will_overflow())
preprocess(graph)
assign_spaces(graph)
graph.topological_sort()
while (overflows = graph.will_overflow()):
for overflow in overflows:
apply_offset_resolution_strategy (overflow, graph)
graph.topological_sort()
```
The actual code for this processing loop can be found in the function hb_resolve_overflows () of
[hb-repacker.hh](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh).
# Topological Sorting Algorithms
The harfbuzz repacker uses two different algorithms for topological sorting:
* [Kahn's Algorithm](https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm)
* Sorting by shortest distance
Kahn's algorithm is approximately twice as fast as the shortest distance sort so that is attempted
first (only on the first topological sort). If it fails to eliminate overflows then shortest distance
sort will be used for all subsequent topological sorting operations.
## Shortest Distance Sort
This algorithm orders the nodes based on total distance to each node. Nodes with a shorter distance
are ordered first.
The "weight" of an edge is the sum of the size of the sub-table being pointed to plus 2^16 for a 16 bit
offset and 2^32 for a 32 bit offset.
The distance of a node is the sum of all weights along the shortest path from the root to that node
plus a priority modifier (used to change where nodes are placed by moving increasing or
decreasing the effective distance). Ties between nodes with the same distance are broken based
on the order of the offset in the sub table bytes.
The shortest distance to each node is determined using
[Djikstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). Then the topological
ordering is produce by applying a modified version of Kahn's algorithm that uses a priority queue
based on the shortest distance to each node.
## Optimizing the Sorting
The topological sorting operation is the core of the repacker and is run on each iteration so it needs
to be as fast as possible. There's a few things that are done to speed up subsequent sorting
operations:
* The number of incoming edges to each node is cached. This is required by the Kahn's algorithm
portion of both sorts. Where possible when the graph is modified we manually update the cached
edge counts of affected nodes.
* The distance to each node is cached. Where possible when the graph is modified we manually update
the cached distances of any affected nodes.
Caching these values allows the repacker to avoid recalculating them for the full graph on each
iteration.
The other important factor to speed is a fast priority queue which is a core datastructure to
the topological sorting algorithm. Currently a basic heap based queue is used. Heap based queue's
don't support fast priority decreases, but that can be worked around by just adding redundant entries
to the priority queue and filtering the older ones out when poppping off entries. This is based
on the recommendations in
[a study of the practical performance of priority queues in Dijkstra's algorithm](https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf)
## Special Handling of 32 bit Offsets
If a graph contains multiple 32 bit offsets then the shortest distance sorting will be likely be
suboptimal. For example consider the case where a graph contains two 32 bit offsets that each point
to a subgraph which are not connected to each other. The shortest distance sort will interleave the
subtables of the two subgraphs, potentially resulting in overflows. Since each of these subgraphs are
independent of each other, and 32 bit offsets can point extremely long distances a better strategy is
to pack the first subgraph in it's entirety and then have the second subgraph packed after with the 32
bit offset pointing over the first subgraph. For example given the graph:
```
a--- b -- d -- f
\
\_ c -- e -- g
```
Where the links from a to b and a to c are 32 bit offsets, the shortest distance sort would be:
```
a, b, c, d, e, f, g
```
If nodes d and e have a combined size greater than 65kb then the offset from d to f will overflow.
A better ordering is:
```
a, b, d, f, c, e, g
```
The ability for 32 bit offsets to point long distances is utilized to jump over the subgraph of
b which gives the remaining 16 bit offsets a better chance of not overflowing.
The above is an ideal situation where the subgraphs are disconnected from each other, in practice
this is often not this case. So this idea can be generalized as follows:
If there is a subgraph that is only reachable from one or more 32 bit offsets, then:
* That subgraph can be treated as an independent unit and all nodes of the subgraph packed in isolation
from the rest of the graph.
* In a table that occupies less than 4gb of space (in practice all fonts), that packed independent
subgraph can be placed anywhere after the parent nodes without overflowing the 32 bit offsets from
the parent nodes.
The sorting algorithm incorporates this via a "space" modifier that can be applied to nodes in the
graph. By default all nodes are treated as being in space zero. If a node is given a non-zero space, n,
then the computed distance to the node will be modified by adding `n * 2^32`. This will cause that
node and it's descendants to be packed between all nodes in space n-1 and space n+1. Resulting in a
topological sort like:
```
| space 0 subtables | space 1 subtables | .... | space n subtables |
```
The assign_spaces() step in the high level algorithm is responsible for identifying independent
subgraphs and assigning unique spaces to each one. More information on the space assignment can be
found in the next section.
# Graph Preprocessing
For certain table types we can preprocess and modify the graph structure to reduce the occurences
of overflows. Currently the repacker implements preprocessing only for GPOS and GSUB tables.
## GSUB/GPOS Table Splitting
The GSUB/GPOS preprocessor scans each lookup subtable and determines if the subtable's children are
so large that no overflow resolution is possible (for example a single subtable that exceeds 65kb
cannot be pointed over). When such cases are detected table splitting is invoked:
* The subtable is first analyzed to determine the smallest number of split points that will allow
for successful offset overflow resolution.
* Then the subtable in the graph representation is modified to actually perform the split at the
previously computed split points. At a high level splits are done by inserting new subtables
which contain a subset of the data of the original subtable and then shrinking the original subtable.
Table splitting must be aware of the underlying format of each subtable type and thus needs custom
code for each subtable type. Currently subtable splitting is only supported for GPOS subtable types.
## GSUB/GPOS Extension Lookup Promotion
In GSUB/GPOS tables lookups can be regular lookups which use 16 bit offsets to the children subtables
or extension lookups which use 32 bit offsets to the children subtables. If the sub graph of all
regular lookups is too large then it can be difficult to find an overflow free configuration. This
can be remedied by promoting one or more regular lookups to extension lookups.
During preprocessing the graph is scanned to determine the size of the subgraph of regular lookups.
If the graph is found to be too big then the analysis finds a set of lookups to promote to reduce
the subgraph size. Lastly the graph is modified to convert those lookups to extension lookups.
# Offset Resolution Strategies
## Space Assignment
The goal of space assignment is to find connected subgraphs that are only reachable via 32 bit offsets
and then assign each such subgraph to a unique non-zero space. The algorithm is roughly:
1. Collect the set, `S`, of nodes that are children of 32 bit offsets.
2. Do a directed traversal from each node in `S` and collect all encountered nodes into set `T`.
Mark all nodes in the graph that are not in `T` as being in space 0.
3. Set `next_space = 1`.
4. While set `S` is not empty:
a. Pick a node `n` in set `S` then perform an undirected graph traversal and find the set `Q` of
nodes that are reachable from `n`.
b. During traversal if a node, `m`, has a edge to a node in space 0 then `m` must be duplicated
to disconnect it from space 0.
d. Remove all nodes in `Q` from `S` and assign all nodes in `Q` to `next_space`.
c. Increment `next_space` by one.
## Manual Iterative Resolutions
For each overflow in each iteration the algorithm will attempt to apply offset overflow resolution
strategies to eliminate the overflow. The type of strategy applied is dependent on the characteristics
of the overflowing link:
* If the overflowing offset is inside a space other than space 0 and the subgraph space has more
than one 32 bit offset pointing into the subgraph then subdivide the space by moving subgraph
from one of the 32 bit offsets into a new space via the duplication of shared nodes.
* If the overflowing offset is pointing to a subtable with more than one incoming edge: duplicate
the node so that the overflowing offset is pointing at it's own copy of that node.
* Otherwise, attempt to move the child subtable closer to it's parent. This is accomplished by
raising the priority of all children of the parent. Next time the topological sort is run the
children will be ordered closer to the parent.
# Test Cases
The harfbuzz repacker has tests defined using generic graphs: https://github.com/harfbuzz/harfbuzz/blob/main/src/test-repacker.cc
# Future Improvements
Currently for GPOS tables the repacker implementation is sufficient to handle both subsetting and the
general case of font compilation repacking. However for GSUB the repacker is only sufficient for
subsetting related overflows. To enable general case repacking of GSUB, support for splitting of
GSUB subtables will need to be added. Other table types such as COLRv1 shouldn't require table
splitting due to the wide use of 24 bit offsets throughout the table.
Beyond subtable splitting there are a couple of "nice to have" improvements, but these are not required
to support the general case:
* Extension demotion: currently extension promotion is supported but in some cases if the non-extension
subgraph is underfilled then packed size can be reduced by demoting extension lookups back to regular
lookups.
* Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
should use a heuristic (based on parent and child subtable sizes) to decide if the children's
priority should be increased or the parent's priority decreased.

178
docs/serializer.md Normal file
View file

@ -0,0 +1,178 @@
# Introduction
In hb-subset serialization is the process of writing the subsetted font
tables out to actual bytes in the final format. All serialization works
through an object called the serialize context
([hb_serialize_context_t](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-serialize.hh)).
Internally the serialize context holds a fixed size memory buffer. For simple
tables the final bytes are written into the buffer sequentially to produce
the final serialized bytes.
## Simple Tables
Simple tables are tables that do not use offset graphs.
To write a struct into the serialization context, first you call an
allocation method on the context which requests a writable array of bytes of
a fixed size. If the requested array will not exceed the bounds of the fixed
buffer the serializer will return a pointer to the next unwritten portion
of the buffer. Then the struct is cast onto the returned pointer and values
are written to the structs fields.
Internally the serialization context ends up looking like:
```
+-------+-------+-----+-------+--------------+
| Obj 1 | Obj 2 | ... | Obj N | Unused Space |
+-------+-------+-----+-------+--------------+
```
Here Obj N, is the object currently being written.
## Complex Tables
Complex tables are made up of graphs of objects, where offset's are used
to form the edges of the graphs. Each object is a continuous slice of bytes
that contains zero or more offsets pointing to more objects.
In this case the serialization buffer has a different layout:
```
|- in progress objects -| |--- packed objects --|
+-----------+-----------+--------------+-------+-----+-------+
| Obj n+2 | Obj n+1 | Unused Space | Obj n | ... | Obj 0 |
+-----------+-----------+--------------+-------+-----+-------+
|-----------------------> <---------------------|
```
The buffer holds two stacks:
1. In progress objects are held in a stack starting from the start of buffer
that grows towards the end of the buffer.
2. Packed objects are held in a stack that starts at the end of the buffer
and grows towards the start of the buffer.
Once the object on the top of the in progress stack is finished being written
its bytes are popped from the in progress stack and copied to the top of
the packed objects stack. In the example above, finalizing Obj n+1
would result in the following state:
```
+---------+--------------+---------+-------+-----+-------+
| Obj n+2 | Unused Space | Obj n+1 | Obj n | ... | Obj 0 |
+---------+--------------+---------+-------+-----+-------+
```
Each packed object is associated with an ID, it's zero based position in the packed
objects stack. In this example Obj 0, would have an ID of 0.
During serialization offsets that link from one object to another are stored
using object ids. The serialize context maintains a list of links between
objects. Each link records the parent object id, the child object id, the position
of the offset field within the parent object, and the width of the offset.
Links are always added to the current in progress object and you can only link too
objects that have been packed and thus have an ID.
### Object De-duplication
An important optimization in packing offset graphs is de-duplicating equivalent objects. If you
have two or more parent objects that point to child objects that are equivalent then you only need
to encode the child once and can have the parents point to the same child. This can significantly
reduce the final size of a serialized graph.
During packing of an inprogress object the serialization context checks if any existing packed
objects are equivalent to the object being packed. Here equivalence means the object has the
exact same bytes and all of it's links are equivalent. If an equivalent object is found the
in progress object is discarded and not copied to the packed object stack. The object id of
the equivalent object is instead returned. Thus parent objects will then link to the existing
equivalent object.
To find equivalent objects the serialization context maintains a hashmap from object to the canonical
object id.
### Link Resolution
Once all objects have been packed the next step is to assign actual values to all of the offset
fields. Prior to this point all links in the graph have been recorded using object id's. For each
link the resolver computes the offset between the parent and child and writes the offset into
the serialization buffer at the appropriate location.
### Offset Overflow Resolution
If during link resolution the resolver finds that an offsets value would exceed what can be encoded
in that offset field link resolution is aborted and the offset overflow resolver is invoked.
That process is documented [here](reapcker.md).
### Example of Complex Serialization
If we wanted to serialize the following graph:
```
a--b--d
\ /
c
```
Serializer would be called like this:
```c++
hb_serialize_context_t ctx;
struct root {
char name;
Offset16To<child> child_1;
Offset16To<child> child_2;
}
struct child {
char name;
Offset16To<char> leaf;
}
// Object A.
ctx->push();
root* a = ctx->start_embed<root> ();
ctx->extend_min (a);
a->name = 'a';
// Object B.
ctx->push();
child* b = ctx->start_embed<child> ();
ctx->extend_min (b);
b->name = 'b';
// Object D.
ctx->push();
*ctx->allocate_size<char> (1) = 'd';
unsigned d_id = ctx->pop_pack ();
ctx->add_link (b->leaf, d_id);
unsigned b_id = ctx->pop_pack ();
// Object C
ctx->push();
child* c = ctx->start_embed<child> ();
ctx->extend_min (c);
c->name = 'c';
// Object D.
ctx->push();
*ctx->allocate_size<char> (1) = 'd';
d_id = ctx->pop_pack (); // Serializer will automatically de-dup this with the previous 'd'
ctx->add_link (c->leaf, d_id);
unsigned c_id = ctx->pop_pack ();
// Object A's links:
ctx->add_link (a->child_1, b_id);
ctx->add_link (a->child_2, c_id);
ctx->pop_pack ();
ctx->end_serialize ();
```

View file

@ -0,0 +1,228 @@
# Introduction
Subset preprocessing is a mechanism which can significantly speed up font subsetting operations.
It works by prepopulating datastructures from the source font which can be used in later subsetting
operations to more quickly produce the subset. Preprocessing is useful in cases where multiple subsets
will be cut from the same source font.
# Usage
```c++
hb_face_t* preprocessed = hb_subset_preprocess (source_face);
...
hb_face_t* subset = hb_subset_or_fail (preprocessed, subset_input);
```
# Additional Details
* A subset produced from a preprocessed face should be identical to a subset produced from only the
original face. The preprocessor does not change the functionality of the subsetter, just speeds
things up.
* The preprocessing operation may take longer than the time it takes to produce a subset from the
source font. Thus the main performance gains are made when a preprocessed face is reused for
multiple subsetting operations.
* Currently the largest performance gains are seen when using a preprocessed face for CFF subsetting.
* The preprocessed face may contain references to the memory backing the source face. If this memory
is fully owned by a harfbuzz hb_blob_t* then it will automatically be kept alive for the lifetime
of the preprocessed face. However, if this memory is not fully owned by a harfbuzz hb_blob_t* then
it is necessary to ensure that the memory is kept alive for the lifetime of the preprocessed face.
# Performance Improvements
Here is the performance difference of producing a subset with a preprocessed face vs producing
a subset with the source face:
Benchmark | Delta Time (%)
----------|-----------------
BM_subset/subset_glyphs/Roboto-Regular.ttf/10_median|-56%
BM_subset/subset_glyphs/Roboto-Regular.ttf/64_median|-33%
BM_subset/subset_glyphs/Roboto-Regular.ttf/512_median|-28%
BM_subset/subset_glyphs/Roboto-Regular.ttf/1000_median|-11%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/10_median|-56%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/64_median|-33%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/512_median|-21%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/1000_median|-9%
BM_subset/subset_glyphs/Amiri-Regular.ttf/10_median|-67%
BM_subset/subset_glyphs/Amiri-Regular.ttf/64_median|-48%
BM_subset/subset_glyphs/Amiri-Regular.ttf/512_median|-21%
BM_subset/subset_glyphs/Amiri-Regular.ttf/4096_median|-9%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/10_median|-66%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/64_median|-50%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/512_median|-8%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/4096_median|-9%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/10_median|-85%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/64_median|-71%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/512_median|-3%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/1400_median|4%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-84%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-72%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|0%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|0%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/10_median|-30%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/64_median|-24%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/512_median|-3%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/1000_median|-3%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-30%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-3%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|-5%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10_median|-96%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/64_median|-90%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/512_median|-74%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/4096_median|-25%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10000_median|-23%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10_median|-95%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/64_median|-90%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/512_median|-73%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/4096_median|-24%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10000_median|-11%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10_median|-84%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/64_median|-77%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/512_median|-70%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/4096_median|-80%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10000_median|-86%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10_median|-84%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/64_median|-78%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/512_median|-71%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/10_median|-59%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/64_median|-55%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/512_median|-67%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/2000_median|-68%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/10_median|-60%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/64_median|-58%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/512_median|-72%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/2000_median|-71%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/10_median|-70%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/64_median|-64%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/300_median|-73%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/10_median|-71%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/64_median|-68%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/300_median|-72%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/10_median|-90%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/64_median|-82%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/512_median|-31%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/4096_median|-9%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/6000_median|-22%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/10_median|-88%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/64_median|-83%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/512_median|-31%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/4096_median|-16%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/6000_median|-18%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/10_median|-44%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/64_median|-18%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/512_median|-2%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/900_median|-6%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/10_median|-45%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/64_median|-17%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/512_median|-15%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/900_median|-3%
BM_subset/subset_codepoints/Roboto-Regular.ttf/10_median|-20%
BM_subset/subset_codepoints/Roboto-Regular.ttf/64_median|-16%
BM_subset/subset_codepoints/Roboto-Regular.ttf/512_median|-12%
BM_subset/subset_codepoints/Roboto-Regular.ttf/1000_median|-10%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/10_median|-24%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/64_median|-14%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/512_median|-15%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/1000_median|-9%
BM_subset/subset_codepoints/Amiri-Regular.ttf/10_median|-51%
BM_subset/subset_codepoints/Amiri-Regular.ttf/64_median|-37%
BM_subset/subset_codepoints/Amiri-Regular.ttf/512_median|-12%
BM_subset/subset_codepoints/Amiri-Regular.ttf/4096_median|-1%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/10_median|-49%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/64_median|-35%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/512_median|-6%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/4096_median|-1%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/10_median|-82%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/64_median|-9%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/512_median|0%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/1400_median|0%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-82%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-13%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|-3%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|2%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/10_median|-40%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/64_median|-26%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/512_median|-5%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/1000_median|3%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-43%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-2%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|2%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10_median|-83%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/64_median|-67%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/512_median|-39%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/4096_median|-20%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10000_median|-25%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10_median|-83%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/64_median|-65%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/512_median|-42%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/4096_median|-34%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10000_median|-21%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10_median|-69%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/64_median|-69%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/512_median|-70%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/4096_median|-84%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10000_median|-83%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10_median|-71%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/64_median|-68%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/512_median|-70%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/10_median|-45%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/64_median|-48%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/512_median|-57%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/2000_median|-66%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/10_median|-43%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/64_median|-50%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/512_median|-63%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/2000_median|-72%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/10_median|-69%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/64_median|-66%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/300_median|-74%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/10_median|-70%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/64_median|-71%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/300_median|-75%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/10_median|-66%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/64_median|-46%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/512_median|-15%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/4096_median|-5%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/6000_median|-16%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/10_median|-66%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/64_median|-45%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/512_median|-14%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/4096_median|-11%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/6000_median|-27%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/10_median|-38%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/64_median|-9%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/512_median|-3%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/900_median|-16%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/10_median|-39%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/64_median|-12%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/512_median|-4%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/900_median|-2%
BM_subset/instance/MPLUS1-Variable.ttf/10_median|-68%
BM_subset/instance/MPLUS1-Variable.ttf/64_median|-45%
BM_subset/instance/MPLUS1-Variable.ttf/512_median|-18%
BM_subset/instance/MPLUS1-Variable.ttf/4096_median|-2%
BM_subset/instance/MPLUS1-Variable.ttf/6000_median|4%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/10_median|-69%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/64_median|-46%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/512_median|-11%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/4096_median|4%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/6000_median|-5%
BM_subset/instance/RobotoFlex-Variable.ttf/10_median|-34%
BM_subset/instance/RobotoFlex-Variable.ttf/64_median|-12%
BM_subset/instance/RobotoFlex-Variable.ttf/512_median|6%
BM_subset/instance/RobotoFlex-Variable.ttf/900_median|-6%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/10_median|-33%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/64_median|-11%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/512_median|3%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/900_median|0%

View file

@ -136,10 +136,12 @@
determine which glyph to return.
</para>
<para>
The safest approach is to add all of the text available, then
use <parameter>item_offset</parameter> and
The safest approach is to add all of the text available (even
if your text contains a mix of scripts, directions, languages
and fonts), then use <parameter>item_offset</parameter> and
<parameter>item_length</parameter> to indicate which characters you
want shaped, so that HarfBuzz has access to any context.
want shaped (which must all have the same script, direction,
language and font), so that HarfBuzz has access to any context.
</para>
<para>
You can also add Unicode code points directly with
@ -193,7 +195,7 @@
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
</programlisting>
<para>
However, since these properties are often the repeated for
However, since these properties are often repeated for
multiple text runs, you can also save them in a
<literal>hb_segment_properties_t</literal> for reuse:
</para>

View file

@ -182,8 +182,7 @@
</para>
<itemizedlist>
<listitem>
<para><emphasis>Level 0</emphasis> is the default and
reproduces the behavior of the old HarfBuzz library.
<para><emphasis>Level 0</emphasis> is the default.
</para>
<para>
The distinguishing feature of level 0 behavior is that, at
@ -194,7 +193,7 @@
as well as the <emphasis>Zero Width Joiner</emphasis> and
<emphasis>Zero Width Non-Joiner</emphasis> code points, are
assigned the cluster value of the closest preceding code
point from <emphasis>different</emphasis> category.
point from <emphasis>different</emphasis> category.
</para>
<para>
In essence, whenever a base character is followed by a mark
@ -206,6 +205,11 @@
url="https://www.unicode.org/reports/tr29/#Regex_Definitions">Unicode
Technical Report 29</ulink>.
</para>
<para>
This cluster level is suitable for code that likes to use
HarfBuzz cluster values as an approximation of the Unicode
Grapheme Cluster Boundaries as well.
</para>
<para>
Client programs can specify level 0 behavior for a buffer by
setting its <literal>cluster_level</literal> to
@ -220,13 +224,13 @@
implement backward compatibility with the old HarfBuzz.
</para>
<para>
Level 1 differs from level 0 by not merging the
<emphasis>Level 1</emphasis> differs from level 0 by not merging the
clusters of marks and other modifier code points with the
preceding "base" code point's cluster. By preserving the
separate cluster values of these marks and modifier code
points, script shapers can perform additional operations
that might lead to improved results (for example, reordering
a sequence of marks).
that might lead to improved results (for example, coloring
mark glyphs differently than their base).
</para>
<para>
Client programs can specify level 1 behavior for a buffer by
@ -242,7 +246,7 @@
</para>
<para>
This difference can be seen most clearly when HarfBuzz processes
ligature substitutions and glyph decompositions. In level 0
ligature substitutions and glyph decompositions. In level 0
and level 1, ligatures and glyph decomposition both involve
merging clusters; in level 2, neither of these operations
triggers a merge.
@ -259,7 +263,7 @@
assign initial cluster values in a buffer by reusing the indices
of the code points in the input text. This gives a sequence of
cluster values that is monotonically increasing (for example,
0,1,2,3,4).
0,1,2,3,4).
</para>
<para>
It is not <emphasis>required</emphasis> that the cluster values
@ -314,7 +318,7 @@
</listitem>
</itemizedlist>
</section>
<section id="a-clustering-example-for-levels-0-and-1">
<title>A clustering example for levels 0 and 1</title>
<para>
@ -419,7 +423,7 @@
<section id="reordering-in-levels-0-and-1">
<title>Reordering in levels 0 and 1</title>
<para>
Another common operation in the more complex shapers is glyph
Another common operation in some shapers is glyph
reordering. In order to maintain a monotonic cluster sequence
when glyph reordering takes place, HarfBuzz merges the clusters
of everything in the reordering sequence.

View file

@ -55,7 +55,7 @@
shaping. The typeface must be set to a specific point size in
order for some details (such as hinting) to work. In addition,
if the font file in question is an OpenType Variable Font, then
you may need to specify one or variation-axis settings (or a
you may need to specify one or more variation-axis settings (or a
named instance) in order to get the output you need.
</para>
<para>
@ -256,22 +256,34 @@
<para>
<function>hb_font_get_glyph_from_name_func_t</function>: returns
the glyph index that corresponds to a given glyph name.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_draw_glyph_func_t</function>: gets the outlines
of a glyph (by calling #hb_draw_funcs_t callbacks).
</para>
</listitem>
<listitem>
<para>
<function>hb_font_paint_glyph_func_t</function>: paints a glyph
(by calling #hb_paint_funcs_t callbacks).
</para>
</listitem>
</itemizedlist>
<para>
You can fetch the font-functions configuration for a font object
by calling <function>hb_font_get_font_funcs()</function>:
You can create new font-functions by calling
<function>hb_font_funcs_create()</function>:
</para>
<programlisting language="C">
hb_font_funcs_t *ffunctions;
ffunctions = hb_font_get_font_funcs (font);
hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
hb_font_set_funcs (font, ffunctions, font_data, destroy);
</programlisting>
<para>
The individual methods can each be replaced with their own setter
The individual methods can each be set with their own setter
function, such as
<function>hb_font_funcs_set_nominal_glyph_func(*ffunctions,
func, *user_data, destroy)</function>.
<function>hb_font_funcs_set_nominal_glyph_func(ffunctions,
func, user_data, destroy)</function>.
</para>
<para>
Font-functions structures can be reused for multiple font
@ -291,6 +303,20 @@
programs from changing the configuration and introducing
inconsistencies and errors downstream.
</para>
<para>
To override only some functions while using the default implementation
for the others, you will need to create a sub-font. By default, the
sub-font uses the font functions of its parent except for the functions
that were explicitly set. The following code will override only the
<function>hb_font_get_nominal_glyph_func_t</function> for the sub-font:
</para>
<programlisting language="C">
hb_font_t *subfont = hb_font_create_sub_font (font)
hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
hb_font_funcs_set_nominal_glyph_func (ffunctions, func, user_data, destroy);
hb_font_set_funcs (subfont, ffunctions, font_data, destroy);
hb_font_funcs_destroy (ffunctions);
</programlisting>
</section>
<section id="fonts-and-faces-native-opentype">
@ -361,20 +387,6 @@
</para>
</section>
<!-- Commenting out FreeType integration section-holder for now. May move
to the full-blown Integration Chapter. -->
<!-- <section id="fonts-and-faces-freetype">
<title>Using FreeType</title>
<para>
</para>
<para>
</para>
</section> -->
<section id="fonts-and-faces-variable">
<title>Working with OpenType Variable Fonts</title>
<para>
@ -441,13 +453,66 @@
range actually implemented in the font's variation axis. After
all, a font might only provide lighter-than-regular weights, and
setting a heavier value on the <literal>wght</literal> axis will
not change that.
not change that.
</para>
<para>
Once your variation settings are specified on your font object,
however, shaping with a variable font is just like shaping a
static font.
</para>
<para>
In addition to providing the variation axes themselves, fonts may also
pre-define certain variation coordinates as named instances. HarfBuzz
makes these coordinates (and their associated names) available via
<function>hb_ot_var_named_instance_get_design_coords()</function> and
<function>hb_ot_var_named_instance_get_subfamily_name_id()</function>.
</para>
<para>
Applications should treat named instances like multiple independent,
static fonts.
</para>
</section>
<section id="glyphs-and-rendering">
<title>Glyphs and rendering</title>
<para>
The main purpose of HarfBuzz is shaping, which creates a list of positioned
glyphs as output. The remaining task for text layout is to convert this list
into rendered output. While HarfBuzz does not handle rasterization of glyphs
per se, it does have APIs that provide access to the font data that is needed
to perform this task.
</para>
<para>
Traditionally, the shapes of glyphs in scalable fonts are provided as quadratic
or cubic Beziér curves defining outlines to be filled. To obtain the outlines
for a glyph, call <function>hb_font_draw_glyph()</function> and pass a
<type>hb_draw_funcs_t</type> struct. The callbacks in that struct will be called
for each segment of the outline. Note that this API provides access to outlines
as they are defined in the font, without applying hinting to fit the curves
to the pixel grid.
</para>
<para>
Fonts may provide pre-rendered images for glyphs instead of or in addition to
outlines. This is most common for fonts that contain colored glyphs, such as
Emoji. To access these images, use <function>hb_ot_color_reference_png()</function>
or <function>hb_ot_color_reference_svg()</function>.
</para>
<para>
Another way in which fonts provide colored glyphs is via paint graphs that
combine glyph outlines with gradients and allow for transformations and
compositing. In its simplest form, this can be presented as a series of
layers that are rendered on top of each other, each with its own color.
HarfBuzz has the <function>hb_ot_color_glyph_get_layers()</function> to
access glyph data in this form.
</para>
<para>
In the general case, you have to use <function>hb_font_paint_glyph()</function>
and pass a <type>hb_paint_funcs_t</type> struct with callbacks to obtain paint
graphs for glyphs that have them. The <function>hb_font_paint_glyph()</function>
API can handle outline and image glyphs as well, so it provides a unified API for
access to glyph rendering information.
</para>
</section>
</chapter>

View file

@ -6,7 +6,7 @@
]>
<chapter id="getting-started">
<title>Getting started with HarfBuzz</title>
<section>
<section id="an-overview-of-the-harfbuzz-shaping-api">
<title>An overview of the HarfBuzz shaping API</title>
<para>
The core of the HarfBuzz shaping API is the function
@ -51,7 +51,7 @@
<para>
Although the default <function>hb_shape()</function> function is
sufficient for most use cases, a variant is also provide that
sufficient for most use cases, a variant is also provided that
lets you specify which of HarfBuzz's shapers to use on a buffer.
</para>
@ -73,7 +73,7 @@
</para>
</section>
<section>
<section id="terminology">
<title>Terminology</title>
<para>
@ -117,7 +117,7 @@
implements separate shapers for Indic, Arabic, Thai and
Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
Universal Shaping Engine (USE), and a default shaper for
non-complex scripts.
scripts with no script-specific shaping model.
</para>
</listitem>
</varlistentry>
@ -201,7 +201,7 @@
</section>
<section>
<section id="a-simple-shaping-example">
<title>A simple shaping example</title>
<para>
@ -216,6 +216,7 @@
</orderedlist>
<programlisting language="C">
#include &lt;hb.h&gt;
hb_buffer_t *buf;
buf = hb_buffer_create();
hb_buffer_add_utf8(buf, text, -1, 0, -1);
@ -235,15 +236,14 @@
<orderedlist numeration="arabic">
<listitem override="3">
<para>
Create a face and a font, using FreeType for now.
Create a face and a font from a font file.
</para>
</listitem>
</orderedlist>
<programlisting language="C">
#include &lt;hb-ft.h&gt;
FT_New_Face(ft_library, font_path, index, &amp;face);
FT_Set_Char_Size(face, 0, 1000, 0, 0);
hb_font_t *font = hb_ft_font_create(face);
hb_blob_t *blob = hb_blob_create_from_file(filename); /* or hb_blob_create_from_file_or_fail() */
hb_face_t *face = hb_face_create(blob, 0);
hb_font_t *font = hb_font_create(face);
</programlisting>
<orderedlist numeration="arabic">
<listitem override="4">
@ -263,6 +263,7 @@
</listitem>
</orderedlist>
<programlisting language="C">
unsigned int glyph_count;
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
@ -274,13 +275,15 @@
</listitem>
</orderedlist>
<programlisting language="C">
for (i = 0; i &lt; glyph_count; ++i) {
glyphid = glyph_info[i].codepoint;
x_offset = glyph_pos[i].x_offset / 64.0;
y_offset = glyph_pos[i].y_offset / 64.0;
x_advance = glyph_pos[i].x_advance / 64.0;
y_advance = glyph_pos[i].y_advance / 64.0;
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
hb_position_t cursor_x = 0;
hb_position_t cursor_y = 0;
for (unsigned int i = 0; i &lt; glyph_count; i++) {
hb_codepoint_t glyphid = glyph_info[i].codepoint;
hb_position_t x_offset = glyph_pos[i].x_offset;
hb_position_t y_offset = glyph_pos[i].y_offset;
hb_position_t x_advance = glyph_pos[i].x_advance;
hb_position_t y_advance = glyph_pos[i].y_advance;
/* draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); */
cursor_x += x_advance;
cursor_y += y_advance;
}
@ -294,7 +297,9 @@
</orderedlist>
<programlisting language="C">
hb_buffer_destroy(buf);
hb_font_destroy(hb_ft_font);
hb_font_destroy(font);
hb_face_destroy(face);
hb_blob_destroy(blob);
</programlisting>
<para>

View file

@ -11,27 +11,20 @@
<title id="download.title">Downloading HarfBuzz</title>
<para>
The HarfBuzz source code is hosted at <ulink
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>. The
same source tree is also available at the
<ulink
url="http://cgit.freedesktop.org/harfbuzz/">Freedesktop.org</ulink>
site.
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
</para>
<para>
Tarball releases and Win32 binary bundles (which include the
libharfbuzz DLL, hb-view.exe, hb-shape.exe, and all
dependencies) of HarfBuzz can be downloaded from <ulink
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz/releases</ulink>
or from
<ulink url="http://www.freedesktop.org/software/harfbuzz/release/">Freedesktop.org</ulink>.
url="https://github.com/harfbuzz/harfbuzz/releases">github.com/harfbuzz/harfbuzz/releases</ulink>.
</para>
<para>
Release notes are posted with each new release to provide an
overview of the changes. The project <ulink url="https://github.com/harfbuzz/harfbuzz/issues">tracks bug
reports and other issues</ulink> on GitHub. Discussion and
questions are welcome on the <ulink
url="http://freedesktop.org/mailman/listinfo/harfbuzz/">HarfBuzz
mailing list</ulink>.
questions are welcome on <ulink
url="https://github.com/harfbuzz/harfbuzz/discussions">GitHub</ulink> as well.
</para>
<para>
The API included in the <filename
@ -56,13 +49,9 @@
</para>
<para>
For example, on an Ubuntu or Debian system, you would run:
<programlisting>
<command>sudo apt install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
</programlisting>
<programlisting><command>sudo apt install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package></programlisting>
On Fedora, RHEL, CentOS, or other Red-Hat&ndash;based systems, you would run:
<programlisting>
<command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package>
</programlisting>
<programlisting><command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package></programlisting>
</para>
@ -77,8 +66,8 @@
</para>
<para>
From a shell in the top-level directory of the extracted source
code, you can run <command>./configure</command> followed by
<command>make</command> as with any other standard package.
code, you can run <command>meson build</command> followed by
<command>meson compile -C build</command> as with any other standard package.
</para>
<para>
This should leave you with a shared
@ -91,25 +80,19 @@
<emphasis>(2)(b)</emphasis> If you are building from the source in the HarfBuzz git
repository, rather than installing from a downloaded tarball
release, then you must install two more auxiliary tools before you
can build for the first time: <package>pkg-config</package> and
<ulink url="http://www.complang.org/ragel/">ragel</ulink>.
can build for the first time: <package>pkg-config</package>.
</para>
<para>
On Ubuntu or Debian, run:
<programlisting>
<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
</programlisting>
<programlisting><command>sudo apt-get install</command> <package>meson pkg-config gtk-doc-tools</package></programlisting>
On Fedora, RHEL, CentOS, run:
<programlisting>
<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
</programlisting>
<programlisting><command>sudo yum install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
</para>
<para>
With <package>pkg-config</package> and <package>ragel</package>
installed, you can now run <command>./autogen.sh</command>,
followed by <command>./configure</command> and
<command>make</command> to build HarfBuzz.
With <package>pkg-config</package> installed, you can now run
<command>meson build</command> then
<command>meson compile -C build</command> to build HarfBuzz.
</para>
</section>
@ -118,18 +101,11 @@
<title>Building on Windows</title>
<para>
On Windows, consider using Microsoft's free <ulink
url="https://github.com/Microsoft/vcpkg">vcpkg</ulink> utility
to build HarfBuzz, its dependencies, and other open-source
libraries.
</para>
<para>
If you need to build HarfBuzz from source, first put the
<package>ragel</package> binary on your
<literal>PATH</literal>, then follow the appveyor CI cmake
<ulink
url="https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml">build
instructions</ulink>.
<ulink url="https://mesonbuild.com/Getting-meson.html">Install meson</ulink>
and run (from the console) <command>meson build</command> (by default
bundled dependencies are not built, <command>--wrap-mode=default</command>
overrides this), then <command>meson compile -C build</command> to
build HarfBuzz.
</para>
</section>
@ -146,15 +122,11 @@
<emphasis>(1)</emphasis> You must first install the
development packages for FreeType, Cairo, and GLib. If you are
using MacPorts, you should run:
<programlisting>
<command>sudo port install</command> <package>freetype glib2 cairo</package>
</programlisting>
<programlisting><command>sudo port install</command> <package>freetype glib2 cairo</package></programlisting>
</para>
<para>
If you are using Homebrew, you should run:
<programlisting>
<command>brew install</command> <package>freetype glib cairo</package>
</programlisting>
<programlisting><command>brew install</command> <package>freetype glib cairo</package></programlisting>
</para>
<para>
<emphasis>(2)</emphasis> The next step depends on whether you are building from the
@ -165,13 +137,9 @@
<emphasis>(2)(a)</emphasis> If you are installing HarfBuzz
from a downloaded tarball release, extract the tarball and
open a Terminal in the extracted source-code directory. Run:
<programlisting>
<command>./configure</command>
</programlisting>
<programlisting><command>meson build</command></programlisting>
followed by:
<programlisting>
<command>make</command>
</programlisting>
<programlisting><command>meson compile -C build</command></programlisting>
to build HarfBuzz.
</para>
<para>
@ -182,30 +150,20 @@
</para>
<para>If you are
using MacPorts, you should run:
<programlisting>
<command>sudo port install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
</programlisting>
<programlisting><command>sudo port install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
to install the build dependencies.
</para>
<para>If you are using Homebrew, you should run:
<programlisting>
<command>brew install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
</programlisting>
<programlisting><command>brew install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
Finally, you can run:
<programlisting>
<command>./autogen.sh</command>
</programlisting>
<programlisting><command>meson build</command></programlisting>
</para>
<para>
<emphasis>(3)</emphasis> You can now build HarfBuzz (on either
a MacPorts or a Homebrew system) by running:
<programlisting>
<command>./configure</command>
</programlisting>
<programlisting><command>meson build</command></programlisting>
followed by:
<programlisting>
<command>make</command>
</programlisting>
<programlisting><command>meson compile -C build</command></programlisting>
</para>
<para>
This should leave you with a shared
@ -227,22 +185,9 @@
</para>
<variablelist>
<?dbfo list-presentation="blocks"?>
<?dbfo list-presentation="blocks"?>
<varlistentry>
<term><command>--with-libstdc++</command></term>
<listitem>
<para>
Allow linking with libstdc++. <emphasis>(Default = no)</emphasis>
</para>
<para>
This option enables or disables linking HarfBuzz to the
system's libstdc++ library.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>--with-glib</command></term>
<term><command>-Dglib=enabled</command></term>
<listitem>
<para>
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
@ -258,7 +203,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-gobject</command></term>
<term><command>-Dgobject=enabled</command></term>
<listitem>
<para>
Use <ulink url="https://developer.gnome.org/gobject/stable/">GObject</ulink>. <emphasis>(Default = no)</emphasis>
@ -274,7 +219,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-cairo</command></term>
<term><command>-Dcairo=enabled</command></term>
<listitem>
<para>
Use <ulink url="https://cairographics.org/">Cairo</ulink>. <emphasis>(Default = auto)</emphasis>
@ -293,27 +238,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-fontconfig</command></term>
<listitem>
<para>
Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
</para>
<para>
This option enables or disables usage of the Fontconfig
library, which provides font-matching functions and
provides access to font properties. The default setting
is to check for the presence of Fontconfig and, if it is
found, build with Fontconfig support.
</para>
<para>
Note: Fontconfig is used only by the HarfBuzz
command-line utilities, and not by the HarfBuzz library.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>--with-icu</command></term>
<term><command>-Dicu=enabled</command></term>
<listitem>
<para>
Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
@ -331,7 +256,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-graphite2</command></term>
<term><command>-Dgraphite=enabled</command></term>
<listitem>
<para>
Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
@ -345,7 +270,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-freetype</command></term>
<term><command>-Dfreetype=enabled</command></term>
<listitem>
<para>
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
@ -360,7 +285,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-uniscribe</command></term>
<term><command>-Dgdi=enabled</command></term>
<listitem>
<para>
Use the <ulink
@ -378,7 +303,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-directwrite</command></term>
<term><command>-Ddirectwrite=enabled</command></term>
<listitem>
<para>
Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
@ -394,7 +319,7 @@
</varlistentry>
<varlistentry>
<term><command>--with-coretext</command></term>
<term><command>-Dcoretext=enabled</command></term>
<listitem>
<para>
Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
@ -407,10 +332,10 @@
</varlistentry>
<varlistentry>
<term><command>--enable-gtk-doc</command></term>
<term><command>-Ddocs=enabled</command></term>
<listitem>
<para>
Use <ulink url="https://www.gtk.org/gtk-doc/">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
Use <ulink url="https://github.com/GNOME/gtk-doc">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
</para>
<para>
This option enables the building of the documentation.

View file

@ -0,0 +1,647 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY version SYSTEM "version.xml">
]>
<chapter id="integration">
<title>Platform Integration Guide</title>
<para>
HarfBuzz was first developed for use with the GNOME and GTK
software stack commonly found in desktop Linux
distributions. Nevertheless, it can be used on other operating
systems and platforms, from iOS and macOS to Windows. It can also
be used with other application frameworks and components, such as
Android, Qt, or application-specific widget libraries.
</para>
<para>
This chapter will look at how HarfBuzz fits into a typical
text-rendering pipeline, and will discuss the APIs available to
integrate HarfBuzz with contemporary Linux, Mac, and Windows
software. It will also show how HarfBuzz integrates with popular
external libraries like FreeType and International Components for
Unicode (ICU) and describe the HarfBuzz language bindings for
Python.
</para>
<para>
On a GNOME system, HarfBuzz is designed to tie in with several
other common system libraries. The most common architecture uses
Pango at the layer directly "above" HarfBuzz; Pango is responsible
for text segmentation and for ensuring that each input
<type>hb_buffer_t</type> passed to HarfBuzz for shaping contains
Unicode code points that share the same segment properties
(namely, direction, language, and script, but also higher-level
properties like the active font, font style, and so on).
</para>
<para>
The layer directly "below" HarfBuzz is typically FreeType, which
is used to rasterize glyph outlines at the necessary optical size,
hinting settings, and pixel resolution. FreeType provides APIs for
accessing font and face information, so HarfBuzz includes
functions to create <type>hb_face_t</type> and
<type>hb_font_t</type> objects directly from FreeType
objects. HarfBuzz can use FreeType's built-in functions for
<structfield>font_funcs</structfield> vtable in an <type>hb_font_t</type>.
</para>
<para>
FreeType's output is bitmaps of the rasterized glyphs; on a
typical Linux system these will then be drawn by a graphics
library like Cairo, but those details are beyond HarfBuzz's
control. On the other hand, at the top end of the stack, Pango is
part of the larger GNOME framework, and HarfBuzz does include APIs
for working with key components of GNOME's higher-level libraries
&mdash; most notably GLib.
</para>
<para>
For other operating systems or application frameworks, the
critical integration points are where HarfBuzz gets font and face
information about the font used for shaping and where HarfBuzz
gets Unicode data about the input-buffer code points.
</para>
<para>
The font and face information is necessary for text shaping
because HarfBuzz needs to retrieve the glyph indices for
particular code points, and to know the extents and advances of
glyphs. Note that, in an OpenType variable font, both of those
types of information can change with different variation-axis
settings.
</para>
<para>
The Unicode information is necessary for shaping because the
properties of a code point (such as its General Category (gc),
Canonical Combining Class (ccc), and decomposition) can directly
impact the shaping moves that HarfBuzz performs.
</para>
<section id="integration-glib">
<title>GNOME integration, GLib, and GObject</title>
<para>
As mentioned in the preceding section, HarfBuzz offers
integration APIs to help client programs using the
GNOME and GTK framework commonly found in desktop Linux
distributions.
</para>
<para>
GLib is the main utility library for GNOME applications. It
provides basic data types and conversions, file abstractions,
string manipulation, and macros, as well as facilities like
memory allocation and the main event loop.
</para>
<para>
Where text shaping is concerned, GLib provides several utilities
that HarfBuzz can take advantage of, including a set of
Unicode-data functions and a data type for script
information. Both are useful when working with HarfBuzz
buffers. To make use of them, you will need to include the
<filename>hb-glib.h</filename> header file.
</para>
<para>
GLib's <ulink
url="https://developer.gnome.org/glib/stable/glib-Unicode-Manipulation.html">Unicode
manipulation API</ulink> includes all the functionality
necessary to retrieve Unicode data for the
<structfield>unicode_funcs</structfield> structure of a HarfBuzz
<type>hb_buffer_t</type>.
</para>
<para>
The function <function>hb_glib_get_unicode_funcs()</function>
sets up a <type>hb_unicode_funcs_t</type> structure configured
with the GLib Unicode functions and returns a pointer to it.
</para>
<para>
You can attach this Unicode-functions structure to your buffer,
and it will be ready for use with GLib:
</para>
<programlisting language="C">
#include &lt;hb-glib.h&gt;
...
hb_unicode_funcs_t *glibufunctions;
glibufunctions = hb_glib_get_unicode_funcs();
hb_buffer_set_unicode_funcs(buf, glibufunctions);
</programlisting>
<para>
For script information, GLib uses the
<type>GUnicodeScript</type> type. Like HarfBuzz's own
<type>hb_script_t</type>, this data type is an enumeration
of Unicode scripts, but text segments passed in from GLib code
will be tagged with a <type>GUnicodeScript</type>. Therefore,
when setting the script property on a <type>hb_buffer_t</type>,
you will need to convert between the <type>GUnicodeScript</type>
of the input provided by GLib and HarfBuzz's
<type>hb_script_t</type> type.
</para>
<para>
The <function>hb_glib_script_to_script()</function> function
takes an <type>GUnicodeScript</type> script identifier as its
sole argument and returns the corresponding <type>hb_script_t</type>.
The <function>hb_glib_script_from_script()</function> does the
reverse, taking an <type>hb_script_t</type> and returning the
<type>GUnicodeScript</type> identifier for GLib.
</para>
<para>
Finally, GLib also provides a reference-counted object type called <ulink
url="https://developer.gnome.org/glib/stable/glib-Byte-Arrays.html#GBytes"><type>GBytes</type></ulink>
that is used for accessing raw memory segments with the benefits
of GLib's lifecycle management. HarfBuzz provides a
<function>hb_glib_blob_create()</function> function that lets
you create an <type>hb_blob_t</type> directly from a
<type>GBytes</type> object. This function takes only the
<type>GBytes</type> object as its input; HarfBuzz registers the
GLib <function>destroy</function> callback automatically.
</para>
<para>
The GNOME platform also features an object system called
GObject. For HarfBuzz, the main advantage of GObject is a
feature called <ulink
url="https://gi.readthedocs.io/en/latest/">GObject
Introspection</ulink>. This is a middleware facility that can be
used to generate language bindings for C libraries. HarfBuzz uses it
to build its Python bindings, which we will look at in a separate section.
</para>
</section>
<section id="integration-freetype">
<title>FreeType integration</title>
<para>
FreeType is the free-software font-rendering engine included in
desktop Linux distributions, Android, ChromeOS, iOS, and multiple Unix
operating systems, and used by cross-platform programs like
Chrome, Java, and GhostScript. Used together, HarfBuzz can
perform shaping on Unicode text segments, outputting the glyph
IDs that FreeType should rasterize from the active font as well
as the positions at which those glyphs should be drawn.
</para>
<para>
HarfBuzz provides integration points with FreeType at the
face-object and font-object level and for the font-functions
virtual-method structure of a font object. These functions
make it easy for clients that use FreeType for rasterization
or font-loading, to use HarfBuzz for shaping. To use the
FreeType-integration API, include the
<filename>hb-ft.h</filename> header.
</para>
<para>
In a typical client program, you will create your
<type>hb_face_t</type> face object and <type>hb_font_t</type>
font object from a FreeType <type>FT_Face</type>. HarfBuzz
provides a suite of functions for doing this.
</para>
<para>
In the most common case, you will want to use
<function>hb_ft_font_create_referenced()</function>, which
creates both an <type>hb_face_t</type> face object and
<type>hb_font_t</type> font object (linked to that face object),
and provides lifecycle management.
</para>
<para>
It is important to note,
though, that while HarfBuzz makes a distinction between its face and
font objects, FreeType's <type>FT_Face</type> does not. After
you create your <type>FT_Face</type>, you must set its size
parameter using <function>FT_Set_Char_Size()</function>, because
an <type>hb_font_t</type> is defined as an instance of an
<type>hb_face_t</type> with size specified.
</para>
<programlisting language="C">
#include &lt;hb-ft.h&gt;
...
FT_New_Face(ft_library, font_path, index, &amp;face);
FT_Set_Char_Size(face, 0, 1000, 0, 0);
hb_font_t *font = hb_ft_font_create(face);
</programlisting>
<para>
<function>hb_ft_font_create_referenced()</function> is
the recommended function for creating an <type>hb_face_t</type> face
object. This function calls <function>FT_Reference_Face()</function>
before using the <type>FT_Face</type> and calls
<function>FT_Done_Face()</function> when it is finished using the
<type>FT_Face</type>. Consequently, your client program does not need
to worry about destroying the <type>FT_Face</type> while HarfBuzz
is still using it.
</para>
<para>
Although <function>hb_ft_font_create_referenced()</function> is
the recommended function, there is another variant for client code
where special circumstances make it necessary. The simpler
version of the function is <function>hb_ft_font_create()</function>,
which takes an <type>FT_Face</type> and an optional destroy callback
as its arguments. Because <function>hb_ft_font_create()</function>
does not offer lifecycle management, however, your client code will
be responsible for tracking references to the <type>FT_Face</type>
objects and destroying them when they are no longer needed. If you
do not have a valid reason for doing this, use
<function>hb_ft_font_create_referenced()</function>.
</para>
<para>
After you have created your font object from your
<type>FT_Face</type>, you can set or retrieve the
<structfield>load_flags</structfield> of the
<type>FT_Face</type> through the <type>hb_font_t</type>
object. HarfBuzz provides
<function>hb_ft_font_set_load_flags()</function> and
<function>hb_ft_font_get_load_flags()</function> for this
purpose. The ability to set the
<structfield>load_flags</structfield> through the font object
could be useful for enabling or disabling hinting, for example,
or to activate vertical layout.
</para>
<para>
HarfBuzz also provides a utility function called
<function>hb_ft_font_has_changed()</function> that you should
call whenever you have altered the properties of your underlying
<type>FT_Face</type>, as well as a
<function>hb_ft_get_face()</function> that you can call on an
<type>hb_font_t</type> font object to fetch its underlying <type>FT_Face</type>.
</para>
<para>
With an <type>hb_face_t</type> and <type>hb_font_t</type> both linked
to your <type>FT_Face</type>, you will typically also want to
use FreeType for the <structfield>font_funcs</structfield>
vtable of your <type>hb_font_t</type>. As a reminder, this
font-functions structure is the set of methods that HarfBuzz
will use to fetch important information from the font, such as
the advances and extents of individual glyphs.
</para>
<para>
All you need to do is call
</para>
<programlisting language="C">
hb_ft_font_set_funcs(font);
</programlisting>
<para>
and HarfBuzz will use FreeType for the font-functions in
<literal>font</literal>.
</para>
<para>
As we noted above, an <type>hb_font_t</type> is derived from an
<type>hb_face_t</type> with size (and, perhaps, other
parameters, such as variation-axis coordinates)
specified. Consequently, you can reuse an <type>hb_face_t</type>
with several <type>hb_font_t</type> objects, and HarfBuzz
provides functions to simplify this.
</para>
<para>
The <function>hb_ft_face_create_referenced()</function>
function creates just an <type>hb_face_t</type> from a FreeType
<type>FT_Face</type> and, as with
<function>hb_ft_font_create_referenced()</function> above,
provides lifecycle management for the <type>FT_Face</type>.
</para>
<para>
Similarly, there is an <function>hb_ft_face_create()</function>
function variant that does not provide the lifecycle-management
feature. As with the font-object case, if you use this version
of the function, it will be your client code's respsonsibility
to track usage of the <type>FT_Face</type> objects.
</para>
<para>
A third variant of this function is
<function>hb_ft_face_create_cached()</function>, which is the
same as <function>hb_ft_face_create()</function> except that it
also uses the <structfield>generic</structfield> field of the
<type>FT_Face</type> structure to save a pointer to the newly
created <type>hb_face_t</type>. Subsequently, function calls
that pass the same <type>FT_Face</type> will get the same
<type>hb_face_t</type> returned &mdash; and the
<type>hb_face_t</type> will be correctly reference
counted. Still, as with
<function>hb_ft_face_create()</function>, your client code must
track references to the <type>FT_Face</type> itself, and destroy
it when it is unneeded.
</para>
</section>
<section id="integration-cairo">
<title>Cairo integration</title>
<para>
Cairo is a 2D graphics library that is frequently used together
with GTK and Pango. Cairo supports rendering text using FreeType, or
by using callback-based 'user fonts'.
</para>
<para>
HarfBuzz provides integration points with cairo for fonts as well as
for buffers. To use the Cairo-integration API, link against libharfbuzz-cairo,
and include the <filename>hb-cairo.h</filename> header. For easy buildsystem
integration, HarfBuzz comes with a <filename>harfbuzz-cairo.pc</filename>
pkg-config file.
</para>
<para>
To create a <type>cairo_scaled_font_t</type> font from a HarfBuzz
<type>hb_font_t</type>, you can use <function>hb_cairo_font_face_create_for_font()</function>
or <function>hb_cairo_font_face_create_for_face()</function>. The former API
applies variations and synthetic slant from the <type>hb_font_t</type> when
rendering, the latter takes them from the <type>cairo_font_options_t</type>
that were passed when creating the <type>cairo_scaled_font_t</type>.
</para>
<para>
The Cairo fonts created in this way make use of Cairo's user-font facilities.
They can be used to render on any Cairo context, and provide full support for
font rendering features, including color. One current limitation of the
implementation is that it does not support hinting for glyph outlines.
</para>
<para>
When using color fonts with this API, the color palette index is taken from
the <type>cairo_font_options_t</type> (with new enough Cairo), and the foreground
color is extracted from the source of the Cairo context.
</para>
<para>
To render the results of shaping a piece of text, use
<function>hb_cairo_glyphs_from_buffer()</function> to obtain the glyphs in
a form that can be passed to <function>cairo_show_text_glyphs()</function> or
<function>cairo_show_glyphs()</function>.
</para>
</section>
<section id="integration-uniscribe">
<title>Uniscribe integration</title>
<para>
If your client program is running on Windows, HarfBuzz offers
an additional API that can help integrate with Microsoft's
Uniscribe engine and the Windows GDI.
</para>
<para>
Overall, the Uniscribe API covers a broader set of typographic
layout functions than HarfBuzz implements, but HarfBuzz's
shaping API can serve as a drop-in replacement for Uniscribe's shaping
functionality. In fact, one of HarfBuzz's design goals is to
accurately reproduce the same output for shaping a given text
segment that Uniscribe produces &mdash; even to the point of
duplicating known shaping bugs or deviations from the
specification &mdash; so you can be confident that your users'
documents with their existing fonts will not be affected adversely by
switching to HarfBuzz.
</para>
<para>
At a basic level, HarfBuzz's <function>hb_shape()</function>
function replaces both the <ulink url=""><function>ScriptShape()</function></ulink>
and <ulink
url="https://docs.microsoft.com/en-us/windows/desktop/api/Usp10/nf-usp10-scriptplace"><function>ScriptPlace()</function></ulink>
functions from Uniscribe.
</para>
<para>
However, whereas <function>ScriptShape()</function> returns the
glyphs and clusters for a shaped sequence and
<function>ScriptPlace()</function> returns the advances and
offsets for those glyphs, <function>hb_shape()</function>
handles both. After <function>hb_shape()</function> shapes a
buffer, the output glyph IDs and cluster IDs are returned as
an array of <structname>hb_glyph_info_t</structname> structures, and the
glyph advances and offsets are returned as an array of
<structname>hb_glyph_position_t</structname> structures.
</para>
<para>
Your client program only needs to ensure that it converts
correctly between HarfBuzz's low-level data types (such as
<type>hb_position_t</type>) and Windows's corresponding types
(such as <type>GOFFSET</type> and <type>ABC</type>). Be sure you
read the <xref linkend="buffers-language-script-and-direction"
/>
chapter for a full explanation of how HarfBuzz input buffers are
used, and see <xref linkend="shaping-buffer-output" /> for the
details of what <function>hb_shape()</function> returns in the
output buffer when shaping is complete.
</para>
<para>
Although <function>hb_shape()</function> itself is functionally
equivalent to Uniscribe's shaping routines, there are two
additional HarfBuzz functions you may want to use to integrate
the libraries in your code. Both are used to link HarfBuzz font
objects to the equivalent Windows structures.
</para>
<para>
The <function>hb_uniscribe_font_get_logfontw()</function>
function takes a <type>hb_font_t</type> font object and returns
a pointer to the <ulink
url="https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-logfontw"><type>LOGFONTW</type></ulink>
"logical font" that corresponds to it. A <type>LOGFONTW</type>
structure holds font-wide attributes, including metrics, size,
and style information.
</para>
<!--
<para>
In Uniscribe's model, the <type>SCRIPT_CACHE</type> holds the
device context, including the logical font that the shaping
functions apply.
https://docs.microsoft.com/en-us/windows/desktop/Intl/script-cache
</para>
-->
<para>
The <function>hb_uniscribe_font_get_hfont()</function> function
also takes a <type>hb_font_t</type> font object, but it returns
an <type>HFONT</type> &mdash; a handle to the underlying logical
font &mdash; instead.
</para>
<para>
<type>LOGFONTW</type>s and <type>HFONT</type>s are both needed
by other Uniscribe functions.
</para>
<para>
As a final note, you may notice a reference to an optional
<literal>uniscribe</literal> shaper back-end in the <xref
linkend="configuration" /> section of the HarfBuzz manual. This
option is not a Uniscribe-integration facility.
</para>
<para>
Instead, it is a internal code path used in the
<command>hb-shape</command> 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.
</para>
<para>
Because this back-end is only used when testing HarfBuzz
functionality, it is disabled by default when building the
HarfBuzz binaries.
</para>
</section>
<section id="integration-coretext">
<title>Core Text integration</title>
<para>
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.
</para>
<para>
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 <literal>mort</literal>, <literal>morx</literal>, and
<literal>kerx</literal>, which AAT fonts use instead of
<literal>GSUB</literal> and <literal>GPOS</literal>.
</para>
<para>
On a macOS or iOS system, the primary integration points offered
by HarfBuzz are for face objects and font objects.
</para>
<para>
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
<ulink url="https://developer.apple.com/documentation/coregraphics/cgfontref"><type>CGFontRef</type></ulink>, which enables access to typeface
properties, but does not include size information. Core Text's
<ulink url="https://developer.apple.com/documentation/coretext/ctfont-q6r"><type>CTFontRef</type></ulink> is analogous to a HarfBuzz font object,
with all of the properties required to render text at a specific
size and configuration.
Consequently, a HarfBuzz <type>hb_font_t</type> font object can
be hooked up to a Core Text <type>CTFontRef</type>, and a HarfBuzz
<type>hb_face_t</type> face object can be hooked up to a
<type>CGFontRef</type>.
</para>
<para>
You can create a <type>hb_face_t</type> from a
<type>CGFontRef</type> by using the
<function>hb_coretext_face_create()</function>. Subsequently,
you can retrieve the <type>CGFontRef</type> from a
<type>hb_face_t</type> with <function>hb_coretext_face_get_cg_font()</function>.
</para>
<para>
Likewise, you create a <type>hb_font_t</type> from a
<type>CTFontRef</type> by calling
<function>hb_coretext_font_create()</function>, and you can
fetch the associated <type>CTFontRef</type> from a
<type>hb_font_t</type> font object with
<function>hb_coretext_face_get_ct_font()</function>.
</para>
<para>
HarfBuzz also offers a <function>hb_font_set_ptem()</function>
that you an use to set the nominal point size on any
<type>hb_font_t</type> font object. Core Text uses this value to
implement optical scaling.
</para>
<para>
When integrating your client code with Core Text, it is
important to recognize that Core Text <literal>points</literal>
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.
</para>
<para>
HarfBuzz's font functions take this distinction into account,
but it can be an easy detail to miss in cross-platform
code.
</para>
<para>
As a final note, you may notice a reference to an optional
<literal>coretext</literal> shaper back-end in the <xref
linkend="configuration" /> section of the HarfBuzz manual. This
option is not a Core Text-integration facility.
</para>
<para>
Instead, it is a internal code path used in the
<command>hb-shape</command> 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.
</para>
<para>
Because this back-end is only used when testing HarfBuzz
functionality, it is disabled by default when building the
HarfBuzz binaries.
</para>
</section>
<section id="integration-icu">
<title>ICU integration</title>
<para>
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.
</para>
<para>
The principal integration point with ICU is the
<type>hb_unicode_funcs_t</type> 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.
</para>
<para>
To use ICU in your client program, you need to call
<function>hb_icu_get_unicode_funcs()</function>, 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:
</para>
<programlisting language="C">
hb_unicode_funcs_t *icufunctions;
icufunctions = hb_icu_get_unicode_funcs();
hb_buffer_set_unicode_funcs(buf, icufunctions);
</programlisting>
<para>
and ICU will be used for Unicode-data access.
</para>
<para>
HarfBuzz also supplies a pair of functions
(<function>hb_icu_script_from_script()</function> and
<function>hb_icu_script_to_script()</function>) for converting
between ICU's and HarfBuzz's internal enumerations of Unicode
scripts. The <function>hb_icu_script_from_script()</function>
function converts from a HarfBuzz <type>hb_script_t</type> to an
ICU <type>UScriptCode</type>. The
<function>hb_icu_script_to_script()</function> function does the
reverse: converting from a <type>UScriptCode</type> identifier
to a <type>hb_script_t</type>.
</para>
<para>
By default, HarfBuzz's ICU support is built as a separate shared
library (<filename class="libraryfile">libharfbuzz-icu.so</filename>)
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
(<filename class="libraryfile">libharfbuzz.so</filename>),
by specifying the <literal>--with-icu=builtin</literal>
compile-time option.
</para>
</section>
<section id="integration-python">
<title>Python bindings</title>
<para>
As noted in the <xref linkend="integration-glib" /> section,
HarfBuzz uses a feature called <ulink
url="https://wiki.gnome.org/Projects/GObjectIntrospection">GObject
Introspection</ulink> (GI) to provide bindings for Python.
</para>
<para>
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.
</para>
<para>
HarfBuzz's Python bindings support Python 2 and Python 3. To use
them, you will need to have the <literal>pygobject</literal>
package installed. Then you should import
<literal>HarfBuzz</literal> from
<literal>gi.repository</literal>:
</para>
<programlisting language="Python">
from gi.repository import HarfBuzz
</programlisting>
<para>
and you can call HarfBuzz functions from Python. Sample code can
be found in the <filename>sample.py</filename> script in the
HarfBuzz <filename>src</filename> directory.
</para>
<para>
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.
</para>
</section>
</chapter>

View file

@ -12,7 +12,7 @@
HarfBuzz features two kinds of data types: non-opaque,
pass-by-value types and opaque, heap-allocated types. This kind
of separation is common in C libraries that have to provide
API/ABI compatibility (almost) indefinitely.
API/ABI compatibility (almost) indefinitely.
</para>
<para>
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
@ -32,8 +32,8 @@
possible future members. As such, its important to provide
<function>equal()</function>, and <function>hash()</function>
methods for such structs, allowing users of the API do
effectively deal with the type without having to
adapt their code to future changes.
effectively deal with the type without having to
adapt their code to future changes.
</para>
<para>
Important value types provided by HarfBuzz include the structs
@ -42,7 +42,7 @@
OpenType properties.
</para>
</section>
<section id="object-model-object-types">
<title>Objects in HarfBuzz</title>
<para>
@ -63,13 +63,17 @@
the <literal>hb_buffer_t</literal> object has
<function>hb_buffer_create()</function> as its constructor,
<function>hb_buffer_reference()</function> to reference, and
<function>hb_buffer_destroy()</function> to dereference.
<function>hb_buffer_destroy()</function> to dereference.
</para>
<para>
After construction, each object's properties are accessible only
through the setter and getter functions described in the API
Reference manual.
</para>
<para>
Note that many object types can be marked as read-only or immutable,
facilitating their use in multi-threaded environments.
</para>
<para>
Key object types provided by HarfBuzz include:
</para>
@ -110,11 +114,11 @@
</para>
</listitem>
</itemizedlist>
</section>
<section id="object-model-lifecycle">
<title>Object lifecycle management</title>
<para>
@ -131,7 +135,7 @@
<literal>1</literal>. Client programs can increase the reference
count on an object by calling its
<function>reference()</function> method. Whenever a client
program is finished with an object, it should call its
program is finished with an object, it should call its
corresponding <function>destroy()</function> method. The destroy
method will decrease the reference count on the object and,
whenever the reference count reaches zero, it will also destroy
@ -141,8 +145,8 @@
All of HarfBuzz's object-lifecycle-management APIs are
thread-safe (unless you compiled HarfBuzz from source with the
<literal>HB_NO_MT</literal> configuration flag), even when the
object as a whole is not thread-safe.
It is also permissible to <function>reference()</function> or to
object as a whole is not thread-safe.
It is also permissible to <function>reference()</function> or to
<function>destroy()</function> the <literal>NULL</literal>
value.
</para>
@ -160,7 +164,7 @@
as immutable and <function>is_immutable()</function> methods to
test whether or not an object is immutable. Attempts to use
setter functions on immutable objects will fail silently; see the API
Reference manual for specifics.
Reference manual for specifics.
</para>
<para>
Note also that there are no "make mutable" methods. If client
@ -187,7 +191,7 @@
</para>
</section>
<section id="object-model-user-data">
<title>User data</title>
<para>
@ -195,7 +199,7 @@
offer a "user data" mechanism that can be used to attach
arbitrary data to the object. User-data attachment can be
useful for tying the lifecycles of various pieces of data
together, or for creating language bindings.
together, or for creating language bindings.
</para>
<para>
Each object type has a <function>set_user_data()</function>
@ -220,10 +224,10 @@
existing <literal>user_data</literal>
associated with the specified key.
</para>
</section>
</section>
<section id="object-model-blobs">
<title>Blobs</title>
<para>
@ -232,27 +236,31 @@
different.
</para>
<para>
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 <literal>hb_blob_t</literal> wrapper.
</para>
<para>
This allows you to take advantage of HarffBuzz's
This allows you to take advantage of HarfBuzz's
reference-counting and <function>destroy</function>
callbacks. If you allocated the memory for the data using
callbacks. If you allocated the memory for the data using
<function>malloc()</function>, you would create the blob using
</para>
<programlisting language="C">
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, data, free)
</programlisting>
<para>
That way, HarfBuzz will call <function>free()</function> on the
allocated memory whenever the blob drops its last reference and
is deconstructed. Consequently, the user code can stop worrying
about freeing memory and let the reference-counting machinery
take care of that.
take care of that.
</para>
<para>
Most of the time, blobs are read-only, facilitating their use in
immutable objects.
</para>
</section>
</chapter>

View file

@ -48,14 +48,14 @@
<para>
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 <literal>morx</literal> 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
<literal>kerx</literal> 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 <literal>kern</literal> table, then HarfBuzz will
use the <literal>kern</literal> table. If there is no <literal>kerx</literal>, no GPOS, and no
<literal>kern</literal>, HarfBuzz will fall back to positioning marks itself.
</para>
<para>
With a well-behaved OpenType font, you expect GDEF, GSUB, and
@ -65,10 +65,10 @@
</para>
<para>
The algorithms
used for complex scripts can be quite involved; HarfBuzz tries
used for shaping can be quite involved; HarfBuzz tries
to be compatible with the OpenType Layout specification
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
output of Microsoft's Uniscribe engine. See the <ulink
output of Microsoft's Uniscribe engine, to the extent that is feasible and desirable. See the <ulink
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
Typography pages</ulink> for more detail.
</para>
@ -131,7 +131,7 @@
</para>
<para>
Some OpenType features are defined for the purpose of supporting
complex-script shaping, and are automatically activated, but
script-specific shaping, and are automatically activated, but
only when a buffer's script property is set to a script that the
feature supports.
</para>
@ -149,9 +149,39 @@
also applies the <literal>calt</literal>,
<literal>clig</literal>, <literal>curs</literal>,
<literal>dist</literal>, <literal>kern</literal>,
<literal>liga</literal>, <literal>rclt</literal>,
and <literal>frac</literal> features.
<literal>liga</literal> and <literal>rclt</literal>, features.
</para>
<para>
Additionally, when HarfBuzz encounters a fraction slash
(<literal>U+2044</literal>), it looks backward and forward for decimal
digits (Unicode General Category = Nd), and enables features
<literal>numr</literal> on the sequence before the fraction slash,
<literal>dnom</literal> on the sequence after the fraction slash,
and <literal>frac</literal> on the whole sequence including the fraction
slash.
</para>
<para>
Some script-specific shaping models
(see <xref linkend="opentype-shaping-models" />) disable some of the
features listed above:
</para>
<itemizedlist>
<listitem>
<para>
Hangul: <literal>calt</literal>
</para>
</listitem>
<listitem>
<para>
Indic: <literal>liga</literal>
</para>
</listitem>
<listitem>
<para>
Khmer: <literal>liga</literal>
</para>
</listitem>
</itemizedlist>
<para>
If the text direction is vertical, HarfBuzz applies
the <literal>vert</literal> feature by default.

View file

@ -22,7 +22,7 @@
correct amount for each successive glyph.
</para>
<para>
But, for <emphasis>complex scripts</emphasis>, any combination of
But, for other scripts (often unceremoniously called <emphasis>complex scripts</emphasis>), any combination of
several shaping operations may be required, and the rules for how
and when they are applied vary from script to script. HarfBuzz and
other shaping engines implement these rules.
@ -36,42 +36,35 @@
</para>
</section>
<section id="complex-scripts">
<title>Complex scripts</title>
<section id="script-specific-shaping">
<title>Script-specific shaping</title>
<para>
In text-shaping terminology, scripts are generally classified as
either <emphasis>complex</emphasis> or <emphasis>non-complex</emphasis>.
</para>
<para>
Complex scripts are those for which transforming the input
sequence into the final layout requires some combination of
In many scripts, transforming the input
sequence into the final layout often requires some combination of
operations&mdash;such as context-dependent substitutions,
context-dependent mark positioning, glyph-to-glyph joining,
glyph reordering, or glyph stacking.
</para>
<para>
In some complex scripts, the shaping rules require that a text
In some scripts, the shaping rules require that a text
run be divided into syllables before the operations can be
applied. Other complex scripts may apply shaping operations over
applied. Other scripts may apply shaping operations over
entire words or over the entire text run, with no subdivision
required.
</para>
<para>
Non-complex scripts, by definition, do not require these
operations. However, correctly shaping a text run in a
non-complex script may still involve Unicode normalization,
Other scripts, do not require these
operations. However, correctly shaping a text run in
any script may still involve Unicode normalization,
ligature substitutions, mark positioning, kerning, and applying
other font features. The key difference is that a text run in a
non-complex script can be processed sequentially and in the same
order as the input sequence of Unicode codepoints, without
requiring an analysis stage.
other font features.
</para>
</section>
<section id="shaping-operations">
<title>Shaping operations</title>
<para>
Shaping a complex-script text run involves transforming the
Shaping a text run involves transforming the
input sequence of Unicode codepoints with some combination of
operations that is specified in the shaping model for the
script.
@ -81,7 +74,7 @@
text run varies from script to script, as do the order that the
operations are performed in and which codepoints are
affected. However, the same general set of shaping operations is
common to all of the complex-script shaping models.
common to all of the script shaping models.
</para>
<itemizedlist>
@ -92,7 +85,7 @@
some other ("visual") position.
</para>
<para>
The shaping model for a given complex script might involve
The shaping model for a given script might involve
more than one reordering step.
</para>
</listitem>
@ -119,7 +112,7 @@
particular string pattern.
</para>
<para>
The shaping model for a given complex script might involve
The shaping model for a given script might involve
multiple contextual-substitution operations, each applying
to different target glyphs and patterns, and which are
performed in separate steps.
@ -138,7 +131,7 @@
Many contextual positioning operations are used to place
<emphasis>mark</emphasis> glyphs (such as diacritics, vowel
signs, and tone markers) with respect to
<emphasis>base</emphasis> glyphs. However, some complex
<emphasis>base</emphasis> glyphs. However, some
scripts may use contextual positioning operations to
correctly place base glyphs as well, such as
when the script uses <emphasis>stacking</emphasis> characters.
@ -194,7 +187,7 @@
multiple positions).
</para>
<para>
Some complex scripts require that the text run be split into
Some scripts require that the text run be split into
syllables. What constitutes a valid syllable in these
scripts is specified in regular expressions, formed from the
Letter and Mark codepoints, that take the UISC and UIPC
@ -235,7 +228,7 @@
<listitem>
<para>
The <emphasis>default</emphasis> shaping model handles all
non-complex scripts, and may also be used as a fallback for
scripts with no script-specific shaping model, and may also be used as a fallback for
handling unrecognized scripts.
</para>
</listitem>
@ -244,7 +237,7 @@
<para>
The <emphasis>Indic</emphasis> shaping model handles the Indic
scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
Malayalam, Oriya, Tamil, Telugu, and Sinhala.
Malayalam, Oriya, Tamil, and Telugu.
</para>
<para>
The Indic shaping model was revised significantly in
@ -310,7 +303,7 @@
<listitem>
<para>
The <emphasis>Universal Shaping Engine</emphasis> (USE)
shaping model supports complex scripts not covered by one of
shaping model supports scripts not covered by one of
the above, script-specific shaping models, including
Javanese, Balinese, Buginese, Batak, Chakma, Lepcha, Modi,
Phags-pa, Tagalog, Siddham, Sundanese, Tai Le, Tai Tham, Tai

View file

@ -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.
</para>
<section id="utilities-command-line-tools">
<title>Command-line tools</title>
<para>
HarfBuzz include three command-line tools:
<program>hb-shape</program>, <program>hb-view</program>, and
<program>hb-subset</program>. They can be used to examine
<command>hb-shape</command>, <command>hb-view</command>, and
<command>hb-subset</command>. They can be used to examine
HarfBuzz's functionality, debug font binaries, or explore the
various shaping models and features from a terminal.
</para>
@ -27,12 +26,12 @@
<section id="utilities-command-line-hbshape">
<title>hb-shape</title>
<para>
<emphasis><program>hb-shape</program></emphasis> allows you to run HarfBuzz's
<emphasis><command>hb-shape</command></emphasis> allows you to run HarfBuzz's
<function>hb_shape()</function> function on an input string and
to examine the outcome, in human-readable form, as terminal
output. <program>hb-shape</program> does
output. <command>hb-shape</command> does
<emphasis>not</emphasis> render the results of the shaping call
into rendered text (you can use <program>hb-view</program>, below, for
into rendered text (you can use <command>hb-view</command>, 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 @@
<section id="utilities-command-line-hbview">
<title>hb-view</title>
<para>
<emphasis><program>hb-view</program></emphasis> allows you to
<emphasis><command>hb-view</command></emphasis> allows you to
see the shaped output of an input string in rendered
form. Like <program>hb-shape</program>,
<program>hb-view</program> takes a font file and a text string
form. Like <command>hb-shape</command>,
<command>hb-view</command> takes a font file and a text string
as its arguments:
</para>
<programlisting>
@ -92,7 +91,7 @@
<parameter>yourinputtext</parameter>
</programlisting>
<para>
By default, <program>hb-view</program> renders the shaped
By default, <command>hb-view</command> renders the shaped
text in ASCII block-character images as terminal output. By
appending the
<command>--output-file=<optional>filename</optional></command>
@ -100,7 +99,7 @@
(among other formats).
</para>
<para>
As with <program>hb-shape</program>, a lengthy set of options
As with <command>hb-shape</command>, 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
</para>
<para>
In general, <program>hb-view</program> is a quick way to
In general, <command>hb-view</command> 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 <program>hb-shape</program> to figure out exactly
want to use <command>hb-shape</command> to figure out exactly
why something does not appear as expected.
</para>
</section>
@ -125,13 +124,13 @@
<section id="utilities-command-line-hbsubset">
<title>hb-subset</title>
<para>
<emphasis><program>hb-subset</program></emphasis> allows you
<emphasis><command>hb-subset</command></emphasis> allows you
to generate a subset of a given font, with a limited set of
supported characters, features, and variation settings.
</para>
<para>
By default, you provide an input font and an input text string
as the arguments to <program>hb-subset</program>, and it will
as the arguments to <command>hb-subset</command>, and it will
generate a font that covers the input text exactly like the
input font does, but includes no other characters or features.
</para>
@ -216,29 +215,4 @@
</para>
</section>
<section id="utilities-ucdn">
<title>UCDN</title>
<para>
HarfBuzz includes a copy of the <ulink
url="https://github.com/grigorig/ucdn">UCDN</ulink> (Unicode
Database and Normalization) library, which provides functions
for accessing basic Unicode character properties, performing
canonical composition, and performing both canonical and
compatibility decomposition.
</para>
<para>
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.
</para>
<para>
The built-in UCDN functions are compiled by default when
building HarfBuzz from source, but this can be disabled with a
compile-time switch.
</para>
</section>
</chapter>

View file

@ -226,7 +226,7 @@
</section>
<section>
<section id="what-does-harfbuzz-do">
<title>What does HarfBuzz do?</title>
<para>
HarfBuzz provides text shaping through a cross-platform
@ -237,8 +237,7 @@
<listitem>
<para>
Indic (covering Devanagari, Bengali, Gujarati,
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
Sinhala)
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and Telugu)
</para>
</listitem>
<listitem>

7
git.mk
View file

@ -204,7 +204,7 @@ git-mk-update:
# Actual .gitignore generation:
###############################################################################
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac
@echo "git.mk: Generating $@"
@{ \
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
@ -375,8 +375,9 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
} | \
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
sed 's@/[.]/@/@g' | \
LC_ALL=C sort | uniq > $@.tmp && \
mv $@.tmp $@;
LC_ALL=C sort | uniq > .gitignore.tmp && \
(mv .gitignore.tmp $@ || (echo "WARNING: Cannot create $@ file; skipping"; \
$(RM) .gitignore.tmp));
all: $(srcdir)/.gitignore gitignore-recurse-maybe
gitignore: $(srcdir)/.gitignore gitignore-recurse

View file

@ -7,11 +7,11 @@
<shortdesc xml:lang="en">Text shaping library</shortdesc>
<homepage
rdf:resource="http://harfbuzz.org/" />
rdf:resource="https://github.com/harfbuzz/harfbuzz" />
<mailing-list
rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
<!--download-page
rdf:resource=""/-->
rdf:resource="https://github.com/harfbuzz/harfbuzz/discussions" />
<download-page
rdf:resource="https://github.com/harfbuzz/harfbuzz/releases" />
<bug-database
rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />

View file

@ -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

442
meson.build Normal file
View file

@ -0,0 +1,442 @@
project('harfbuzz', 'c', 'cpp',
meson_version: '>= 0.55.0',
version: '7.2.0',
default_options: [
'cpp_eh=none', # Just to support msvc, we are passing -fno-exceptions also anyway
'cpp_rtti=false', # Just to support msvc, we are passing -fno-rtti 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 = 60000 + hb_version_major*100 + hb_version_minor*10 + 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_argument_syntax() == '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 = [
'/wd4244', # lossy type conversion (e.g. double -> int)
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
if host_machine.system() == 'windows'
add_project_arguments(cpp.get_supported_arguments([
'-Wa,-mbig-obj'
]), language : 'cpp')
endif
check_headers = [
['unistd.h'],
['sys/mman.h'],
['stdbool.h'],
['xlocale.h'],
]
check_funcs = [
['atexit'],
['mprotect'],
['sysconf'],
['getpagesize'],
['mmap'],
['isatty'],
['uselocale'],
['newlocale'],
['sincosf'],
]
m_dep = cpp.find_library('m', required: false)
if meson.version().version_compare('>=0.60.0')
# pkg-config: freetype2, cmake: Freetype
freetype_dep = dependency('freetype2', 'Freetype',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
else
# painful hack to handle multiple dependencies but also respect options
freetype_opt = get_option('freetype')
# we want to handle enabled manually after fallbacks, but also handle disabled normally
if freetype_opt.enabled()
freetype_opt = false
endif
# try pkg-config name
freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt)
# when disabled, leave it not-found
if not freetype_dep.found() and not get_option('freetype').disabled()
# Try cmake name
freetype_dep = dependency('Freetype', method: 'cmake', required: false)
# Subproject fallback, `allow_fallback: true` means the fallback will be
# tried even if the freetype option is set to `auto`.
if not freetype_dep.found()
freetype_dep = dependency('freetype2',
method: 'pkg-config',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
endif
endif
endif
glib_dep = dependency('glib-2.0', required: get_option('glib'))
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
graphite_dep = dependency('graphite2', required: get_option('graphite'))
if meson.version().version_compare('>=0.60.0')
# pkg-config: icu-uc, cmake: ICU but with components
icu_dep = dependency('icu-uc', 'ICU',
components: 'uc',
required: get_option('icu'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
else
# painful hack to handle multiple dependencies but also respect options
icu_opt = get_option('icu')
# we want to handle enabled manually after fallbacks, but also handle disabled normally
if icu_opt.enabled()
icu_opt = false
endif
# try pkg-config name
icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt)
# when disabled, leave it not-found
if not icu_dep.found() and not get_option('icu').disabled()
# Try cmake name
icu_dep = dependency('ICU', method: 'cmake', components: 'uc', required: false)
# Try again with subproject fallback. `allow_fallback: true` means the
# fallback will be tried even if the icu option is set to `auto`, but
# we cannot pass this option until Meson 0.59.0, because no wrap file
# is checked into git.
if not icu_dep.found()
icu_dep = dependency('icu-uc',
method: 'pkg-config',
required: get_option('icu'))
endif
endif
endif
if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
icu_defs = icu_dep.get_variable(pkgconfig: 'DEFS', default_value: '').split()
if icu_defs.length() > 0
add_project_arguments(icu_defs, language: ['c', 'cpp'])
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_argument_syntax() == '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 <cairo-ft.h>',
dependencies: cairo_dep)
cairo_ft_dep = cairo_dep
endif
endif
if not cairo_dep.found()
# 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', required: get_option('cairo'))
cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled()
cairo_ft_dep = dependency('cairo-ft', required: cairo_ft_required)
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)
check_cairo_funcs = [
['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}],
['cairo_font_options_get_custom_palette_color', {'deps': cairo_dep}],
['cairo_user_scaled_font_get_foreground_source', {'deps': cairo_dep}],
]
if cairo_dep.type_name() == 'internal'
foreach func: check_cairo_funcs
name = func[0]
conf.set('HAVE_@0@'.format(name.to_upper()), 1)
endforeach
else
check_funcs += check_cairo_funcs
endif
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() or graphite_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}],
['FT_Get_Transform', {'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)
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
conf.set('HAVE_DIRECTWRITE', 1)
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 <ApplicationServices/ApplicationServices.h>', 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 <CoreText/CoreText.h>', 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')
if not get_option('utilities').disabled()
subdir('util')
endif
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)
alias_target('lib', libharfbuzz)
alias_target('libs', libharfbuzz, libharfbuzz_subset)
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)':
{'Builtin' : true,
'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,
'Cairo integration': conf.get('HAVE_CAIRO', 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(),
},
}
foreach section_title, section : build_summary
summary(section, bool_yn: true, section: section_title)
endforeach

46
meson_options.txt Normal file
View file

@ -0,0 +1,46 @@
# 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: 'Deprecated use graphite2 option instead')
option('graphite2', 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('doc_tests', type: 'boolean', value: false,
description: 'Run gtkdoc-check tests')
option('utilities', type: 'feature', value: 'enabled', yield: true,
description: 'Build harfbuzz utils')
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('ragel_subproject', type: 'boolean', value: false,
description: 'Build Ragel subproject if no suitable version is found')
option('fuzzer_ldflags', type: 'string',
description: 'Extra LDFLAGS used during linking of fuzzing binaries')

View file

@ -17,12 +17,14 @@ exec "$(dirname "$0")"/configure \
CPP= \
LD= \
CFLAGS="-static-libgcc" \
CXXFLAGS="-static-libgcc -static-libstdc++" \
CXXFLAGS="-O2 -static-libgcc -static-libstdc++" \
CPPFLAGS="-I$HOME/.local/$target/include" \
LDFLAGS=-L$HOME/.local/$target/lib \
PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
--without-icu \
--with-gdi \
--with-uniscribe \
--with-directwrite=auto \
"$@"

View file

@ -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)

View file

@ -1,2 +0,0 @@
#!/bin/sh
exec "$(dirname "$0")"/mingw-configure.sh i686 "$@"

View file

@ -1,2 +0,0 @@
#!/bin/sh
exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@"

23
perf/Makefile.am Normal file
View file

@ -0,0 +1,23 @@
# Process this file with automake to produce Makefile.in
NULL =
EXTRA_DIST =
SUBDIRS =
EXTRA_DIST += \
meson.build \
benchmark-font.cc \
benchmark-map.cc \
benchmark-ot.cc \
benchmark-set.cc \
benchmark-shape.cc \
benchmark-subset.cc \
fonts \
texts \
$(NULL)
# Convenience targets:
lib:
@$(MAKE) $(AM_MAKEFLAGS) -C $(top_builddir)/src lib
-include $(top_srcdir)/git.mk

54
perf/README.md Normal file
View file

@ -0,0 +1,54 @@
# Building and Running
Benchmarks are implemented using [Google Benchmark](https://github.com/google/benchmark).
To build the benchmarks in this directory you need to set the benchmark
option while configuring the build with meson:
```
meson build -Dbenchmark=enabled --buildtype=release
```
or:
```
meson build -Dbenchmark=enabled --buildtype=debugoptimized
```
Then build a specific benchmark binaries with ninja:
```
ninja -Cbuild perf/benchmark-set
```
or just build the whole project:
```
ninja -Cbuild
```
Finally, to run one of the benchmarks:
```
./build/perf/benchmark-set
```
It's possible to filter the benchmarks being run and customize the output
via flags to the benchmark binary. See the
[Google Benchmark User Guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md#user-guide) for more details.
# Profiling
Configure the build to include debug information for profiling:
```
CXXFLAGS="-fno-omit-frame-pointer" meson --reconfigure build -Dbenchmark=enabled --buildtype=debug
ninja -Cbuild
```
Then run the benchmark with perf:
```
perf record -g build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
```
You probably want to filter to a specific benchmark of interest and set the number of repititions high enough to get a good sampling of profile data.
Finally view the profile with:
perf report

245
perf/benchmark-font.cc Normal file
View file

@ -0,0 +1,245 @@
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
struct test_input_t
{
bool is_variable;
const char *font_path;
} default_tests[] =
{
{true , SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"},
{false, SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf"},
{true , SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf"},
{true , SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf"},
{false, SUBSET_FONT_BASE_PATH "Comfortaa-Regular-new.ttf"},
{false, SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf"},
{false, SUBSET_FONT_BASE_PATH "NotoSerifMyanmar-Regular.otf"},
};
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
enum backend_t { HARFBUZZ, FREETYPE };
enum operation_t
{
nominal_glyphs,
glyph_h_advances,
glyph_extents,
draw_glyph,
};
static void
_hb_move_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
static void
_hb_line_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
//static void
//_hb_quadratic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, void *) {}
static void
_hb_cubic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, float, float, void *) {}
static void
_hb_close_path (hb_draw_funcs_t *, void *, hb_draw_state_t *, void *) {}
static hb_draw_funcs_t *
_draw_funcs_create (void)
{
hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr);
hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr);
//hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr);
hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr);
return draw_funcs;
}
static void BM_Font (benchmark::State &state,
bool is_var, backend_t backend, operation_t operation,
const test_input_t &test_input)
{
hb_font_t *font;
unsigned num_glyphs;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (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);
}
switch (backend)
{
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
}
switch (operation)
{
case nominal_glyphs:
{
hb_set_t *set = hb_set_create ();
hb_face_collect_unicodes (hb_font_get_face (font), set);
unsigned pop = hb_set_get_population (set);
hb_codepoint_t *unicodes = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
hb_codepoint_t *p = unicodes;
for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
hb_set_next (set, &u);)
*p++ = u;
assert (p == unicodes + pop);
for (auto _ : state)
hb_font_get_nominal_glyphs (font,
pop,
unicodes, sizeof (*unicodes),
glyphs, sizeof (*glyphs));
free (glyphs);
free (unicodes);
hb_set_destroy (set);
break;
}
case glyph_h_advances:
{
hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
hb_position_t *advances = (hb_position_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
for (unsigned g = 0; g < num_glyphs; g++)
glyphs[g] = g;
for (auto _ : state)
hb_font_get_glyph_h_advances (font,
num_glyphs,
glyphs, sizeof (*glyphs),
advances, sizeof (*advances));
free (advances);
free (glyphs);
break;
}
case glyph_extents:
{
hb_glyph_extents_t extents;
for (auto _ : state)
for (unsigned gid = 0; gid < num_glyphs; ++gid)
hb_font_get_glyph_extents (font, gid, &extents);
break;
}
case draw_glyph:
{
hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
for (auto _ : state)
for (unsigned gid = 0; gid < num_glyphs; ++gid)
hb_font_draw_glyph (font, gid, draw_funcs, nullptr);
break;
hb_draw_funcs_destroy (draw_funcs);
}
}
hb_font_destroy (font);
}
static void test_backend (backend_t backend,
const char *backend_name,
bool variable,
operation_t op,
const char *op_name,
benchmark::TimeUnit time_unit,
const test_input_t &test_input)
{
char name[1024] = "BM_Font/";
strcat (name, op_name);
strcat (name, "/");
const char *p = strrchr (test_input.font_path, '/');
strcat (name, p ? p + 1 : test_input.font_path);
strcat (name, variable ? "/var" : "");
strcat (name, "/");
strcat (name, backend_name);
benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
->Unit(time_unit);
}
static void test_operation (operation_t op,
const char *op_name,
benchmark::TimeUnit time_unit)
{
for (unsigned i = 0; i < num_tests; i++)
{
auto& test_input = tests[i];
for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
{
bool is_var = (bool) variable;
test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
#endif
}
}
}
int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
if (argc > 1)
{
num_tests = argc - 1;
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
for (unsigned i = 0; i < num_tests; i++)
{
tests[i].is_variable = true;
tests[i].font_path = argv[i + 1];
}
}
#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit)
TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond);
TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
TEST_OPERATION (draw_glyph, benchmark::kMicrosecond);
#undef TEST_OPERATION
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

68
perf/benchmark-map.cc Normal file
View file

@ -0,0 +1,68 @@
/*
* Benchmarks for hb_map_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
void RandomMap(unsigned size, hb_map_t* out) {
hb_map_clear(out);
srand(size);
for (unsigned i = 0; i < size; i++) {
while (true) {
hb_codepoint_t next = rand();
if (hb_map_has (out, next)) continue;
hb_map_set (out, next, rand ());
break;
}
}
}
/* Insert a single value into map of varying sizes. */
static void BM_MapInsert(benchmark::State& state) {
unsigned map_size = state.range(0);
hb_map_t* original = hb_map_create ();
RandomMap(map_size, original);
assert(hb_map_get_population(original) == map_size);
auto needle = map_size / 2;
auto v = 0;
for (auto _ : state) {
// TODO(garretrieger): create a copy of the original map.
// Needs a hb_map_copy(..) in public api.
hb_map_set (original, needle++, v++);
}
hb_map_destroy(original);
}
BENCHMARK(BM_MapInsert)
->Range(1 << 4, 1 << 20);
/* Single value lookup on map of various sizes. */
static void BM_MapLookup(benchmark::State& state) {
unsigned map_size = state.range(0);
hb_map_t* original = hb_map_create ();
RandomMap(map_size, original);
assert(hb_map_get_population(original) == map_size);
auto needle = map_size / 2;
for (auto _ : state) {
benchmark::DoNotOptimize(
hb_map_get (original, needle++));
}
hb_map_destroy(original);
}
BENCHMARK(BM_MapLookup)
->Range(1 << 4, 1 << 20); // Map size
BENCHMARK_MAIN();

44
perf/benchmark-ot.cc Normal file
View file

@ -0,0 +1,44 @@
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include "hb-ot.h"
static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state,
hb_script_t script,
const char *language_str) {
hb_language_t language = hb_language_from_string (language_str, -1);
for (auto _ : state)
{
hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
unsigned script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
unsigned language_count = HB_OT_MAX_TAGS_PER_LANGUAGE;
hb_ot_tags_from_script_and_language (script,
language,
&script_count /* IN/OUT */,
script_tags /* OUT */,
&language_count /* IN/OUT */,
language_tags /* OUT */);
}
}
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_abcd, HB_SCRIPT_COMMON, "zh_abcd");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_hans, HB_SCRIPT_COMMON, "zh_hans");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON ab_abcd, HB_SCRIPT_COMMON, "ab_abcd");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON ab_abc, HB_SCRIPT_COMMON, "ab_abc");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON abcdef_XY, HB_SCRIPT_COMMON, "abcdef_XY");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON abcd_XY, HB_SCRIPT_COMMON, "abcd_XY");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON cxy_CN, HB_SCRIPT_COMMON, "cxy_CN");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON exy_CN, HB_SCRIPT_COMMON, "exy_CN");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON zh_CN, HB_SCRIPT_COMMON, "zh_CN");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON en_US, HB_SCRIPT_COMMON, "en_US");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, LATIN en_US, HB_SCRIPT_LATIN, "en_US");
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, COMMON none, HB_SCRIPT_LATIN, nullptr);
BENCHMARK_CAPTURE (BM_hb_ot_tags_from_script_and_language, LATIN none, HB_SCRIPT_LATIN, nullptr);
BENCHMARK_MAIN();

151
perf/benchmark-set.cc Normal file
View file

@ -0,0 +1,151 @@
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) {
hb_set_clear(out);
srand(size * max_value);
for (unsigned i = 0; i < size; i++) {
while (true) {
unsigned next = rand() % max_value;
if (hb_set_has (out, next)) continue;
hb_set_add(out, next);
break;
}
}
}
// TODO(garretrieger): benchmark union/subtract/intersection etc.
/* Insert a 1000 values into set of varying sizes. */
static void BM_SetInsert_1000(benchmark::State& state) {
unsigned set_size = state.range(0);
unsigned max_value = state.range(0) * state.range(1);
hb_set_t* original = hb_set_create ();
RandomSet(set_size, max_value, original);
assert(hb_set_get_population(original) == set_size);
for (auto _ : state) {
state.PauseTiming ();
hb_set_t* data = hb_set_copy(original);
state.ResumeTiming ();
for (int i = 0; i < 1000; i++) {
hb_set_add(data, i * 2654435761u % max_value);
}
hb_set_destroy(data);
}
hb_set_destroy(original);
}
BENCHMARK(BM_SetInsert_1000)
->Unit(benchmark::kMicrosecond)
->Ranges(
{{1 << 10, 1 << 16}, // Set Size
{2, 512}}); // Density
/* Insert a 1000 values into set of varying sizes. */
static void BM_SetOrderedInsert_1000(benchmark::State& state) {
unsigned set_size = state.range(0);
unsigned max_value = state.range(0) * state.range(1);
hb_set_t* original = hb_set_create ();
RandomSet(set_size, max_value, original);
assert(hb_set_get_population(original) == set_size);
for (auto _ : state) {
state.PauseTiming ();
hb_set_t* data = hb_set_copy(original);
state.ResumeTiming ();
for (int i = 0; i < 1000; i++) {
hb_set_add(data, i);
}
hb_set_destroy(data);
}
hb_set_destroy(original);
}
BENCHMARK(BM_SetOrderedInsert_1000)
->Unit(benchmark::kMicrosecond)
->Ranges(
{{1 << 10, 1 << 16}, // Set Size
{2, 512}}); // Density
/* Single value lookup on sets of various sizes. */
static void BM_SetLookup(benchmark::State& state, unsigned interval) {
unsigned set_size = state.range(0);
unsigned max_value = state.range(0) * state.range(1);
hb_set_t* original = hb_set_create ();
RandomSet(set_size, max_value, original);
assert(hb_set_get_population(original) == set_size);
auto needle = max_value / 2;
for (auto _ : state) {
benchmark::DoNotOptimize(
hb_set_has (original, (needle += interval) % max_value));
}
hb_set_destroy(original);
}
BENCHMARK_CAPTURE(BM_SetLookup, ordered, 3)
->Ranges(
{{1 << 10, 1 << 16}, // Set Size
{2, 512}}); // Density
BENCHMARK_CAPTURE(BM_SetLookup, random, 12345)
->Ranges(
{{1 << 10, 1 << 16}, // Set Size
{2, 512}}); // Density
/* Full iteration of sets of varying sizes. */
static void BM_SetIteration(benchmark::State& state) {
unsigned set_size = state.range(0);
unsigned max_value = state.range(0) * state.range(1);
hb_set_t* original = hb_set_create ();
RandomSet(set_size, max_value, original);
assert(hb_set_get_population(original) == set_size);
hb_codepoint_t cp = HB_SET_VALUE_INVALID;
for (auto _ : state) {
hb_set_next (original, &cp);
}
hb_set_destroy(original);
}
BENCHMARK(BM_SetIteration)
->Ranges(
{{1 << 10, 1 << 16}, // Set Size
{2, 512}}); // Density
/* Set copy. */
static void BM_SetCopy(benchmark::State& state) {
unsigned set_size = state.range(0);
unsigned max_value = state.range(0) * state.range(1);
hb_set_t* original = hb_set_create ();
RandomSet(set_size, max_value, original);
assert(hb_set_get_population(original) == set_size);
for (auto _ : state) {
hb_set_t *s = hb_set_create ();
hb_set_set (s, original);
hb_set_destroy (s);
}
hb_set_destroy(original);
}
BENCHMARK(BM_SetCopy)
->Unit(benchmark::kMicrosecond)
->Ranges(
{{1 << 10, 1 << 16}, // Set Size
{2, 512}}); // Density
BENCHMARK_MAIN();

180
perf/benchmark-shape.cc Normal file
View file

@ -0,0 +1,180 @@
#include "benchmark/benchmark.h"
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cassert>
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
struct test_input_t
{
const char *font_path;
const char *text_path;
bool is_variable;
} default_tests[] =
{
{"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
"perf/texts/fa-thelittleprince.txt",
false},
{"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
"perf/texts/fa-words.txt",
false},
{"perf/fonts/Amiri-Regular.ttf",
"perf/texts/fa-thelittleprince.txt",
false},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
"perf/texts/hi-words.txt",
false},
{"perf/fonts/Roboto-Regular.ttf",
"perf/texts/en-thelittleprince.txt",
false},
{"perf/fonts/Roboto-Regular.ttf",
"perf/texts/en-words.txt",
false},
{SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
"perf/texts/en-thelittleprince.txt",
true},
};
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
enum backend_t { HARFBUZZ, FREETYPE };
static void BM_Shape (benchmark::State &state,
bool is_var,
backend_t backend,
const test_input_t &input)
{
hb_font_t *font;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
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);
}
switch (backend)
{
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
}
hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
assert (text_blob);
unsigned orig_text_length;
const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
hb_buffer_t *buf = hb_buffer_create ();
for (auto _ : state)
{
unsigned text_length = orig_text_length;
const char *text = orig_text;
const char *end;
while ((end = (const char *) memchr (text, '\n', text_length)))
{
hb_buffer_clear_contents (buf);
hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
hb_buffer_guess_segment_properties (buf);
hb_shape (font, buf, nullptr, 0);
unsigned skip = end - text + 1;
text_length -= skip;
text += skip;
}
}
hb_buffer_destroy (buf);
hb_blob_destroy (text_blob);
hb_font_destroy (font);
}
static void test_backend (backend_t backend,
const char *backend_name,
bool variable,
const test_input_t &test_input)
{
char name[1024] = "BM_Shape";
const char *p;
strcat (name, "/");
p = strrchr (test_input.font_path, '/');
strcat (name, p ? p + 1 : test_input.font_path);
strcat (name, "/");
p = strrchr (test_input.text_path, '/');
strcat (name, p ? p + 1 : test_input.text_path);
strcat (name, variable ? "/var" : "");
strcat (name, "/");
strcat (name, backend_name);
benchmark::RegisterBenchmark (name, BM_Shape, variable, backend, test_input)
->Unit(benchmark::kMillisecond);
}
int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
if (argc > 2)
{
num_tests = (argc - 1) / 2;
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
for (unsigned i = 0; i < num_tests; i++)
{
tests[i].is_variable = true;
tests[i].font_path = argv[1 + i * 2];
tests[i].text_path = argv[2 + i * 2];
}
}
for (unsigned i = 0; i < num_tests; i++)
{
auto& test_input = tests[i];
for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
{
bool is_var = (bool) variable;
test_backend (HARFBUZZ, "hb", is_var, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, test_input);
#endif
}
}
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

259
perf/benchmark-subset.cc Normal file
View file

@ -0,0 +1,259 @@
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb-subset.h"
enum operation_t
{
subset_codepoints,
subset_glyphs,
instance,
};
struct axis_location_t
{
hb_tag_t axis_tag;
float axis_value;
};
static const axis_location_t
_roboto_flex_instance_opts[] =
{
{HB_TAG ('w', 'g', 'h', 't'), 600.f},
{HB_TAG ('w', 'd', 't', 'h'), 75.f},
{HB_TAG ('o', 'p', 's', 'z'), 90.f},
{HB_TAG ('G', 'R', 'A', 'D'), -100.f},
{HB_TAG ('s', 'l', 'n', 't'), -3.f},
{HB_TAG ('X', 'T', 'R', 'A'), 500.f},
{HB_TAG ('X', 'O', 'P', 'Q'), 150.f},
{HB_TAG ('Y', 'O', 'P', 'Q'), 100.f},
{HB_TAG ('Y', 'T', 'L', 'C'), 480.f},
{HB_TAG ('Y', 'T', 'U', 'C'), 600.f},
{HB_TAG ('Y', 'T', 'A', 'S'), 800.f},
{HB_TAG ('Y', 'T', 'D', 'E'), -50.f},
{HB_TAG ('Y', 'T', 'F', 'I'), 600.f},
};
static const axis_location_t
_mplus_instance_opts[] =
{
{HB_TAG ('w', 'g', 'h', 't'), 800.f},
};
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
struct test_input_t
{
const char *font_path;
unsigned max_subset_size;
const axis_location_t *instance_opts;
unsigned num_instance_opts;
} default_tests[] =
{
{SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0},
{SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)},
{SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)},
#if 0
{"perf/fonts/NotoSansCJKsc-VF.ttf", 100000},
#endif
};
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
void AddCodepoints(const hb_set_t* codepoints_in_font,
unsigned subset_size,
hb_subset_input_t* input)
{
auto *unicodes = hb_subset_input_unicode_set (input);
hb_codepoint_t cp = HB_SET_VALUE_INVALID;
for (unsigned i = 0; i < subset_size; i++) {
// TODO(garretrieger): pick randomly.
if (!hb_set_next (codepoints_in_font, &cp)) return;
hb_set_add (unicodes, cp);
}
}
void AddGlyphs(unsigned num_glyphs_in_font,
unsigned subset_size,
hb_subset_input_t* input)
{
auto *glyphs = hb_subset_input_glyph_set (input);
for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
// TODO(garretrieger): pick randomly.
hb_set_add (glyphs, i);
}
}
// Preprocess face and populate the subset accelerator on it to speed up
// the subsetting operations.
static hb_face_t* preprocess_face(hb_face_t* face)
{
hb_face_t* new_face = hb_subset_preprocess(face);
hb_face_destroy(face);
return new_face;
}
/* benchmark for subsetting a font */
static void BM_subset (benchmark::State &state,
operation_t operation,
const test_input_t &test_input,
bool hinting)
{
unsigned subset_size = state.range(0);
hb_face_t *face = nullptr;
static hb_face_t *cached_face;
static const char *cached_font_path;
if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
face = preprocess_face (face);
if (cached_face)
hb_face_destroy (cached_face);
cached_face = hb_face_reference (face);
cached_font_path = test_input.font_path;
}
else
face = hb_face_reference (cached_face);
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
assert (input);
if (!hinting)
hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
switch (operation)
{
case subset_codepoints:
{
hb_set_t* all_codepoints = hb_set_create ();
hb_face_collect_unicodes (face, all_codepoints);
AddCodepoints(all_codepoints, subset_size, input);
hb_set_destroy (all_codepoints);
}
break;
case subset_glyphs:
{
unsigned num_glyphs = hb_face_get_glyph_count (face);
AddGlyphs(num_glyphs, subset_size, input);
}
break;
case instance:
{
hb_set_t* all_codepoints = hb_set_create ();
hb_face_collect_unicodes (face, all_codepoints);
AddCodepoints(all_codepoints, subset_size, input);
hb_set_destroy (all_codepoints);
for (unsigned i = 0; i < test_input.num_instance_opts; i++)
hb_subset_input_pin_axis_location (input, face,
test_input.instance_opts[i].axis_tag,
test_input.instance_opts[i].axis_value);
}
break;
}
for (auto _ : state)
{
hb_face_t* subset = hb_subset_or_fail (face, input);
assert (subset);
hb_face_destroy (subset);
}
hb_subset_input_destroy (input);
hb_face_destroy (face);
}
static void test_subset (operation_t op,
const char *op_name,
bool hinting,
benchmark::TimeUnit time_unit,
const test_input_t &test_input)
{
if (op == instance && test_input.instance_opts == nullptr)
return;
char name[1024] = "BM_subset/";
strcat (name, op_name);
strcat (name, "/");
const char *p = strrchr (test_input.font_path, '/');
strcat (name, p ? p + 1 : test_input.font_path);
if (!hinting)
strcat (name, "/nohinting");
benchmark::RegisterBenchmark (name, BM_subset, op, test_input, hinting)
->Range(10, test_input.max_subset_size)
->Unit(time_unit);
}
static void test_operation (operation_t op,
const char *op_name,
const test_input_t *tests,
unsigned num_tests,
benchmark::TimeUnit time_unit)
{
for (unsigned i = 0; i < num_tests; i++)
{
auto& test_input = tests[i];
test_subset (op, op_name, true, time_unit, test_input);
test_subset (op, op_name, false, time_unit, test_input);
}
}
int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
if (argc > 1)
{
num_tests = (argc - 1) / 2;
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
for (unsigned i = 0; i < num_tests; i++)
{
tests[i].font_path = argv[1 + i * 2];
tests[i].max_subset_size = atoi (argv[2 + i * 2]);
}
}
#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit)
TEST_OPERATION (subset_glyphs, benchmark::kMillisecond);
TEST_OPERATION (subset_codepoints, benchmark::kMillisecond);
TEST_OPERATION (instance, benchmark::kMillisecond);
#undef TEST_OPERATION
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

62
perf/meson.build Normal file
View file

@ -0,0 +1,62 @@
google_benchmark = subproject('google-benchmark')
google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep')
benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc',
dependencies: [
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc',
dependencies: [
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz, libharfbuzz_subset],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)

View file

@ -1,25 +0,0 @@
#!/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

12391
perf/texts/en-words.txt Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

10000
perf/texts/fa-words.txt Normal file

File diff suppressed because it is too large Load diff

10000
perf/texts/hi-words.txt Normal file

File diff suppressed because it is too large Load diff

250
src/ArabicPUASimplified.txt Normal file
View file

@ -0,0 +1,250 @@
#
# Name: Legacy Simplified Arabic encoding
#
# Format: Three tab-separated columns
# Column #1 is the PUA code (in hex as 0xXXXX)
# Column #2 is the Unicode (in hex as 0xXXXX)
# Column #3 is the Unicode name (follows a comment sign, '#')
#
# The entries are in PUA order
#
0xF100 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE
0xF100 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW
0xF100 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V
0xF100 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE
0xF100 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
0xF100 0x0653 # ARABIC MADDAH ABOVE
0xF100 0x0654 # ARABIC HAMZA ABOVE
0xF100 0x0655 # ARABIC HAMZA BELOW
0xF100 0x0656 # ARABIC SUBSCRIPT ALEF
0xF100 0x0657 # ARABIC INVERTED DAMMA
0xF100 0x0658 # ARABIC MARK NOON GHUNNA
0xF100 0x0659 # ARABIC ZWARAKAY
0xF100 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE
0xF100 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
0xF100 0x065C # ARABIC VOWEL SIGN DOT BELOW
0xF100 0x065D # ARABIC REVERSED DAMMA
0xF100 0x065E # ARABIC FATHA WITH TWO DOTS
0xF10C 0x200C # ZERO WIDTH NON-JOINER
0xF10D 0x200D # ZERO WIDTH JOINER
0xF10E 0x200E # LEFT-TO-RIGHT MARK
0xF10F 0x200F # RIGHT-TO-LEFT MARK
0xF120 0x0020 # SPACE
0xF121 0x0021 # EXCLAMATION MARK
0xF122 0x0022 # QUOTATION MARK
0xF123 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF124 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF125 0x0025 # PERCENT SIGN
0xF126 0x00D7 # MULTIPLICATION SIGN
0xF127 0x00F7 # DIVISION SIGN
0xF128 0x0028 # LEFT PARENTHESIS
0xF129 0x0029 # RIGHT PARENTHESIS
0xF12A 0x002A # ASTERISK
0xF12B 0x002B # PLUS SIGN
0xF12C 0x060C # ARABIC COMMA
0xF12D 0x002D # HYPHEN-MINUS
0xF12E 0x002E # FULL STOP
0xF12F 0x002F # SOLIDUS
0xF130 0x0660 # ARABIC-INDIC DIGIT ZERO
0xF131 0x0661 # ARABIC-INDIC DIGIT ONE
0xF132 0x0662 # ARABIC-INDIC DIGIT TWO
0xF133 0x0663 # ARABIC-INDIC DIGIT THREE
0xF134 0x0664 # ARABIC-INDIC DIGIT FOUR
0xF135 0x0665 # ARABIC-INDIC DIGIT FIVE
0xF136 0x0666 # ARABIC-INDIC DIGIT SIX
0xF137 0x0667 # ARABIC-INDIC DIGIT SEVEN
0xF138 0x0668 # ARABIC-INDIC DIGIT EIGHT
0xF139 0x0669 # ARABIC-INDIC DIGIT NINE
0xF13A 0x003A # COLON
0xF13B 0x003B # SEMICOLON
0xF13B 0x061B # ARABIC SEMICOLON
0xF13C 0x2018 # LEFT SINGLE QUOTATION MARK
0xF13D 0x003D # EQUALS SIGN
0xF13E 0x2019 # RIGHT SINGLE QUOTATION MARK
0xF13F 0x003F # QUESTION MARK
0xF13F 0x061F # ARABIC QUESTION MARK
0xF141 0x0627 # ARABIC LETTER ALEF
0xF141 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM
0xF142 0xFE8E # ARABIC LETTER ALEF FINAL FORM
0xF143 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE
0xF143 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF144 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
0xF145 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE
0xF145 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
0xF146 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
0xF147 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW
0xF147 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM
0xF148 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM
0xF149 0xFE91 # ARABIC LETTER BEH INITIAL FORM
0xF149 0xFE92 # ARABIC LETTER BEH MEDIAL FORM
0xF14A 0x0628 # ARABIC LETTER BEH
0xF14A 0xFE8F # ARABIC LETTER BEH ISOLATED FORM
0xF14A 0xFE90 # ARABIC LETTER BEH FINAL FORM
0xF14B 0xFE97 # ARABIC LETTER TEH INITIAL FORM
0xF14B 0xFE98 # ARABIC LETTER TEH MEDIAL FORM
0xF14C 0x062A # ARABIC LETTER TEH
0xF14C 0xFE95 # ARABIC LETTER TEH ISOLATED FORM
0xF14C 0xFE96 # ARABIC LETTER TEH FINAL FORM
0xF14D 0xFE9B # ARABIC LETTER THEH INITIAL FORM
0xF14D 0xFE9C # ARABIC LETTER THEH MEDIAL FORM
0xF14E 0x062B # ARABIC LETTER THEH
0xF14E 0xFE99 # ARABIC LETTER THEH ISOLATED FORM
0xF14E 0xFE9A # ARABIC LETTER THEH FINAL FORM
0xF14F 0xFE9F # ARABIC LETTER JEEM INITIAL FORM
0xF14F 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM
0xF150 0xFE9E # ARABIC LETTER JEEM FINAL FORM
0xF151 0x062C # ARABIC LETTER JEEM
0xF151 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM
0xF152 0xFEA3 # ARABIC LETTER HAH INITIAL FORM
0xF152 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM
0xF153 0xFEA2 # ARABIC LETTER HAH FINAL FORM
0xF154 0x062D # ARABIC LETTER HAH
0xF154 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM
0xF155 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM
0xF155 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM
0xF156 0xFEA6 # ARABIC LETTER KHAH FINAL FORM
0xF157 0x062E # ARABIC LETTER KHAH
0xF157 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM
0xF158 0x062F # ARABIC LETTER DAL
0xF158 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM
0xF158 0xFEAA # ARABIC LETTER DAL FINAL FORM
0xF159 0x0630 # ARABIC LETTER THAL
0xF159 0xFEAB # ARABIC LETTER THAL ISOLATED FORM
0xF159 0xFEAC # ARABIC LETTER THAL FINAL FORM
0xF15A 0x0631 # ARABIC LETTER REH
0xF15A 0xFEAD # ARABIC LETTER REH ISOLATED FORM
0xF15A 0xFEAE # ARABIC LETTER REH FINAL FORM
0xF15B 0x005B # LEFT SQUARE BRACKET
0xF15C 0x005C # REVERSE SOLIDUS
0xF15D 0x005D # RIGHT SQUARE BRACKET
0xF15E 0x002C # COMMA
0xF15E 0x066B # ARABIC DECIMAL SEPARATOR
0xF15E 0x066C # ARABIC THOUSANDS SEPARATOR
0xF15F 0x0640 # ARABIC TATWEEL
0xF160 0x0632 # ARABIC LETTER ZAIN
0xF160 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM
0xF160 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM
0xF161 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM
0xF161 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM
0xF162 0x0633 # ARABIC LETTER SEEN
0xF162 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM
0xF162 0xFEB2 # ARABIC LETTER SEEN FINAL FORM
0xF163 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM
0xF163 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM
0xF164 0x0634 # ARABIC LETTER SHEEN
0xF164 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM
0xF164 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM
0xF165 0xFEBB # ARABIC LETTER SAD INITIAL FORM
0xF165 0xFEBC # ARABIC LETTER SAD MEDIAL FORM
0xF166 0x0635 # ARABIC LETTER SAD
0xF166 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM
0xF166 0xFEBA # ARABIC LETTER SAD FINAL FORM
0xF167 0xFEBF # ARABIC LETTER DAD INITIAL FORM
0xF167 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM
0xF168 0x0636 # ARABIC LETTER DAD
0xF168 0xFEBD # ARABIC LETTER DAD ISOLATED FORM
0xF168 0xFEBE # ARABIC LETTER DAD FINAL FORM
0xF169 0x0637 # ARABIC LETTER TAH
0xF169 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM
0xF169 0xFEC2 # ARABIC LETTER TAH FINAL FORM
0xF169 0xFEC3 # ARABIC LETTER TAH INITIAL FORM
0xF169 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM
0xF16A 0x0638 # ARABIC LETTER ZAH
0xF16A 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM
0xF16A 0xFEC6 # ARABIC LETTER ZAH FINAL FORM
0xF16A 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM
0xF16A 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM
0xF16B 0xFECB # ARABIC LETTER AIN INITIAL FORM
0xF16C 0xFECC # ARABIC LETTER AIN MEDIAL FORM
0xF16D 0xFECA # ARABIC LETTER AIN FINAL FORM
0xF16E 0x0639 # ARABIC LETTER AIN
0xF16E 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM
0xF16F 0xFECF # ARABIC LETTER GHAIN INITIAL FORM
0xF170 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM
0xF171 0xFECE # ARABIC LETTER GHAIN FINAL FORM
0xF172 0x063A # ARABIC LETTER GHAIN
0xF172 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM
0xF173 0xFED3 # ARABIC LETTER FEH INITIAL FORM
0xF174 0xFED4 # ARABIC LETTER FEH MEDIAL FORM
0xF175 0x0641 # ARABIC LETTER FEH
0xF175 0xFED1 # ARABIC LETTER FEH ISOLATED FORM
0xF175 0xFED2 # ARABIC LETTER FEH FINAL FORM
0xF176 0xFED7 # ARABIC LETTER QAF INITIAL FORM
0xF177 0xFED8 # ARABIC LETTER QAF MEDIAL FORM
0xF178 0x0642 # ARABIC LETTER QAF
0xF178 0xFED5 # ARABIC LETTER QAF ISOLATED FORM
0xF178 0xFED6 # ARABIC LETTER QAF FINAL FORM
0xF179 0xFEDB # ARABIC LETTER KAF INITIAL FORM
0xF179 0xFEDC # ARABIC LETTER KAF MEDIAL FORM
0xF17A 0x0643 # ARABIC LETTER KAF
0xF17A 0xFED9 # ARABIC LETTER KAF ISOLATED FORM
0xF17A 0xFEDA # ARABIC LETTER KAF FINAL FORM
0xF17B 0xFEDF # ARABIC LETTER LAM INITIAL FORM
0xF17B 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM
0xF17C 0x0644 # ARABIC LETTER LAM
0xF17C 0xFEDD # ARABIC LETTER LAM ISOLATED FORM
0xF17C 0xFEDE # ARABIC LETTER LAM FINAL FORM
0xF17D 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM
0xF17D 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM
0xF17E 0x0645 # ARABIC LETTER MEEM
0xF17E 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM
0xF17E 0xFEE2 # ARABIC LETTER MEEM FINAL FORM
0xF17F 0xFEE7 # ARABIC LETTER NOON INITIAL FORM
0xF17F 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM
0xF1A1 0xFEEB # ARABIC LETTER HEH INITIAL FORM
0xF1A2 0xFEEC # ARABIC LETTER HEH MEDIAL FORM
0xF1A3 0xFEEA # ARABIC LETTER HEH FINAL FORM
0xF1A4 0x0647 # ARABIC LETTER HEH
0xF1A4 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM
0xF1A5 0x0648 # ARABIC LETTER WAW
0xF1A5 0xFEED # ARABIC LETTER WAW ISOLATED FORM
0xF1A5 0xFEEE # ARABIC LETTER WAW FINAL FORM
0xF1A6 0xFEF3 # ARABIC LETTER YEH INITIAL FORM
0xF1A6 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM
0xF1A7 0xFEF2 # ARABIC LETTER YEH FINAL FORM
0xF1A8 0x064A # ARABIC LETTER YEH
0xF1A8 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM
0xF1A9 0x0629 # ARABIC LETTER TEH MARBUTA
0xF1A9 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM
0xF1AA 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM
0xF1AB 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM
0xF1AC 0x0649 # ARABIC LETTER ALEF MAKSURA
0xF1AC 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
0xF1AD 0x0621 # ARABIC LETTER HAMZA
0xF1AE 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
0xF1AE 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM
0xF1AF 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
0xF1B0 0x0030 # DIGIT ZERO
0xF1B1 0x0031 # DIGIT ONE
0xF1B2 0x0032 # DIGIT TWO
0xF1B3 0x0033 # DIGIT THREE
0xF1B4 0x0034 # DIGIT FOUR
0xF1B5 0x0035 # DIGIT FIVE
0xF1B6 0x0036 # DIGIT SIX
0xF1B7 0x0037 # DIGIT SEVEN
0xF1B8 0x0038 # DIGIT EIGHT
0xF1B9 0x0039 # DIGIT NINE
0xF1BA 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE
0xF1BA 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
0xF1BB 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE
0xF1BB 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
0xF1BB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM
0xF1BC 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
0xF1BD 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
0xF1BE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF1BF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
0xF1C0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
0xF1C1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
0xF1C2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
0xF1C3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
0xF1C4 0x064E # ARABIC FATHA
0xF1C5 0x064F # ARABIC DAMMA
0xF1C6 0x0652 # ARABIC SUKUN
0xF1C7 0x064B # ARABIC FATHATAN
0xF1C8 0x064C # ARABIC DAMMATAN
0xF1C9 0x0651 # ARABIC SHADDA
0xF1CA 0x0650 # ARABIC KASRA
0xF1CB 0x064D # ARABIC KASRATAN
0xF1E1 0x0646 # ARABIC LETTER NOON
0xF1E1 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM
0xF1E1 0xFEE6 # ARABIC LETTER NOON FINAL FORM

View file

@ -0,0 +1,295 @@
#
# Name: Legacy Traditional Arabic encoding
#
# Format: Three tab-separated columns
# Column #1 is the PUA code (in hex as 0xXXXX)
# Column #2 is the Unicode (in hex as 0xXXXX)
# Column #3 is the Unicode name (follows a comment sign, '#')
#
# The entries are in PUA order
#
0xF200 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE
0xF200 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW
0xF200 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V
0xF200 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE
0xF200 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
0xF200 0x0653 # ARABIC MADDAH ABOVE
0xF200 0x0654 # ARABIC HAMZA ABOVE
0xF200 0x0655 # ARABIC HAMZA BELOW
0xF200 0x0656 # ARABIC SUBSCRIPT ALEF
0xF200 0x0657 # ARABIC INVERTED DAMMA
0xF200 0x0658 # ARABIC MARK NOON GHUNNA
0xF200 0x0659 # ARABIC ZWARAKAY
0xF200 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE
0xF200 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
0xF200 0x065C # ARABIC VOWEL SIGN DOT BELOW
0xF200 0x065D # ARABIC REVERSED DAMMA
0xF200 0x065E # ARABIC FATHA WITH TWO DOTS
0xF202 0xFC08 # ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM
0xF203 0xFC0E # ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM
0xF204 0xFC12 # ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM
0xF205 0xFC42 # ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM
0xF206 0xFC4E # ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM
0xF20C 0x200C # ZERO WIDTH NON-JOINER
0xF20D 0x200D # ZERO WIDTH JOINER
0xF20E 0x200E # LEFT-TO-RIGHT MARK
0xF20F 0x200F # RIGHT-TO-LEFT MARK
0xF210 0xFD88 # ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM
0xF212 0xFC3F # ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM
0xF213 0xFC40 # ARABIC LIGATURE LAM WITH HAH ISOLATED FORM
0xF214 0xFC41 # ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM
0xF215 0xFC6A # ARABIC LIGATURE BEH WITH REH FINAL FORM
0xF216 0xFC70 # ARABIC LIGATURE TEH WITH REH FINAL FORM
0xF217 0xFC91 # ARABIC LIGATURE YEH WITH REH FINAL FORM
0xF218 0xFCB0 # ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM
0xF219 0xFD30 # ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM
0xF21A 0xFCCD # ARABIC LIGATURE LAM WITH HEH INITIAL FORM
0xF21C 0xFC44 # ARABIC LIGATURE LAM WITH YEH ISOLATED FORM
0xF21D 0xFC0A # ARABIC LIGATURE BEH WITH YEH ISOLATED FORM
0xF21E 0xFC10 # ARABIC LIGATURE TEH WITH YEH ISOLATED FORM
0xF21F 0xFC50 # ARABIC LIGATURE NOON WITH YEH ISOLATED FORM
0xF220 0x0020 # SPACE
0xF221 0x0021 # EXCLAMATION MARK
0xF222 0x0022 # QUOTATION MARK
0xF223 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF224 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF225 0x0025 # PERCENT SIGN
0xF226 0x00D7 # MULTIPLICATION SIGN
0xF227 0x00F7 # DIVISION SIGN
0xF228 0x0028 # LEFT PARENTHESIS
0xF229 0x0029 # RIGHT PARENTHESIS
0xF22A 0x002A # ASTERISK
0xF22B 0x002B # PLUS SIGN
0xF22C 0x060C # ARABIC COMMA
0xF22D 0x002D # HYPHEN-MINUS
0xF22E 0x002E # FULL STOP
0xF22F 0x002F # SOLIDUS
0xF230 0x0660 # ARABIC-INDIC DIGIT ZERO
0xF231 0x0661 # ARABIC-INDIC DIGIT ONE
0xF232 0x0662 # ARABIC-INDIC DIGIT TWO
0xF233 0x0663 # ARABIC-INDIC DIGIT THREE
0xF234 0x0664 # ARABIC-INDIC DIGIT FOUR
0xF235 0x0665 # ARABIC-INDIC DIGIT FIVE
0xF236 0x0666 # ARABIC-INDIC DIGIT SIX
0xF237 0x0667 # ARABIC-INDIC DIGIT SEVEN
0xF238 0x0668 # ARABIC-INDIC DIGIT EIGHT
0xF239 0x0669 # ARABIC-INDIC DIGIT NINE
0xF23A 0x003A # COLON
0xF23B 0x003B # SEMICOLON
0xF23B 0x061B # ARABIC SEMICOLON
0xF23C 0x201C # LEFT DOUBLE QUOTATION MARK
0xF23D 0x003D # EQUALS SIGN
0xF23E 0x201D # RIGHT DOUBLE QUOTATION MARK
0xF23F 0x003F # QUESTION MARK
0xF23F 0x061F # ARABIC QUESTION MARK
0xF241 0x0627 # ARABIC LETTER ALEF
0xF241 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM
0xF242 0xFE8E # ARABIC LETTER ALEF FINAL FORM
0xF243 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE
0xF243 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF244 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
0xF245 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE
0xF245 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
0xF246 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
0xF247 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW
0xF247 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM
0xF248 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM
0xF249 0xFE91 # ARABIC LETTER BEH INITIAL FORM
0xF24A 0xFE92 # ARABIC LETTER BEH MEDIAL FORM
0xF24B 0xFE90 # ARABIC LETTER BEH FINAL FORM
0xF24C 0x0628 # ARABIC LETTER BEH
0xF24C 0xFE8F # ARABIC LETTER BEH ISOLATED FORM
0xF24D 0xFE97 # ARABIC LETTER TEH INITIAL FORM
0xF24E 0xFE98 # ARABIC LETTER TEH MEDIAL FORM
0xF24F 0xFE96 # ARABIC LETTER TEH FINAL FORM
0xF250 0x062A # ARABIC LETTER TEH
0xF250 0xFE95 # ARABIC LETTER TEH ISOLATED FORM
0xF251 0xFE9B # ARABIC LETTER THEH INITIAL FORM
0xF252 0xFE9C # ARABIC LETTER THEH MEDIAL FORM
0xF253 0xFE9A # ARABIC LETTER THEH FINAL FORM
0xF254 0x062B # ARABIC LETTER THEH
0xF254 0xFE99 # ARABIC LETTER THEH ISOLATED FORM
0xF255 0xFE9F # ARABIC LETTER JEEM INITIAL FORM
0xF256 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM
0xF257 0xFE9E # ARABIC LETTER JEEM FINAL FORM
0xF258 0x062C # ARABIC LETTER JEEM
0xF258 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM
0xF259 0xFEA3 # ARABIC LETTER HAH INITIAL FORM
0xF25A 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM
0xF25B 0x005B # LEFT SQUARE BRACKET
0xF25C 0xFEA2 # ARABIC LETTER HAH FINAL FORM
0xF25D 0x005D # RIGHT SQUARE BRACKET
0xF25E 0x002C # COMMA
0xF25E 0x066B # ARABIC DECIMAL SEPARATOR
0xF25E 0x066C # ARABIC THOUSANDS SEPARATOR
0xF25F 0x0640 # ARABIC TATWEEL
0xF260 0x062D # ARABIC LETTER HAH
0xF260 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM
0xF261 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM
0xF262 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM
0xF263 0xFEA6 # ARABIC LETTER KHAH FINAL FORM
0xF264 0x062E # ARABIC LETTER KHAH
0xF264 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM
0xF265 0x062F # ARABIC LETTER DAL
0xF265 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM
0xF266 0xFEAA # ARABIC LETTER DAL FINAL FORM
0xF267 0x0630 # ARABIC LETTER THAL
0xF267 0xFEAB # ARABIC LETTER THAL ISOLATED FORM
0xF268 0xFEAC # ARABIC LETTER THAL FINAL FORM
0xF269 0x0631 # ARABIC LETTER REH
0xF269 0xFEAD # ARABIC LETTER REH ISOLATED FORM
0xF26A 0xFEAE # ARABIC LETTER REH FINAL FORM
0xF26B 0x0632 # ARABIC LETTER ZAIN
0xF26B 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM
0xF26C 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM
0xF26D 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM
0xF26E 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM
0xF26F 0xFEB2 # ARABIC LETTER SEEN FINAL FORM
0xF270 0x0633 # ARABIC LETTER SEEN
0xF270 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM
0xF271 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM
0xF272 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM
0xF273 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM
0xF274 0x0634 # ARABIC LETTER SHEEN
0xF274 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM
0xF275 0xFEBB # ARABIC LETTER SAD INITIAL FORM
0xF276 0xFEBC # ARABIC LETTER SAD MEDIAL FORM
0xF277 0xFEBA # ARABIC LETTER SAD FINAL FORM
0xF278 0x0635 # ARABIC LETTER SAD
0xF278 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM
0xF279 0xFEBF # ARABIC LETTER DAD INITIAL FORM
0xF27A 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM
0xF27B 0xFD3E # ORNATE LEFT PARENTHESIS
0xF27C 0xFEBE # ARABIC LETTER DAD FINAL FORM
0xF27D 0xFD3F # ORNATE RIGHT PARENTHESIS
0xF27E 0x0636 # ARABIC LETTER DAD
0xF27E 0xFEBD # ARABIC LETTER DAD ISOLATED FORM
0xF27F 0xFEC3 # ARABIC LETTER TAH INITIAL FORM
0xF280 0xFC9C # ARABIC LIGATURE BEH WITH JEEM INITIAL FORM
0xF281 0xFC9D # ARABIC LIGATURE BEH WITH HAH INITIAL FORM
0xF282 0xFC9E # ARABIC LIGATURE BEH WITH KHAH INITIAL FORM
0xF283 0xFCA1 # ARABIC LIGATURE TEH WITH JEEM INITIAL FORM
0xF284 0xFCA2 # ARABIC LIGATURE TEH WITH HAH INITIAL FORM
0xF285 0xFCA3 # ARABIC LIGATURE TEH WITH KHAH INITIAL FORM
0xF286 0xFCC9 # ARABIC LIGATURE LAM WITH JEEM INITIAL FORM
0xF287 0xFCCA # ARABIC LIGATURE LAM WITH HAH INITIAL FORM
0xF288 0xFCCB # ARABIC LIGATURE LAM WITH KHAH INITIAL FORM
0xF289 0xFCCE # ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM
0xF28A 0xFCCF # ARABIC LIGATURE MEEM WITH HAH INITIAL FORM
0xF28B 0xFCD0 # ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM
0xF28D 0xFCD2 # ARABIC LIGATURE NOON WITH JEEM INITIAL FORM
0xF28E 0xFCD3 # ARABIC LIGATURE NOON WITH HAH INITIAL FORM
0xF28F 0xFCDA # ARABIC LIGATURE YEH WITH JEEM INITIAL FORM
0xF290 0xFCDB # ARABIC LIGATURE YEH WITH HAH INITIAL FORM
0xF291 0xFCDC # ARABIC LIGATURE YEH WITH KHAH INITIAL FORM
0xF292 0xFC6D # ARABIC LIGATURE BEH WITH NOON FINAL FORM
0xF293 0xFC73 # ARABIC LIGATURE TEH WITH NOON FINAL FORM
0xF294 0xFC94 # ARABIC LIGATURE YEH WITH NOON FINAL FORM
0xF295 0xFC86 # ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM
0xF296 0xFC9F # ARABIC LIGATURE BEH WITH MEEM INITIAL FORM
0xF297 0xFCA4 # ARABIC LIGATURE TEH WITH MEEM INITIAL FORM
0xF298 0xFCD5 # ARABIC LIGATURE NOON WITH MEEM INITIAL FORM
0xF299 0xFCDD # ARABIC LIGATURE YEH WITH MEEM INITIAL FORM
0xF29A 0xFCA8 # ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM
0xF29B 0xFCAA # ARABIC LIGATURE HAH WITH MEEM INITIAL FORM
0xF29C 0xFCAC # ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM
0xF29D 0xFCCC # ARABIC LIGATURE LAM WITH MEEM INITIAL FORM
0xF29E 0xFCD1 # ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM
0xF29F 0xFC32 # ARABIC LIGATURE FEH WITH YEH ISOLATED FORM
0xF2A1 0xFEC2 # ARABIC LETTER TAH FINAL FORM
0xF2A2 0x0637 # ARABIC LETTER TAH
0xF2A2 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM
0xF2A3 0x0638 # ARABIC LETTER ZAH
0xF2A3 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM
0xF2A4 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM
0xF2A5 0xFEC6 # ARABIC LETTER ZAH FINAL FORM
0xF2A6 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM
0xF2A7 0xFECB # ARABIC LETTER AIN INITIAL FORM
0xF2A8 0xFECC # ARABIC LETTER AIN MEDIAL FORM
0xF2A9 0xFECA # ARABIC LETTER AIN FINAL FORM
0xF2AA 0x0639 # ARABIC LETTER AIN
0xF2AA 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM
0xF2AB 0xFECF # ARABIC LETTER GHAIN INITIAL FORM
0xF2AC 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM
0xF2AD 0xFECE # ARABIC LETTER GHAIN FINAL FORM
0xF2AE 0x063A # ARABIC LETTER GHAIN
0xF2AE 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM
0xF2AF 0xFED3 # ARABIC LETTER FEH INITIAL FORM
0xF2B0 0xFED4 # ARABIC LETTER FEH MEDIAL FORM
0xF2B1 0xFED2 # ARABIC LETTER FEH FINAL FORM
0xF2B2 0x0641 # ARABIC LETTER FEH
0xF2B2 0xFED1 # ARABIC LETTER FEH ISOLATED FORM
0xF2B3 0xFED7 # ARABIC LETTER QAF INITIAL FORM
0xF2B4 0xFED8 # ARABIC LETTER QAF MEDIAL FORM
0xF2B5 0xFED6 # ARABIC LETTER QAF FINAL FORM
0xF2B6 0x0642 # ARABIC LETTER QAF
0xF2B6 0xFED5 # ARABIC LETTER QAF ISOLATED FORM
0xF2B7 0xFEDB # ARABIC LETTER KAF INITIAL FORM
0xF2B8 0xFEDC # ARABIC LETTER KAF MEDIAL FORM
0xF2B9 0xFEDA # ARABIC LETTER KAF FINAL FORM
0xF2BA 0x0643 # ARABIC LETTER KAF
0xF2BA 0xFED9 # ARABIC LETTER KAF ISOLATED FORM
0xF2BB 0xFEDF # ARABIC LETTER LAM INITIAL FORM
0xF2BC 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM
0xF2BD 0xFEDE # ARABIC LETTER LAM FINAL FORM
0xF2BE 0x0644 # ARABIC LETTER LAM
0xF2BE 0xFEDD # ARABIC LETTER LAM ISOLATED FORM
0xF2BF 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM
0xF2C0 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM
0xF2C1 0xFEE2 # ARABIC LETTER MEEM FINAL FORM
0xF2C2 0x0645 # ARABIC LETTER MEEM
0xF2C2 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM
0xF2C3 0xFEE7 # ARABIC LETTER NOON INITIAL FORM
0xF2C4 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM
0xF2C5 0xFEE6 # ARABIC LETTER NOON FINAL FORM
0xF2C6 0x0646 # ARABIC LETTER NOON
0xF2C6 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM
0xF2C7 0xFEEB # ARABIC LETTER HEH INITIAL FORM
0xF2C8 0xFEEC # ARABIC LETTER HEH MEDIAL FORM
0xF2C9 0xFEEA # ARABIC LETTER HEH FINAL FORM
0xF2CA 0x0647 # ARABIC LETTER HEH
0xF2CA 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM
0xF2CB 0x0648 # ARABIC LETTER WAW
0xF2CB 0xFEED # ARABIC LETTER WAW ISOLATED FORM
0xF2CC 0xFEEE # ARABIC LETTER WAW FINAL FORM
0xF2CD 0xFEF3 # ARABIC LETTER YEH INITIAL FORM
0xF2CE 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM
0xF2CF 0xFEF2 # ARABIC LETTER YEH FINAL FORM
0xF2D0 0x064A # ARABIC LETTER YEH
0xF2D0 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM
0xF2D1 0x0629 # ARABIC LETTER TEH MARBUTA
0xF2D1 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM
0xF2D2 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM
0xF2D3 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM
0xF2D4 0x0649 # ARABIC LETTER ALEF MAKSURA
0xF2D4 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
0xF2D5 0x0621 # ARABIC LETTER HAMZA
0xF2D6 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
0xF2D7 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM
0xF2D8 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
0xF2D9 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE
0xF2D9 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
0xF2DA 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE
0xF2DA 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
0xF2DB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM
0xF2DC 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
0xF2DD 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
0xF2DE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF2DF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
0xF2E0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
0xF2E1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
0xF2E2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
0xF2E3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
0xF2E4 0x064E # ARABIC FATHA
0xF2E5 0x064F # ARABIC DAMMA
0xF2E6 0x0652 # ARABIC SUKUN
0xF2E7 0x064B # ARABIC FATHATAN
0xF2E8 0x064C # ARABIC DAMMATAN
0xF2E9 0x0651 # ARABIC SHADDA
0xF2EA 0x0650 # ARABIC KASRA
0xF2EB 0x064D # ARABIC KASRATAN
0xF2EC 0xFC60 # ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM
0xF2ED 0xFC61 # ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM
0xF2EF 0xFC5E # ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM
0xF2F0 0xFC62 # ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM
0xF2F1 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM

View file

@ -12,7 +12,9 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS =
check_PROGRAMS =
EXTRA_DIST += harfbuzz.cc
EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
EXTRA_DIST += meson.build
EXTRA_DIST += fix_get_types.py
# Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la
@ -45,19 +47,20 @@ HBLIBS += $(GLIB_LIBS)
HBDEPS += $(GLIB_DEPS)
HBSOURCES += $(HB_GLIB_sources)
HBHEADERS += $(HB_GLIB_headers)
HB_HAS_GLIB_DEF = define HB_HAS_GLIB 1
else
HB_HAS_GLIB_DEF = undef HB_HAS_GLIB
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)
HB_HAS_FREETYPE_DEF = define HB_HAS_FREETYPE 1
else
HB_HAS_FREETYPE_DEF = undef HB_HAS_FREETYPE
endif
if HAVE_GRAPHITE2
@ -66,6 +69,9 @@ HBLIBS += $(GRAPHITE2_LIBS)
HBDEPS += $(GRAPHITE2_DEPS)
HBSOURCES += $(HB_GRAPHITE2_sources)
HBHEADERS += $(HB_GRAPHITE2_headers)
HB_HAS_GRAPHITE_DEF = define HB_HAS_GRAPHITE 1
else
HB_HAS_GRAPHITE_DEF = undef HB_HAS_GRAPHITE
endif
if HAVE_UNISCRIBE
@ -73,6 +79,9 @@ HBCFLAGS += $(UNISCRIBE_CFLAGS)
HBNONPCLIBS += $(UNISCRIBE_LIBS)
HBSOURCES += $(HB_UNISCRIBE_sources)
HBHEADERS += $(HB_UNISCRIBE_headers)
HB_HAS_UNISCRIBE_DEF = define HB_HAS_UNISCRIBE 1
else
HB_HAS_UNISCRIBE_DEF = undef HB_HAS_UNISCRIBE
endif
if HAVE_DIRECTWRITE
@ -80,6 +89,9 @@ HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
HBNONPCLIBS += $(DIRECTWRITE_LIBS)
HBSOURCES += $(HB_DIRECTWRITE_sources)
HBHEADERS += $(HB_DIRECTWRITE_headers)
HB_HAS_DIRECTWRITE_DEF = define HB_HAS_DIRECTWRITE 1
else
HB_HAS_DIRECTWRITE_DEF = undef HB_HAS_DIRECTWRITE
endif
if HAVE_GDI
@ -87,6 +99,9 @@ HBCFLAGS += $(GDI_CXXFLAGS)
HBNONPCLIBS += $(GDI_LIBS)
HBSOURCES += $(HB_GDI_sources)
HBHEADERS += $(HB_GDI_headers)
HB_HAS_GDI_DEF = define HB_HAS_GDI 1
else
HB_HAS_GDI_DEF = undef HB_HAS_GDI
endif
if HAVE_CORETEXT
@ -94,6 +109,9 @@ HBCFLAGS += $(CORETEXT_CFLAGS)
HBNONPCLIBS += $(CORETEXT_LIBS)
HBSOURCES += $(HB_CORETEXT_sources)
HBHEADERS += $(HB_CORETEXT_headers)
HB_HAS_CORETEXT_DEF = define HB_HAS_CORETEXT 1
else
HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT
endif
@ -117,6 +135,8 @@ export_symbols = -export-symbols harfbuzz.def
harfbuzz_def_dependency = harfbuzz.def
export_symbols_subset = -export-symbols harfbuzz-subset.def
harfbuzz_subset_def_dependency = harfbuzz-subset.def
export_symbols_cairo = -export-symbols harfbuzz-cairo.def
harfbuzz_cairo_def_dependency = harfbuzz-cairo.def
export_symbols_icu = -export-symbols harfbuzz-icu.def
harfbuzz_icu_def_dependency = harfbuzz-icu.def
export_symbols_gobject = -export-symbols harfbuzz-gobject.def
@ -150,9 +170,10 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
cmakedir = $(libdir)/cmake/harfbuzz
cmake_DATA = harfbuzz-config.cmake
EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
EXTRA_DIST += hb-version.h.in hb-features.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)
@ -162,12 +183,36 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
pkgconfig_DATA += harfbuzz-subset.pc
EXTRA_DIST += harfbuzz-subset.pc.in
harfbuzz-subset.cc: Makefile.sources
$(AM_V_GEN) \
LANG=C; \
for f in \
$(HB_BASE_sources) \
$(HB_SUBSET_sources) \
; do echo '#include "'$$f'"'; done | \
sort -u | \
grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \
|| ($(RM) $(srcdir)/harfbuzz-subset.cc; false)
BUILT_SOURCES += harfbuzz-subset.cc
lib_LTLIBRARIES += libharfbuzz-cairo.la
libharfbuzz_cairo_la_LINK = $(chosen_linker) $(libharfbuzz_cairo_la_LDFLAGS)
libharfbuzz_cairo_la_SOURCES = $(HB_CAIRO_sources)
libharfbuzz_cairo_la_CPPFLAGS = $(HBCFLAGS) $(CAIRO_CFLAGS) $(CODE_COVERAGE_CFLAGS)
libharfbuzz_cairo_la_LDFLAGS = $(base_link_flags) $(export_symbols_cairo) $(CODE_COVERAGE_LDFLAGS)
libharfbuzz_cairo_la_LIBADD = $(CAIRO_LIBS) libharfbuzz.la
EXTRA_libharfbuzz_cairo_la_DEPENDENCIES = $(harfbuzz_cairo_def_dependency)
pkginclude_HEADERS += $(HB_CAIRO_headers)
pkgconfig_DATA += harfbuzz-cairo.pc
EXTRA_DIST += harfbuzz-cairo.pc.in
if HAVE_ICU
if HAVE_ICU_BUILTIN
HBCFLAGS += $(ICU_CFLAGS)
HBLIBS += $(ICU_LIBS)
HBSOURCES += $(HB_ICU_sources)
HBHEADERS += $(HB_ICU_headers)
HB_HAS_ICU_DEF = define HB_HAS_ICU 1
else
lib_LTLIBRARIES += libharfbuzz-icu.la
libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
@ -177,6 +222,7 @@ libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency)
pkginclude_HEADERS += $(HB_ICU_headers)
pkgconfig_DATA += harfbuzz-icu.pc
HB_HAS_ICU_DEF = undef HB_HAS_ICU
endif
endif
EXTRA_DIST += harfbuzz-icu.pc.in
@ -208,6 +254,9 @@ hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
--template $^ | \
sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
|| ($(RM) "$@"; false)
HB_HAS_GOBJECT_DEF = define HB_HAS_GOBJECT 1
else
HB_HAS_GOBJECT_DEF = undef HB_HAS_GOBJECT
endif
EXTRA_DIST += \
harfbuzz-gobject.pc.in \
@ -216,6 +265,27 @@ EXTRA_DIST += \
$(NULL)
BUILT_SOURCES += \
hb-features.h
DISTCLEANFILES += \
hb-features.h
hb-features.h: hb-features.h.in $(top_builddir)/config.status
$(AM_V_GEN) $(SED) \
-e 's/mesondefine HB_HAS_CAIRO/$(HB_HAS_CAIRO_DEF)/' \
-e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \
-e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
-e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
-e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
-e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \
-e 's/mesondefine HB_HAS_GOBJECT/$(HB_HAS_GOBJECT_DEF)/' \
-e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
-e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
-e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
-e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \
"$<" > "$@" || ($(RM) "$@"; false)
%.pc: %.pc.in $(top_builddir)/config.status
$(AM_V_GEN) \
$(SED) -e 's@%prefix%@$(prefix)@g' \
@ -237,10 +307,13 @@ 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 "$@" $^
harfbuzz-cairo.def: $(HB_CAIRO_headers)
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-icu.def: $(HB_ICU_headers)
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-gobject.def: $(HB_GOBJECT_headers)
@ -250,11 +323,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 +339,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 ms-use/IndicShapingInvalidCluster.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)) \
@ -314,6 +358,7 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
harfbuzz.cc: Makefile.sources
$(AM_V_GEN) \
LANG=C; \
for f in \
$(HB_BASE_sources) \
$(HB_GLIB_sources) \
@ -324,6 +369,7 @@ harfbuzz.cc: Makefile.sources
$(HB_DIRECTWRITE_sources) \
$(HB_CORETEXT_sources) \
; do echo '#include "'$$f'"'; done | \
sort -u | \
grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
|| ($(RM) $(srcdir)/harfbuzz.cc; false)
BUILT_SOURCES += harfbuzz.cc
@ -336,7 +382,9 @@ noinst_PROGRAMS = \
test-ot-name \
test-ot-glyphname \
test-gpos-size-params \
test-gsub-get-alternates \
test-gsub-would-substitute \
test-use-table \
$(NULL)
bin_PROGRAMS =
@ -364,30 +412,39 @@ test_ot_glyphname_SOURCES = test-ot-glyphname.cc
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
test_use_table_SOURCES = test-use-table.cc
test_use_table_CPPFLAGS = $(HBCFLAGS)
test_use_table_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)
test_gsub_get_alternates_SOURCES = test-gsub-get-alternates.cc
test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS)
test_gsub_get_alternates_LDADD = libharfbuzz.la $(HBLIBS)
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 \
COMPILED_TESTS = \
test-algs \
test-array \
test-bimap \
test-iter \
test-machinery \
test-map \
test-multimap \
test-number \
test-ot-tag \
test-priority-queue \
test-set \
test-serialize \
test-unicode-ranges \
test-vector \
test-repacker \
test-classdef-graph \
$(NULL)
TESTS += $(dist_check_SCRIPTS)
@ -436,56 +493,120 @@ COMPILED_TESTS = \
test_algs_SOURCES = test-algs.cc $(COMPILED_TESTS_SOURCES)
test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_algs_LDADD = $(COMPILED_TESTS_LDADD)
test_bimap_SOURCES = test-bimap.cc $(COMPILED_TESTS_SOURCES)
test_array_SOURCES = test-array.cc
test_array_CPPFLAGS = $(HBCFLAGS)
test_array_LDADD = libharfbuzz.la $(HBLIBS)
test_bimap_SOURCES = test-bimap.cc hb-static.cc
test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
test_iter_SOURCES = test-iter.cc $(COMPILED_TESTS_SOURCES)
test_iter_SOURCES = test-iter.cc hb-static.cc
test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_iter_LDADD = $(COMPILED_TESTS_LDADD)
test_meta_SOURCES = test-meta.cc $(COMPILED_TESTS_SOURCES)
test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_meta_LDADD = $(COMPILED_TESTS_LDADD)
test_number_SOURCES = test-number.cc $(COMPILED_TESTS_SOURCES)
test_machinery_SOURCES = test-machinery.cc hb-static.cc
test_machinery_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_machinery_LDADD = $(COMPILED_TESTS_LDADD)
test_map_SOURCES = test-map.cc hb-static.cc
test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_map_LDADD = $(COMPILED_TESTS_LDADD)
test_multimap_SOURCES = test-multimap.cc hb-static.cc
test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_multimap_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 $(COMPILED_TESTS_SOURCES)
test_ot_tag_SOURCES = hb-ot-tag.cc
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
test_simd_SOURCES = test-simd.cc $(COMPILED_TESTS_SOURCES)
test_simd_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_simd_LDADD = $(COMPILED_TESTS_LDADD)
test_unicode_ranges_SOURCES = test-unicode-ranges.cc $(COMPILED_TESTS_SOURCES)
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 graph/gsubgpos-context.cc
test_repacker_CPPFLAGS = $(HBCFLAGS)
test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
test_classdef_graph_SOURCES = graph/test-classdef-graph.cc hb-static.cc graph/gsubgpos-context.cc
test_classdef_graph_CPPFLAGS = $(HBCFLAGS)
test_classdef_graph_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
test_set_SOURCES = test-set.cc hb-static.cc
test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_set_LDADD = $(COMPILED_TESTS_LDADD)
test_serialize_SOURCES = test-serialize.cc hb-static.cc
test_serialize_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_serialize_LDADD = $(COMPILED_TESTS_LDADD)
test_unicode_ranges_SOURCES = test-unicode-ranges.cc
test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
test_vector_SOURCES = test-vector.cc hb-static.cc
test_vector_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_vector_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
>>>>>>> main
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
base_srcdir="$(srcdir)" \
builddir="$(builddir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
HBSOURCES="$(HBSOURCES)" \
HBHEADERS="$(HBHEADERS)" \
LDD="$(LDD)" \
NM="$(NM)" \
OBJDUMP="$(OBJDUMP)" \
OTOOL="$(OTOOL)" \
$(NULL)
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)"
HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
HarfBuzz_0_0_gir_INCLUDES = GObject-2.0 freetype2-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)

View file

@ -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,9 +18,14 @@ HB_BASE_sources = \
hb-algs.hh \
hb-array.hh \
hb-atomic.hh \
hb-bimap.hh \
hb-bit-page.hh \
hb-bit-set.hh \
hb-bit-set-invertible.hh \
hb-blob.cc \
hb-blob.hh \
hb-buffer-serialize.cc \
hb-buffer-verify.cc \
hb-buffer.cc \
hb-buffer.hh \
hb-cache.hh \
@ -35,18 +38,23 @@ 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-face-builder.cc \
hb-fallback-shape.cc \
hb-font.cc \
hb-font.hh \
hb-iter.hh \
hb-kern.hh \
hb-limits.hh \
hb-machinery.hh \
hb-map.cc \
hb-map.hh \
hb-bimap.hh \
hb-meta.hh \
hb-ms-feature-ranges.hh \
hb-multimap.hh \
hb-mutex.hh \
hb-null.hh \
hb-number.cc \
@ -55,21 +63,16 @@ HB_BASE_sources = \
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-cff1-std-str.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-face-table-list.hh \
hb-ot-font.cc \
hb-ot-gasp-table.hh \
hb-ot-glyf-table.hh \
@ -82,7 +85,91 @@ HB_BASE_sources = \
hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-outline.hh \
hb-outline.cc \
hb-paint.cc \
hb-paint.hh \
hb-paint-extents.cc \
hb-paint-extents.hh \
hb-ot-layout-gsub-table.hh \
OT/Color/CBDT/CBDT.hh \
OT/Color/COLR/COLR.hh \
OT/Color/CPAL/CPAL.hh \
OT/Color/sbix/sbix.hh \
OT/Color/svg/svg.hh \
OT/glyf/glyf.hh \
OT/glyf/glyf-helpers.hh \
OT/glyf/loca.hh \
OT/glyf/path-builder.hh \
OT/glyf/Glyph.hh \
OT/glyf/GlyphHeader.hh \
OT/glyf/SimpleGlyph.hh \
OT/glyf/coord-setter.hh \
OT/glyf/composite-iter.hh \
OT/glyf/CompositeGlyph.hh \
OT/glyf/VarCompositeGlyph.hh \
OT/glyf/SubsetGlyph.hh \
OT/Layout/types.hh \
OT/Layout/Common/Coverage.hh \
OT/Layout/Common/CoverageFormat1.hh \
OT/Layout/Common/CoverageFormat2.hh \
OT/Layout/Common/RangeRecord.hh \
OT/Layout/GDEF/GDEF.hh \
OT/Layout/GPOS/AnchorFormat1.hh \
OT/Layout/GPOS/AnchorFormat2.hh \
OT/Layout/GPOS/AnchorFormat3.hh \
OT/Layout/GPOS/Anchor.hh \
OT/Layout/GPOS/AnchorMatrix.hh \
OT/Layout/GPOS/ChainContextPos.hh \
OT/Layout/GPOS/Common.hh \
OT/Layout/GPOS/ContextPos.hh \
OT/Layout/GPOS/CursivePosFormat1.hh \
OT/Layout/GPOS/CursivePos.hh \
OT/Layout/GPOS/ExtensionPos.hh \
OT/Layout/GPOS/GPOS.hh \
OT/Layout/GPOS/LigatureArray.hh \
OT/Layout/GPOS/MarkArray.hh \
OT/Layout/GPOS/MarkBasePosFormat1.hh \
OT/Layout/GPOS/MarkBasePos.hh \
OT/Layout/GPOS/MarkLigPosFormat1.hh \
OT/Layout/GPOS/MarkLigPos.hh \
OT/Layout/GPOS/MarkMarkPosFormat1.hh \
OT/Layout/GPOS/MarkMarkPos.hh \
OT/Layout/GPOS/MarkRecord.hh \
OT/Layout/GPOS/PairPosFormat1.hh \
OT/Layout/GPOS/PairPosFormat2.hh \
OT/Layout/GPOS/PairPos.hh \
OT/Layout/GPOS/PairSet.hh \
OT/Layout/GPOS/PairValueRecord.hh \
OT/Layout/GPOS/PosLookup.hh \
OT/Layout/GPOS/PosLookupSubTable.hh \
OT/Layout/GPOS/SinglePosFormat1.hh \
OT/Layout/GPOS/SinglePosFormat2.hh \
OT/Layout/GPOS/SinglePos.hh \
OT/Layout/GPOS/ValueFormat.hh \
OT/Layout/GSUB/AlternateSet.hh \
OT/Layout/GSUB/AlternateSubstFormat1.hh \
OT/Layout/GSUB/AlternateSubst.hh \
OT/Layout/GSUB/ChainContextSubst.hh \
OT/Layout/GSUB/Common.hh \
OT/Layout/GSUB/ContextSubst.hh \
OT/Layout/GSUB/ExtensionSubst.hh \
OT/Layout/GSUB/GSUB.hh \
OT/Layout/GSUB/Ligature.hh \
OT/Layout/GSUB/LigatureSet.hh \
OT/Layout/GSUB/LigatureSubstFormat1.hh \
OT/Layout/GSUB/LigatureSubst.hh \
OT/Layout/GSUB/MultipleSubstFormat1.hh \
OT/Layout/GSUB/MultipleSubst.hh \
OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
OT/Layout/GSUB/ReverseChainSingleSubst.hh \
OT/Layout/GSUB/Sequence.hh \
OT/Layout/GSUB/SingleSubstFormat1.hh \
OT/Layout/GSUB/SingleSubstFormat2.hh \
OT/Layout/GSUB/SingleSubst.hh \
OT/Layout/GSUB/SubstLookup.hh \
OT/Layout/GSUB/SubstLookupSubTable.hh \
OT/name/name.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout.cc \
@ -104,28 +191,29 @@ HB_BASE_sources = \
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-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-thai.cc \
hb-ot-shape-complex-use-table.cc \
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 \
hb-ot-shaper-arabic-fallback.hh \
hb-ot-shaper-arabic-joining-list.hh \
hb-ot-shaper-arabic-pua.hh \
hb-ot-shaper-arabic-table.hh \
hb-ot-shaper-arabic-win1256.hh \
hb-ot-shaper-arabic.cc \
hb-ot-shaper-arabic.hh \
hb-ot-shaper-default.cc \
hb-ot-shaper-hangul.cc \
hb-ot-shaper-hebrew.cc \
hb-ot-shaper-indic-table.cc \
hb-ot-shaper-indic.cc \
hb-ot-shaper-indic.hh \
hb-ot-shaper-khmer.cc \
hb-ot-shaper-myanmar.cc \
hb-ot-shaper-syllabic.cc \
hb-ot-shaper-syllabic.hh \
hb-ot-shaper-thai.cc \
hb-ot-shaper-use-table.hh \
hb-ot-shaper-use.cc \
hb-ot-shaper-vowel-constraints.cc \
hb-ot-shaper-vowel-constraints.hh \
hb-ot-shaper.hh \
hb-ot-shape-fallback.cc \
hb-ot-shape-fallback.hh \
hb-ot-shape-normalize.cc \
@ -136,6 +224,8 @@ HB_BASE_sources = \
hb-ot-tag-table.hh \
hb-ot-tag.cc \
hb-ot-var-avar-table.hh \
hb-ot-var-common.hh \
hb-ot-var-cvar-table.hh \
hb-ot-var-fvar-table.hh \
hb-ot-var-gvar-table.hh \
hb-ot-var-hvar-table.hh \
@ -158,6 +248,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 \
@ -165,26 +256,29 @@ HB_BASE_sources = \
hb-unicode.hh \
hb-utf.hh \
hb-vector.hh \
hb-priority-queue.hh \
hb.hh \
$(NULL)
HB_BASE_RAGEL_GENERATED_sources = \
hb-buffer-deserialize-json.hh \
hb-buffer-deserialize-text.hh \
hb-buffer-deserialize-text-glyphs.hh \
hb-buffer-deserialize-text-unicode.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-ot-shaper-indic-machine.hh \
hb-ot-shaper-khmer-machine.hh \
hb-ot-shaper-myanmar-machine.hh \
hb-ot-shaper-use-machine.hh \
$(NULL)
HB_BASE_RAGEL_sources = \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text.rl \
hb-buffer-deserialize-text-glyphs.rl \
hb-buffer-deserialize-text-unicode.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-ot-shaper-indic-machine.rl \
hb-ot-shaper-khmer-machine.rl \
hb-ot-shaper-myanmar-machine.rl \
hb-ot-shaper-use-machine.rl \
$(NULL)
HB_BASE_headers = \
@ -193,7 +287,9 @@ HB_BASE_headers = \
hb-blob.h \
hb-buffer.h \
hb-common.h \
hb-cplusplus.hh \
hb-deprecated.h \
hb-draw.h \
hb-face.h \
hb-font.h \
hb-map.h \
@ -208,9 +304,11 @@ HB_BASE_headers = \
hb-ot-shape.h \
hb-ot-var.h \
hb-ot.h \
hb-paint.h \
hb-set.h \
hb-shape-plan.h \
hb-shape.h \
hb-style.h \
hb-unicode.h \
hb-version.h \
hb.h \
@ -218,7 +316,7 @@ HB_BASE_headers = \
# Optional Sources and Headers with external deps
HB_FT_sources = hb-ft.cc
HB_FT_sources = hb-ft.cc hb-ft-colr.hh
HB_FT_headers = hb-ft.h
HB_GLIB_sources = hb-glib.cc
@ -251,6 +349,7 @@ HB_SUBSET_sources = \
hb-number.hh \
hb-ot-cff1-table.cc \
hb-ot-cff2-table.cc \
hb-ot-post-table-v2subset.hh \
hb-static.cc \
hb-subset-cff-common.cc \
hb-subset-cff-common.hh \
@ -260,16 +359,40 @@ HB_SUBSET_sources = \
hb-subset-cff2.hh \
hb-subset-input.cc \
hb-subset-input.hh \
hb-subset-instancer-solver.cc \
hb-subset-accelerator.hh \
hb-subset-plan.cc \
hb-subset-plan.hh \
hb-subset-plan.hh \
hb-subset-repacker.cc \
hb-subset.cc \
hb-subset.hh \
hb-subset.hh \
hb-repacker.hh \
graph/graph.hh \
graph/gsubgpos-graph.hh \
graph/gsubgpos-context.hh \
graph/gsubgpos-context.cc \
graph/coverage-graph.hh \
graph/classdef-graph.hh \
graph/pairpos-graph.hh \
graph/markbasepos-graph.hh \
graph/split-helpers.hh \
graph/serialize.hh \
OT/Color/COLR/colrv1-closure.hh \
$(NULL)
HB_SUBSET_headers = \
hb-subset.h \
hb-subset-repacker.h \
$(NULL)
HB_CAIRO_sources = \
hb-cairo.cc \
hb-cairo-utils.cc \
hb-cairo-utils.hh \
hb-static.cc \
$(NULL)
HB_CAIRO_headers = \
hb-cairo.h \
$(NULL)
HB_GOBJECT_DIST_sources = hb-gobject-structs.cc

1030
src/OT/Color/CBDT/CBDT.hh Normal file

File diff suppressed because it is too large Load diff

2436
src/OT/Color/COLR/COLR.hh Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,107 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* 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.
*
*/
#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH
#define OT_COLOR_COLR_COLRV1_CLOSURE_HH
#include "../../../hb-open-type.hh"
#include "COLR.hh"
/*
* COLR -- Color
* https://docs.microsoft.com/en-us/typography/opentype/spec/colr
*/
namespace OT {
HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) const
{
c->add_layer_indices (firstLayerIndex, numLayers);
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
const Paint &paint = std::addressof (paint_offset_lists) + paint_offset_lists[i];
paint.dispatch (c);
}
}
HB_INTERNAL void PaintGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
{
c->add_glyph (gid);
(this+paint).dispatch (c);
}
HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
{
const COLR *colr_table = c->get_colr_table ();
const BaseGlyphPaintRecord* baseglyph_paintrecord = colr_table->get_base_glyph_paintrecord (gid);
if (!baseglyph_paintrecord) return;
c->add_glyph (gid);
const BaseGlyphList &baseglyph_list = colr_table->get_baseglyphList ();
(&baseglyph_list+baseglyph_paintrecord->paint).dispatch (c);
}
template <template<typename> class Var>
HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintTranslate::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintScale::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintScaleAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintScaleUniform::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintScaleUniformAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintRotate::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintRotateAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintSkew::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintSkewAroundCenter::closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+src).dispatch (c); }
HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
{
(this+src).dispatch (c);
(this+backdrop).dispatch (c);
}
} /* namespace OT */
#endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */

350
src/OT/Color/CPAL/CPAL.hh Normal file
View file

@ -0,0 +1,350 @@
/*
* Copyright © 2016 Google, Inc.
* 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.
*
* Google Author(s): Sascha Brawer
*/
#ifndef OT_COLOR_CPAL_CPAL_HH
#define OT_COLOR_CPAL_CPAL_HH
#include "../../../hb-open-type.hh"
#include "../../../hb-ot-color.h"
#include "../../../hb-ot-name.h"
/*
* CPAL -- Color Palette
* https://docs.microsoft.com/en-us/typography/opentype/spec/cpal
*/
#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
namespace OT {
struct CPALV1Tail
{
friend struct CPAL;
private:
hb_ot_color_palette_flags_t get_palette_flags (const void *base,
unsigned int palette_index,
unsigned int palette_count) const
{
if (!paletteFlagsZ) return HB_OT_COLOR_PALETTE_FLAG_DEFAULT;
return (hb_ot_color_palette_flags_t) (uint32_t)
(base+paletteFlagsZ).as_array (palette_count)[palette_index];
}
hb_ot_name_id_t get_palette_name_id (const void *base,
unsigned int palette_index,
unsigned int palette_count) const
{
if (!paletteLabelsZ) return HB_OT_NAME_ID_INVALID;
return (base+paletteLabelsZ).as_array (palette_count)[palette_index];
}
hb_ot_name_id_t get_color_name_id (const void *base,
unsigned int color_index,
unsigned int color_count) const
{
if (!colorLabelsZ) return HB_OT_NAME_ID_INVALID;
return (base+colorLabelsZ).as_array (color_count)[color_index];
}
public:
void collect_name_ids (const void *base,
unsigned palette_count,
unsigned color_count,
const hb_map_t *color_index_map,
hb_set_t *nameids_to_retain /* OUT */) const
{
if (paletteLabelsZ)
{
+ (base+paletteLabelsZ).as_array (palette_count)
| hb_sink (nameids_to_retain)
;
}
if (colorLabelsZ)
{
const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
for (unsigned i = 0; i < color_count; i++)
{
if (!color_index_map->has (i)) continue;
nameids_to_retain->add (colorLabels[i]);
}
}
}
bool serialize (hb_serialize_context_t *c,
unsigned palette_count,
unsigned color_count,
const void *base,
const hb_map_t *color_index_map) const
{
TRACE_SERIALIZE (this);
auto *out = c->allocate_size<CPALV1Tail> (static_size);
if (unlikely (!out)) return_trace (false);
out->paletteFlagsZ = 0;
if (paletteFlagsZ)
out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
out->paletteLabelsZ = 0;
if (paletteLabelsZ)
out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
if (colorLabelsZ)
{
c->push ();
for (unsigned i = 0; i < color_count; i++)
{
if (!color_index_map->has (i)) continue;
if (!c->copy<NameID> (colorLabels[i]))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (out->colorLabelsZ, c->pop_pack ());
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c,
const void *base,
unsigned int palette_count,
unsigned int color_count) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
(!paletteFlagsZ || (base+paletteFlagsZ).sanitize (c, palette_count)) &&
(!paletteLabelsZ || (base+paletteLabelsZ).sanitize (c, palette_count)) &&
(!colorLabelsZ || (base+colorLabelsZ).sanitize (c, color_count)));
}
protected:
// TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
// here. Currently they are needed since UnsizedArrayOf doesn't define null_size
NNOffset32To<UnsizedArrayOf<HBUINT32>>
paletteFlagsZ; /* Offset from the beginning of CPAL table to
* the Palette Type Array. Set to 0 if no array
* is provided. */
NNOffset32To<UnsizedArrayOf<NameID>>
paletteLabelsZ; /* Offset from the beginning of CPAL table to
* the palette labels array. Set to 0 if no
* array is provided. */
NNOffset32To<UnsizedArrayOf<NameID>>
colorLabelsZ; /* Offset from the beginning of CPAL table to
* the color labels array. Set to 0
* if no array is provided. */
public:
DEFINE_SIZE_STATIC (12);
};
typedef HBUINT32 BGRAColor;
struct CPAL
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_CPAL;
bool has_data () const { return numPalettes; }
unsigned int get_size () const
{ return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
unsigned int get_palette_count () const { return numPalettes; }
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); }
hb_ot_name_id_t get_palette_name_id (unsigned int palette_index) const
{ return v1 ().get_palette_name_id (this, palette_index, numPalettes); }
hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
{ return v1 ().get_color_name_id (this, color_index, numColors); }
unsigned int get_palette_colors (unsigned int palette_index,
unsigned int start_offset,
unsigned int *color_count, /* IN/OUT. May be NULL. */
hb_color_t *colors /* OUT. May be NULL. */) const
{
if (unlikely (palette_index >= numPalettes))
{
if (color_count) *color_count = 0;
return 0;
}
unsigned int start_index = colorRecordIndicesZ[palette_index];
hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords);
hb_array_t<const BGRAColor> palette_colors = all_colors.sub_array (start_index,
numColors);
if (color_count)
{
+ palette_colors.sub_array (start_offset, color_count)
| hb_sink (hb_array (colors, *color_count))
;
}
return numColors;
}
void collect_name_ids (const hb_map_t *color_index_map,
hb_set_t *nameids_to_retain /* OUT */) const
{
if (version == 1)
v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
}
private:
const CPALV1Tail& v1 () const
{
if (version == 0) return Null (CPALV1Tail);
return StructAfter<CPALV1Tail> (*this);
}
public:
bool serialize (hb_serialize_context_t *c,
const hb_array_t<const HBUINT16> &color_record_indices,
const hb_array_t<const BGRAColor> &color_records,
const hb_vector_t<unsigned>& first_color_index_for_layer,
const hb_map_t& first_color_to_layer_index,
const hb_set_t &retained_color_indices) const
{
TRACE_SERIALIZE (this);
// TODO(grieger): limit total final size.
for (const auto idx : color_record_indices)
{
hb_codepoint_t layer_index = first_color_to_layer_index[idx];
HBUINT16 new_idx;
new_idx = layer_index * retained_color_indices.get_population ();
if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
}
c->push ();
for (unsigned first_color_index : first_color_index_for_layer)
{
for (hb_codepoint_t color_index : retained_color_indices)
{
if (!c->copy<BGRAColor> (color_records[first_color_index + color_index]))
{
c->pop_discard ();
return_trace (false);
}
}
}
c->add_link (colorRecordsZ, c->pop_pack ());
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
if (!numPalettes) return_trace (false);
const hb_map_t *color_index_map = &c->plan->colr_palettes;
if (color_index_map->is_empty ()) return_trace (false);
hb_set_t retained_color_indices;
for (const auto _ : color_index_map->keys ())
{
if (_ == 0xFFFF) continue;
retained_color_indices.add (_);
}
if (retained_color_indices.is_empty ()) return_trace (false);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->version = version;
out->numColors = retained_color_indices.get_population ();
out->numPalettes = numPalettes;
hb_vector_t<unsigned> first_color_index_for_layer;
hb_map_t first_color_to_layer_index;
const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
for (const auto first_color_record_idx : colorRecordIndices)
{
if (first_color_to_layer_index.has (first_color_record_idx)) continue;
first_color_index_for_layer.push (first_color_record_idx);
first_color_to_layer_index.set (first_color_record_idx,
first_color_index_for_layer.length - 1);
}
out->numColorRecords = first_color_index_for_layer.length
* retained_color_indices.get_population ();
const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
if (!out->serialize (c->serializer,
colorRecordIndices,
color_records,
first_color_index_for_layer,
first_color_to_layer_index,
retained_color_indices))
return_trace (false);
if (version == 1)
return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
(this+colorRecordsZ).sanitize (c, numColorRecords) &&
colorRecordIndicesZ.sanitize (c, numPalettes) &&
(version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
}
protected:
HBUINT16 version; /* Table version number */
/* Version 0 */
HBUINT16 numColors; /* Number of colors in each palette. */
HBUINT16 numPalettes; /* Number of palettes in the table. */
HBUINT16 numColorRecords; /* Total number of color records, combined for
* all palettes. */
NNOffset32To<UnsizedArrayOf<BGRAColor>>
colorRecordsZ; /* Offset from the beginning of CPAL table to
* the first ColorRecord. */
UnsizedArrayOf<HBUINT16>
colorRecordIndicesZ; /* Index of each palettes first color record in
* the combined color record array. */
/*CPALV1Tail v1;*/
public:
DEFINE_SIZE_ARRAY (12, colorRecordIndicesZ);
};
} /* namespace OT */
#endif /* OT_COLOR_CPAL_CPAL_HH */

452
src/OT/Color/sbix/sbix.hh Normal file
View file

@ -0,0 +1,452 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* 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
*/
#ifndef OT_COLOR_SBIX_SBIX_HH
#define OT_COLOR_SBIX_SBIX_HH
#include "../../../hb-open-type.hh"
#include "../../../hb-paint.hh"
/*
* sbix -- Standard Bitmap Graphics
* https://docs.microsoft.com/en-us/typography/opentype/spec/sbix
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6sbix.html
*/
#define HB_OT_TAG_sbix HB_TAG('s','b','i','x')
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<SBIXGlyph> ();
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 glyphs origin.
* That is, the x-coordinate of the point on the
* baseline at the left edge of the glyph. */
HBINT16 yOffset; /* The vertical (y-axis) offset from the bottom
* edge of the graphic to the glyphs origin.
* That is, the y-coordinate of the point on the
* baseline at the left edge of the glyph. */
Tag graphicType; /* Indicates the format of the embedded graphic
* data: one of 'jpg ', 'png ' or 'tiff', or the
* special format 'dupe'. */
UnsizedArrayOf<HBUINT8>
data; /* The actual embedded graphic data. The total
* length is inferred from sequential entries in
* the glyphDataOffsets array and the fixed size
* (8 bytes) of the preceding fields. */
public:
DEFINE_SIZE_ARRAY (8, data);
};
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);
return_trace (c->check_struct (this) &&
imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1));
}
hb_blob_t *get_glyph_blob (unsigned int glyph_id,
hb_blob_t *sbix_blob,
hb_tag_t file_type,
int *x_offset,
int *y_offset,
unsigned int num_glyphs,
unsigned int *strike_ppem) const
{
if (unlikely (!ppem)) return hb_blob_get_empty (); /* To get Null() object out of the way. */
unsigned int retry_count = 8;
unsigned int sbix_len = sbix_blob->length;
unsigned int strike_offset = (const char *) this - (const char *) sbix_blob->data;
assert (strike_offset < sbix_len);
retry:
if (unlikely (glyph_id >= num_glyphs ||
imageOffsetsZ[glyph_id + 1] <= imageOffsetsZ[glyph_id] ||
imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] <= SBIXGlyph::min_size ||
(unsigned int) imageOffsetsZ[glyph_id + 1] > sbix_len - strike_offset))
return hb_blob_get_empty ();
unsigned int glyph_offset = strike_offset + (unsigned int) imageOffsetsZ[glyph_id] + SBIXGlyph::min_size;
unsigned int glyph_length = imageOffsetsZ[glyph_id + 1] - imageOffsetsZ[glyph_id] - SBIXGlyph::min_size;
const SBIXGlyph *glyph = &(this+imageOffsetsZ[glyph_id]);
if (glyph->graphicType == HB_TAG ('d','u','p','e'))
{
if (glyph_length >= 2)
{
glyph_id = *((HBUINT16 *) &glyph->data);
if (retry_count--)
goto retry;
}
return hb_blob_get_empty ();
}
if (unlikely (file_type != glyph->graphicType))
return hb_blob_get_empty ();
if (strike_ppem) *strike_ppem = ppem;
if (x_offset) *x_offset = glyph->xOffset;
if (y_offset) *y_offset = glyph->yOffset;
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<SBIXStrike> ();
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<Offset32To<SBIXGlyph>>
imageOffsetsZ; /* Offset from the beginning of the strike data header
* to bitmap data for an individual glyph ID. */
public:
DEFINE_SIZE_ARRAY (4, imageOffsetsZ);
};
struct sbix
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_sbix;
bool has_data () const { return version; }
const SBIXStrike &get_strike (unsigned int i) const { return this+strikes[i]; }
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<sbix> (face);
num_glyphs = face->get_num_glyphs ();
}
~accelerator_t () { table.destroy (); }
bool has_data () const { return table->has_data (); }
bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
bool scale = true) const
{
/* We only support PNG right now, and following function checks type. */
return get_png_extents (font, glyph, extents, scale);
}
hb_blob_t *reference_png (hb_font_t *font,
hb_codepoint_t glyph_id,
int *x_offset,
int *y_offset,
unsigned int *available_ppem) const
{
return choose_strike (font).get_glyph_blob (glyph_id, table.get_blob (),
HB_TAG ('p','n','g',' '),
x_offset, y_offset,
num_glyphs, available_ppem);
}
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ())
return false;
int x_offset = 0, y_offset = 0;
unsigned int strike_ppem = 0;
hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
hb_glyph_extents_t extents;
hb_glyph_extents_t pixel_extents;
if (blob == hb_blob_get_empty ())
return false;
if (!hb_font_get_glyph_extents (font, glyph, &extents))
return false;
if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
return false;
bool ret = funcs->image (data,
blob,
pixel_extents.width, -pixel_extents.height,
HB_PAINT_IMAGE_FORMAT_PNG,
font->slant_xy,
&extents);
hb_blob_destroy (blob);
return ret;
}
private:
const SBIXStrike &choose_strike (hb_font_t *font) const
{
unsigned count = table->strikes.len;
if (unlikely (!count))
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. */
/* TODO Add DPI sensitivity as well? */
unsigned int best_i = 0;
unsigned int best_ppem = table->get_strike (0).ppem;
for (unsigned int i = 1; i < count; i++)
{
unsigned int ppem = (table->get_strike (i)).ppem;
if ((requested_ppem <= ppem && ppem < best_ppem) ||
(requested_ppem > best_ppem && ppem > best_ppem))
{
best_i = i;
best_ppem = ppem;
}
}
return table->get_strike (best_i);
}
struct PNGHeader
{
HBUINT8 signature[8];
struct
{
struct
{
HBUINT32 length;
Tag type;
} header;
HBUINT32 width;
HBUINT32 height;
HBUINT8 bitDepth;
HBUINT8 colorType;
HBUINT8 compressionMethod;
HBUINT8 filterMethod;
HBUINT8 interlaceMethod;
} IHDR;
public:
DEFINE_SIZE_STATIC (29);
};
bool get_png_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
bool scale = true) const
{
/* Following code is safe to call even without data.
* But faster to short-circuit. */
if (!has_data ())
return false;
int x_offset = 0, y_offset = 0;
unsigned int strike_ppem = 0;
hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
const PNGHeader &png = *blob->as<PNGHeader>();
if (png.IHDR.height >= 65536 || png.IHDR.width >= 65536)
{
hb_blob_destroy (blob);
return false;
}
extents->x_bearing = x_offset;
extents->y_bearing = png.IHDR.height + y_offset;
extents->width = png.IHDR.width;
extents->height = -1 * png.IHDR.height;
/* Convert to font units. */
if (strike_ppem && scale)
{
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);
}
if (scale)
font->scale_glyph_extents (extents);
hb_blob_destroy (blob);
return strike_ppem;
}
private:
hb_blob_ptr_t<sbix> table;
unsigned int num_glyphs;
};
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version >= 1 &&
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<Array32OfOffset32To<SBIXStrike>> ();
if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_vector_t<Offset32To<SBIXStrike>*> new_strikes;
hb_vector_t<hb_serialize_context_t::objidx_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<sbix> ();
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). */
Array32OfOffset32To<SBIXStrike>
strikes; /* Offsets from the beginning of the 'sbix'
* table to data for each individual bitmap strike. */
public:
DEFINE_SIZE_ARRAY (8, strikes);
};
struct sbix_accelerator_t : sbix::accelerator_t {
sbix_accelerator_t (hb_face_t *face) : sbix::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_COLOR_SBIX_SBIX_HH */

151
src/OT/Color/svg/svg.hh Normal file
View file

@ -0,0 +1,151 @@
/*
* 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 OT_COLOR_SVG_SVG_HH
#define OT_COLOR_SVG_SVG_HH
#include "../../../hb-open-type.hh"
#include "../../../hb-blob.hh"
#include "../../../hb-paint.hh"
/*
* SVG -- SVG (Scalable Vector Graphics)
* https://docs.microsoft.com/en-us/typography/opentype/spec/svg
*/
#define HB_OT_TAG_SVG HB_TAG('S','V','G',' ')
namespace OT {
struct SVGDocumentIndexEntry
{
int cmp (hb_codepoint_t g) const
{ return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; }
hb_blob_t *reference_blob (hb_blob_t *svg_blob, unsigned int index_offset) const
{
return hb_blob_create_sub_blob (svg_blob,
index_offset + (unsigned int) svgDoc,
svgDocLength);
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
svgDoc.sanitize (c, base, svgDocLength));
}
protected:
HBUINT16 startGlyphID; /* The first glyph ID in the range described by
* this index entry. */
HBUINT16 endGlyphID; /* The last glyph ID in the range described by
* this index entry. Must be >= startGlyphID. */
NNOffset32To<UnsizedArrayOf<HBUINT8>>
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.
* Must be non-zero. */
public:
DEFINE_SIZE_STATIC (12);
};
struct SVG
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG;
bool has_data () const { return svgDocEntries; }
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{ table = hb_sanitize_context_t ().reference_table<SVG> (face); }
~accelerator_t () { table.destroy (); }
hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
{
return table->get_glyph_entry (glyph_id).reference_blob (table.get_blob (),
table->svgDocEntries);
}
bool has_data () const { return table->has_data (); }
bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ())
return false;
hb_blob_t *blob = reference_blob_for_glyph (glyph);
if (blob == hb_blob_get_empty ())
return false;
funcs->image (data,
blob,
0, 0,
HB_PAINT_IMAGE_FORMAT_SVG,
font->slant_xy,
nullptr);
hb_blob_destroy (blob);
return true;
}
private:
hb_blob_ptr_t<SVG> table;
public:
DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t<SVG>));
};
const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
{ return (this+svgDocEntries).bsearch (glyph_id); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(this+svgDocEntries).sanitize_shallow (c)));
}
protected:
HBUINT16 version; /* Table version (starting at 0). */
Offset32To<SortedArray16Of<SVGDocumentIndexEntry>>
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. */
HBUINT32 reserved; /* Set to 0. */
public:
DEFINE_SIZE_STATIC (10);
};
struct SVG_accelerator_t : SVG::accelerator_t {
SVG_accelerator_t (hb_face_t *face) : SVG::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_COLOR_SVG_SVG_HH */

View file

@ -0,0 +1,336 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_COVERAGE_HH
#define OT_LAYOUT_COMMON_COVERAGE_HH
#include "../types.hh"
#include "CoverageFormat1.hh"
#include "CoverageFormat2.hh"
namespace OT {
namespace Layout {
namespace Common {
template<typename Iterator>
static inline void Coverage_serialize (hb_serialize_context_t *c,
Iterator it);
struct Coverage
{
protected:
union {
HBUINT16 format; /* Format identifier */
CoverageFormat1_3<SmallTypes> format1;
CoverageFormat2_4<SmallTypes> format2;
#ifndef HB_NO_BEYOND_64K
CoverageFormat1_3<MediumTypes>format3;
CoverageFormat2_4<MediumTypes>format4;
#endif
} u;
public:
DEFINE_SIZE_UNION (2, format);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format)
{
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
#endif
default:return_trace (true);
}
}
/* Has interface. */
unsigned operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1: return u.format1.get_coverage (glyph_id);
case 2: return u.format2.get_coverage (glyph_id);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_coverage (glyph_id);
case 4: return u.format4.get_coverage (glyph_id);
#endif
default:return NOT_COVERED;
}
}
unsigned get_population () const
{
switch (u.format) {
case 1: return u.format1.get_population ();
case 2: return u.format2.get_population ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_population ();
case 4: return u.format4.get_population ();
#endif
default:return NOT_COVERED;
}
}
template <typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned count = hb_len (glyphs);
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
for (auto g: glyphs)
{
if (last + 1 != g)
num_ranges++;
last = g;
}
u.format = count <= num_ranges * 3 ? 1 : 2;
#ifndef HB_NO_BEYOND_64K
if (count && last > 0xFFFFu)
u.format += 2;
#endif
switch (u.format)
{
case 1: return_trace (u.format1.serialize (c, glyphs));
case 2: return_trace (u.format2.serialize (c, glyphs));
#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.serialize (c, glyphs));
case 4: return_trace (u.format4.serialize (c, glyphs));
#endif
default:return_trace (false);
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto it =
+ iter ()
| hb_take (c->plan->source->get_num_glyphs ())
| hb_map_retains_sorting (c->plan->glyph_map_gsub)
| hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
// Cache the iterator result as it will be iterated multiple times
// by the serialize code below.
hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
Coverage_serialize (c->serializer, glyphs.iter ());
return_trace (bool (glyphs));
}
bool intersects (const hb_set_t *glyphs) const
{
switch (u.format)
{
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersects (glyphs);
case 4: return u.format4.intersects (glyphs);
#endif
default:return false;
}
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
switch (u.format)
{
case 1: return u.format1.intersects_coverage (glyphs, index);
case 2: return u.format2.intersects_coverage (glyphs, index);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersects_coverage (glyphs, index);
case 4: return u.format4.intersects_coverage (glyphs, index);
#endif
default:return false;
}
}
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
switch (u.format)
{
case 1: return u.format1.collect_coverage (glyphs);
case 2: return u.format2.collect_coverage (glyphs);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.collect_coverage (glyphs);
case 4: return u.format4.collect_coverage (glyphs);
#endif
default:return false;
}
}
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
switch (u.format)
{
case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
#endif
default:return ;
}
}
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
iter_t (const Coverage &c_ = Null (Coverage))
{
hb_memset (this, 0, sizeof (*this));
format = c_.u.format;
switch (format)
{
case 1: u.format1.init (c_.u.format1); return;
case 2: u.format2.init (c_.u.format2); return;
#ifndef HB_NO_BEYOND_64K
case 3: u.format3.init (c_.u.format3); return;
case 4: u.format4.init (c_.u.format4); return;
#endif
default: return;
}
}
bool __more__ () const
{
switch (format)
{
case 1: return u.format1.__more__ ();
case 2: return u.format2.__more__ ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.__more__ ();
case 4: return u.format4.__more__ ();
#endif
default:return false;
}
}
void __next__ ()
{
switch (format)
{
case 1: u.format1.__next__ (); break;
case 2: u.format2.__next__ (); break;
#ifndef HB_NO_BEYOND_64K
case 3: u.format3.__next__ (); break;
case 4: u.format4.__next__ (); break;
#endif
default: break;
}
}
typedef hb_codepoint_t __item_t__;
__item_t__ __item__ () const { return get_glyph (); }
hb_codepoint_t get_glyph () const
{
switch (format)
{
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_glyph ();
case 4: return u.format4.get_glyph ();
#endif
default:return 0;
}
}
bool operator != (const iter_t& o) const
{
if (unlikely (format != o.format)) return true;
switch (format)
{
case 1: return u.format1 != o.u.format1;
case 2: return u.format2 != o.u.format2;
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3 != o.u.format3;
case 4: return u.format4 != o.u.format4;
#endif
default:return false;
}
}
iter_t __end__ () const
{
iter_t it = {};
it.format = format;
switch (format)
{
case 1: it.u.format1 = u.format1.__end__ (); break;
case 2: it.u.format2 = u.format2.__end__ (); break;
#ifndef HB_NO_BEYOND_64K
case 3: it.u.format3 = u.format3.__end__ (); break;
case 4: it.u.format4 = u.format4.__end__ (); break;
#endif
default: break;
}
return it;
}
private:
unsigned int format;
union {
#ifndef HB_NO_BEYOND_64K
CoverageFormat2_4<MediumTypes>::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */
CoverageFormat1_3<MediumTypes>::iter_t format3;
#endif
CoverageFormat2_4<SmallTypes>::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
CoverageFormat1_3<SmallTypes>::iter_t format1;
} u;
};
iter_t iter () const { return iter_t (*this); }
};
template<typename Iterator>
static inline void
Coverage_serialize (hb_serialize_context_t *c,
Iterator it)
{ c->start_embed<Coverage> ()->serialize (c, it); }
}
}
}
#endif // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH

View file

@ -0,0 +1,133 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
#define OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
namespace OT {
namespace Layout {
namespace Common {
#define NOT_COVERED ((unsigned int) -1)
template <typename Types>
struct CoverageFormat1_3
{
friend struct Coverage;
protected:
HBUINT16 coverageFormat; /* Format identifier--format = 1 */
SortedArray16Of<typename Types::HBGlyphID>
glyphArray; /* Array of GlyphIDs--in numerical order */
public:
DEFINE_SIZE_ARRAY (4, glyphArray);
private:
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (glyphArray.sanitize (c));
}
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
unsigned int i;
glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
return i;
}
unsigned get_population () const
{
return glyphArray.len;
}
template <typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
return_trace (glyphArray.serialize (c, glyphs));
}
bool intersects (const hb_set_t *glyphs) const
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
{
for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
}
for (const auto& g : glyphArray.as_array ())
if (glyphs->has (g))
return true;
return false;
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{ return glyphs->has (glyphArray[index]); }
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
unsigned count = glyphArray.len;
for (unsigned i = 0; i < count; i++)
if (glyphs.has (glyphArray[i]))
intersect_glyphs << glyphArray[i];
}
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{ return glyphs->add_sorted_array (glyphArray.as_array ()); }
public:
/* Older compilers need this to be public. */
struct iter_t
{
void init (const struct CoverageFormat1_3 &c_) { c = &c_; i = 0; }
bool __more__ () const { return i < c->glyphArray.len; }
void __next__ () { i++; }
hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
bool operator != (const iter_t& o) const
{ return i != o.i; }
iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; }
private:
const struct CoverageFormat1_3 *c;
unsigned int i;
};
private:
};
}
}
}
#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH

View file

@ -0,0 +1,232 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
#define OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
#include "RangeRecord.hh"
namespace OT {
namespace Layout {
namespace Common {
template <typename Types>
struct CoverageFormat2_4
{
friend struct Coverage;
protected:
HBUINT16 coverageFormat; /* Format identifier--format = 2 */
SortedArray16Of<RangeRecord<Types>>
rangeRecord; /* Array of glyph ranges--ordered by
* Start GlyphID. rangeCount entries
* long */
public:
DEFINE_SIZE_ARRAY (4, rangeRecord);
private:
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (rangeRecord.sanitize (c));
}
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
const RangeRecord<Types> &range = rangeRecord.bsearch (glyph_id);
return likely (range.first <= range.last)
? (unsigned int) range.value + (glyph_id - range.first)
: NOT_COVERED;
}
unsigned get_population () const
{
typename Types::large_int ret = 0;
for (const auto &r : rangeRecord)
ret += r.get_population ();
return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
}
template <typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
for (auto g: glyphs)
{
if (last + 1 != g)
num_ranges++;
last = g;
}
if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
if (!num_ranges) return_trace (true);
unsigned count = 0;
unsigned range = (unsigned) -1;
last = (hb_codepoint_t) -2;
for (auto g: glyphs)
{
if (last + 1 != g)
{
range++;
rangeRecord.arrayZ[range].first = g;
rangeRecord.arrayZ[range].value = count;
}
rangeRecord.arrayZ[range].last = g;
last = g;
count++;
}
return_trace (true);
}
bool intersects (const hb_set_t *glyphs) const
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
}
return hb_any (+ hb_iter (rangeRecord)
| hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs); }));
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
auto *range = rangeRecord.as_array ().bsearch (index);
if (range)
return range->intersects (*glyphs);
return false;
}
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
/* Break out of loop for overlapping, broken, tables,
* to avoid fuzzer timouts. */
hb_codepoint_t last = 0;
for (const auto& range : rangeRecord)
{
if (unlikely (range.first < last))
break;
last = range.last;
for (hb_codepoint_t g = range.first - 1;
glyphs.next (&g) && g <= last;)
intersect_glyphs << g;
}
}
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
for (const auto& range: rangeRecord)
if (unlikely (!range.collect_coverage (glyphs)))
return false;
return true;
}
public:
/* Older compilers need this to be public. */
struct iter_t
{
void init (const CoverageFormat2_4 &c_)
{
c = &c_;
coverage = 0;
i = 0;
j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
{
/* Broken table. Skip. */
i = c->rangeRecord.len;
j = 0;
}
}
bool __more__ () const { return i < c->rangeRecord.len; }
void __next__ ()
{
if (j >= c->rangeRecord[i].last)
{
i++;
if (__more__ ())
{
unsigned int old = coverage;
j = c->rangeRecord[i].first;
coverage = c->rangeRecord[i].value;
if (unlikely (coverage != old + 1))
{
/* Broken table. Skip. Important to avoid DoS.
* Also, our callers depend on coverage being
* consecutive and monotonically increasing,
* ie. iota(). */
i = c->rangeRecord.len;
j = 0;
return;
}
}
else
j = 0;
return;
}
coverage++;
j++;
}
hb_codepoint_t get_glyph () const { return j; }
bool operator != (const iter_t& o) const
{ return i != o.i || j != o.j; }
iter_t __end__ () const
{
iter_t it;
it.init (*c);
it.i = c->rangeRecord.len;
it.j = 0;
return it;
}
private:
const struct CoverageFormat2_4 *c;
unsigned int i, coverage;
hb_codepoint_t j;
};
private:
};
}
}
}
#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH

View file

@ -0,0 +1,85 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
#define OT_LAYOUT_COMMON_RANGERECORD_HH
namespace OT {
namespace Layout {
namespace Common {
template <typename Types>
struct RangeRecord
{
typename Types::HBGlyphID first; /* First GlyphID in the range */
typename Types::HBGlyphID last; /* Last GlyphID in the range */
HBUINT16 value; /* Value */
DEFINE_SIZE_STATIC (2 + 2 * Types::size);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
unsigned get_population () const
{
if (unlikely (last < first)) return 0;
return (last - first + 1);
}
bool intersects (const hb_set_t &glyphs) const
{ return glyphs.intersects (first, last); }
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{ return glyphs->add_range (first, last); }
};
}
}
}
// TODO(garretrieger): This was previously implemented using
// DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (OT, RangeRecord, 9);
// but that only works when there is only a single namespace level.
// The macro should probably be fixed so it can work in this situation.
extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9];
template <typename Spec>
struct Null<OT::Layout::Common::RangeRecord<Spec>> {
static OT::Layout::Common::RangeRecord<Spec> const & get_null () {
return *reinterpret_cast<const OT::Layout::Common::RangeRecord<Spec> *> (_hb_Null_OT_RangeRecord);
}
};
#endif // #ifndef OT_LAYOUT_COMMON_RANGERECORD_HH

942
src/OT/Layout/GDEF/GDEF.hh Normal file
View file

@ -0,0 +1,942 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef OT_LAYOUT_GDEF_GDEF_HH
#define OT_LAYOUT_GDEF_GDEF_HH
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-font.hh"
#include "../../../hb-cache.hh"
namespace OT {
/*
* Attachment List Table
*/
/* Array of contour point indices--in increasing numerical order */
struct AttachPoint : Array16Of<HBUINT16>
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (out->serialize (c->serializer, + iter ()));
}
};
struct AttachList
{
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (point_count)
*point_count = 0;
return 0;
}
const AttachPoint &points = this+attachPoint[index];
if (point_count)
{
+ points.as_array ().sub_array (start_offset, point_count)
| hb_sink (hb_array (point_array, *point_count))
;
}
return points.len;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, attachPoint)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
}
protected:
Offset16To<Coverage>
coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
Array16OfOffset16To<AttachPoint>
attachPoint; /* Array of AttachPoint tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, attachPoint);
};
/*
* Ligature Caret Table
*/
struct CaretValueFormat1
{
friend struct CaretValue;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (true);
}
private:
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 1 */
FWORD coordinate; /* X or Y value, in design units */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat2
{
friend struct CaretValue;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (true);
}
private:
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
{
hb_position_t x, y;
font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 2 */
HBUINT16 caretValuePoint; /* Contour point index on glyph */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat3
{
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
if (!c->serializer->embed (caretValueFormat)) return_trace (false);
if (!c->serializer->embed (coordinate)) return_trace (false);
unsigned varidx = (this+deviceTable).get_variation_index ();
if (c->plan->layout_variation_idx_delta_map.has (varidx))
{
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
}
if (c->plan->all_axes_pinned)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
return_trace (false);
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ (this+deviceTable).collect_variation_indices (c); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */
Offset16To<Device>
deviceTable; /* Offset to Device table for X or Y
* value--from beginning of CaretValue
* table */
public:
DEFINE_SIZE_STATIC (6);
};
struct CaretValue
{
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
case 2: return u.format2.get_caret_value (font, direction, glyph_id);
case 3: return u.format3.get_caret_value (font, direction, var_store);
default:return 0;
}
}
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.format) {
case 1:
case 2:
return;
case 3:
u.format3.collect_variation_indices (c);
return;
default: return;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
CaretValueFormat1 format1;
CaretValueFormat2 format2;
CaretValueFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct LigGlyph
{
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
if (caret_count)
{
+ carets.as_array ().sub_array (start_offset, caret_count)
| hb_map (hb_add (this))
| hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
| hb_sink (hb_array (caret_array, *caret_count))
;
}
return carets.len;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_iter (carets)
| hb_apply (subset_offset_array (c, out->carets, this))
;
return_trace (bool (out->carets));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (const Offset16To<CaretValue>& offset : carets.iter ())
(this+offset).collect_variation_indices (c);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (carets.sanitize (c, this));
}
protected:
Array16OfOffset16To<CaretValue>
carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
* --in increasing coordinate order */
public:
DEFINE_SIZE_ARRAY (2, carets);
};
struct LigCaretList
{
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (caret_count)
*caret_count = 0;
return 0;
}
const LigGlyph &lig_glyph = this+ligGlyph[index];
return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, ligGlyph)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+coverage, ligGlyph)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
}
protected:
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
Array16OfOffset16To<LigGlyph>
ligGlyph; /* Array of LigGlyph tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, ligGlyph);
};
struct MarkGlyphSetsFormat1
{
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
bool ret = true;
for (const Offset32To<Coverage>& offset : coverage.iter ())
{
auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o))
{
ret = false;
break;
}
//not using o->serialize_subset (c, offset, this, out) here because
//OTS doesn't allow null offset.
//See issue: https://github.com/khaledhosny/ots/issues/172
c->serializer->push ();
c->dispatch (this+offset);
c->serializer->add_link (*o, c->serializer->pop_pack ());
}
return_trace (ret && out->coverage.len);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Array16Of<Offset32To<Coverage>>
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
DEFINE_SIZE_ARRAY (4, coverage);
};
struct MarkGlyphSets
{
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1: return u.format1.covers (set_index, glyph_id);
default:return false;
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
switch (u.format) {
case 1: return_trace (u.format1.subset (c));
default:return_trace (false);
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
MarkGlyphSetsFormat1 format1;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/*
* GDEF -- Glyph Definition
* https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
*/
template <typename Types>
struct GDEFVersion1_2
{
friend struct GDEF;
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
* 0x00010003u */
typename Types::template OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
* GDEF header (may be Null) */
typename Types::template OffsetTo<AttachList>
attachList; /* Offset to list of glyphs with
* attachment points--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<LigCaretList>
ligCaretList; /* Offset to list of positioning points
* for ligature carets--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<ClassDef>
markAttachClassDef; /* Offset to class definition table for
* mark attachment type--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<MarkGlyphSets>
markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
Offset32To<VariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010003. */
public:
DEFINE_SIZE_MIN (4 + 4 * Types::size);
unsigned int get_size () const
{
return min_size +
(version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
(version.to_int () >= 0x00010003u ? varStore.static_size : 0);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
glyphClassDef.sanitize (c, this) &&
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_markglyphsetsdef = false;
if (version.to_int () >= 0x00010002u)
{
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
}
bool subset_varstore = false;
if (version.to_int () >= 0x00010003u)
{
if (c->plan->all_axes_pinned)
out->varStore = 0;
else
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
}
if (subset_varstore)
{
out->version.minor = 3;
} else if (subset_markglyphsetsdef) {
out->version.minor = 2;
} else {
out->version.minor = 0;
}
return_trace (subset_glyphclassdef || subset_attachlist ||
subset_ligcaretlist || subset_markattachclassdef ||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
(out->version.to_int () >= 0x00010003u && subset_varstore));
}
};
struct GDEF
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses {
UnclassifiedGlyph = 0,
BaseGlyph = 1,
LigatureGlyph = 2,
MarkGlyph = 3,
ComponentGlyph = 4
};
unsigned int get_size () const
{
switch (u.version.major) {
case 1: return u.version1.get_size ();
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.get_size ();
#endif
default: return u.version.static_size;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false);
switch (u.version.major) {
case 1: return_trace (u.version1.sanitize (c));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (u.version2.sanitize (c));
#endif
default: return_trace (true);
}
}
bool subset (hb_subset_context_t *c) const
{
switch (u.version.major) {
case 1: return u.version1.subset (c);
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.subset (c);
#endif
default: return false;
}
}
bool has_glyph_classes () const
{
switch (u.version.major) {
case 1: return u.version1.glyphClassDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.glyphClassDef != 0;
#endif
default: return false;
}
}
const ClassDef &get_glyph_class_def () const
{
switch (u.version.major) {
case 1: return this+u.version1.glyphClassDef;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.glyphClassDef;
#endif
default: return Null(ClassDef);
}
}
bool has_attach_list () const
{
switch (u.version.major) {
case 1: return u.version1.attachList != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.attachList != 0;
#endif
default: return false;
}
}
const AttachList &get_attach_list () const
{
switch (u.version.major) {
case 1: return this+u.version1.attachList;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.attachList;
#endif
default: return Null(AttachList);
}
}
bool has_lig_carets () const
{
switch (u.version.major) {
case 1: return u.version1.ligCaretList != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.ligCaretList != 0;
#endif
default: return false;
}
}
const LigCaretList &get_lig_caret_list () const
{
switch (u.version.major) {
case 1: return this+u.version1.ligCaretList;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.ligCaretList;
#endif
default: return Null(LigCaretList);
}
}
bool has_mark_attachment_types () const
{
switch (u.version.major) {
case 1: return u.version1.markAttachClassDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.markAttachClassDef != 0;
#endif
default: return false;
}
}
const ClassDef &get_mark_attach_class_def () const
{
switch (u.version.major) {
case 1: return this+u.version1.markAttachClassDef;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.markAttachClassDef;
#endif
default: return Null(ClassDef);
}
}
bool has_mark_glyph_sets () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.markGlyphSetsDef != 0;
#endif
default: return false;
}
}
const MarkGlyphSets &get_mark_glyph_sets () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.markGlyphSetsDef;
#endif
default: return Null(MarkGlyphSets);
}
}
bool has_var_store () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.varStore != 0;
#endif
default: return false;
}
}
const VariationStore &get_var_store () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
default: return Null(VariationStore);
}
}
bool has_data () const { return u.version.to_int (); }
unsigned int get_glyph_class (hb_codepoint_t glyph) const
{ return get_glyph_class_def ().get_class (glyph); }
void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
{ get_glyph_class_def ().collect_class (glyphs, klass); }
unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
{ return get_mark_attach_class_def ().get_class (glyph); }
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{ return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{ return get_lig_caret_list ().get_lig_carets (font,
direction, glyph_id, get_var_store(),
start_offset, caret_count, caret_array); }
bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return get_mark_glyph_sets ().covers (set_index, glyph_id); }
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit the mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
unsigned int klass = get_glyph_class (glyph);
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
switch (klass) {
default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case MarkGlyph:
klass = get_mark_attachment_type (glyph);
return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
}
}
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<GDEF> (face);
if (unlikely (table->is_blocklisted (table.get_blob (), face)))
{
hb_blob_destroy (table.get_blob ());
table = hb_blob_get_empty ();
}
}
~accelerator_t () { table.destroy (); }
unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
unsigned v;
#ifndef HB_NO_GDEF_CACHE
if (glyph_props_cache.get (glyph, &v))
return v;
#endif
v = table->get_glyph_props (glyph);
#ifndef HB_NO_GDEF_CACHE
if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
glyph_props_cache.set (glyph, v);
#endif
return v;
}
hb_blob_ptr_t<GDEF> table;
#ifndef HB_NO_GDEF_CACHE
mutable hb_cache_t<21, 3, 8> glyph_props_cache;
#endif
};
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
if (layout_variation_indices->is_empty ()) return;
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ())
{
uint16_t major = idx >> 16;
if (major >= get_var_store ().get_sub_table_count ()) break;
if (major != last_major)
{
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
if (!layout_variation_idx_delta_map->has (idx))
continue;
int delta = hb_second (layout_variation_idx_delta_map->get (idx));
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
}
protected:
union {
FixedVersion<> version; /* Version identifier */
GDEFVersion1_2<SmallTypes> version1;
#ifndef HB_NO_BEYOND_64K
GDEFVersion1_2<MediumTypes> version2;
#endif
} u;
public:
DEFINE_SIZE_MIN (4);
};
struct GDEF_accelerator_t : GDEF::accelerator_t {
GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_LAYOUT_GDEF_GDEF_HH */

View file

@ -0,0 +1,83 @@
#ifndef OT_LAYOUT_GPOS_ANCHOR_HH
#define OT_LAYOUT_GPOS_ANCHOR_HH
#include "AnchorFormat1.hh"
#include "AnchorFormat2.hh"
#include "AnchorFormat3.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct Anchor
{
protected:
union {
HBUINT16 format; /* Format identifier */
AnchorFormat1 format1;
AnchorFormat2 format2;
AnchorFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION (2, format);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
default:return_trace (true);
}
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
float *x, float *y) const
{
*x = *y = 0;
switch (u.format) {
case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
default: return;
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
switch (u.format) {
case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
case 2:
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
// AnchorFormat 2 just containins extra hinting information, so
// if hints are being dropped convert to format 1.
return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
}
return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
case 3: return_trace (u.format3.subset (c));
default:return_trace (false);
}
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.format) {
case 1: case 2:
return;
case 3:
u.format3.collect_variation_indices (c);
return;
default: return;
}
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_ANCHOR_HH

Some files were not shown because too many files have changed in this diff Show more