Compare commits
1 Commits
main
...
run-tests-
Author | SHA1 | Date |
---|---|---|
Behdad Esfahbod | f462f2dbcf |
|
@ -1,28 +0,0 @@
|
|||
#!/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."
|
|
@ -1,28 +0,0 @@
|
|||
#!/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."
|
|
@ -3,6 +3,13 @@
|
|||
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)
|
||||
|
||||
|
@ -10,24 +17,20 @@ rm -rf $DOCSDIR || exit
|
|||
mkdir $DOCSDIR
|
||||
cd $DOCSDIR
|
||||
|
||||
cp ../build/docs/html/* .
|
||||
#cp ../build/docs/CNAME .
|
||||
cp ../docs/html/* .
|
||||
#cp ../docs/CNAME .
|
||||
|
||||
git init
|
||||
git branch -m main
|
||||
git config user.name "CI"
|
||||
git config user.email "harfbuzz-admin@googlegroups.com"
|
||||
git config user.name "Travis CI"
|
||||
git config user.email "travis@harfbuzz.org"
|
||||
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/main
|
||||
git reset upstream/master
|
||||
|
||||
touch .
|
||||
git add -A .
|
||||
|
||||
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
|
||||
git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION"
|
||||
git push -q upstream HEAD:master
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
#!/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
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set -o errexit -o nounset
|
||||
|
||||
if test "x$TRAVIS_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
|
|
@ -1,20 +0,0 @@
|
|||
[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'
|
|
@ -1,20 +0,0 @@
|
|||
[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'
|
|
@ -1,216 +1,154 @@
|
|||
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
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
|
||||
macos-aat-fonts:
|
||||
macos:
|
||||
xcode: "12.5.1"
|
||||
steps:
|
||||
- checkout
|
||||
- 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:
|
||||
executor: autotools-executor
|
||||
steps:
|
||||
- checkout
|
||||
- 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 -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
|
||||
|
||||
publish-dist:
|
||||
executor: autotools-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: |
|
||||
.ci/publish_release_artifact.sh harfbuzz-$CIRCLE_TAG.tar.xz
|
||||
|
||||
fedora-valgrind:
|
||||
oracledeveloperstudio:
|
||||
docker:
|
||||
- image: fedora:36
|
||||
- image: fedora
|
||||
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))
|
||||
- run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python || 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_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_ICU=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
|
||||
- run: make -Cbuild
|
||||
- run: make -Cbuild test
|
||||
- run: make -Cbuild install
|
||||
|
||||
fedora-out-of-tree:
|
||||
docker:
|
||||
- image: fedora
|
||||
steps:
|
||||
- checkout
|
||||
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config || true
|
||||
- run: NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
|
||||
- run: mkdir build && cd build && ../configure && make && make check
|
||||
|
||||
archlinux:
|
||||
docker:
|
||||
- image: base/devel
|
||||
steps:
|
||||
- checkout
|
||||
- run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel
|
||||
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
|
||||
- run: make && make check
|
||||
|
||||
freebsd9:
|
||||
docker:
|
||||
- image: donbowman/freebsd-cross-build
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y pkg-config ragel
|
||||
- run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9
|
||||
- run: make
|
||||
|
||||
base:
|
||||
docker:
|
||||
- image: dockcross/base
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
|
||||
- run: cmake -DHB_HAVE_FREETYPE=ON -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_ICU=ON -DHB_BUILD_UTILS=ON -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
- run: ninja -Cbuild test
|
||||
- run: ninja -Cbuild install
|
||||
|
||||
distcheck:
|
||||
docker:
|
||||
- image: dockcross/base
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
|
||||
- run: ./autogen.sh && make distcheck
|
||||
- run: make distdir && cd harfbuzz-* && cmake -DDHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
|
||||
|
||||
psvita:
|
||||
docker:
|
||||
- image: dockcross/base
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install ragel
|
||||
- run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh
|
||||
- run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
|
||||
- run: make
|
||||
|
||||
android-arm:
|
||||
docker:
|
||||
- image: dockcross/android-arm
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install ragel
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
browser-asmjs:
|
||||
docker:
|
||||
- image: dockcross/browser-asmjs
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install ragel
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
linux-arm64:
|
||||
docker:
|
||||
- image: dockcross/linux-arm64
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install ragel
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
linux-mips:
|
||||
docker:
|
||||
- image: dockcross/linux-mips
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install ragel
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
windows-x64:
|
||||
docker:
|
||||
- image: dockcross/windows-x64
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install ragel
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
alpine:
|
||||
docker:
|
||||
- image: alpine
|
||||
steps:
|
||||
- checkout
|
||||
- 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
|
||||
- run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev
|
||||
- run: ./autogen.sh
|
||||
- run: make && make check
|
||||
|
||||
asan-ubsan:
|
||||
dos:
|
||||
docker:
|
||||
- image: ubuntu:20.04
|
||||
- image: quay.io/ebraminio/djgpp
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || 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=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
|
||||
|
||||
tsan:
|
||||
docker:
|
||||
- image: ubuntu:20.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || 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
|
||||
|
||||
msan:
|
||||
docker:
|
||||
- image: ubuntu:20.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || 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
|
||||
# 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-cxx2a:
|
||||
docker:
|
||||
- image: ubuntu:20.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- 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
|
||||
|
||||
crossbuild-win32:
|
||||
executor: win32-executor
|
||||
steps:
|
||||
- checkout
|
||||
- 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: 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: harfbuzz-win64.zip
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: harfbuzz-win64.zip
|
||||
|
||||
publish-win64:
|
||||
executor: win64-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: |
|
||||
mv harfbuzz-win64{,-$CIRCLE_TAG}.zip
|
||||
.ci/publish_release_artifact.sh harfbuzz-win64-$CIRCLE_TAG.zip
|
||||
|
||||
- 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
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
build:
|
||||
jobs:
|
||||
- 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
|
||||
#- oracledeveloperstudio
|
||||
#- fedora-out-of-tree
|
||||
- archlinux
|
||||
- freebsd9
|
||||
- base
|
||||
- distcheck
|
||||
- psvita
|
||||
- android-arm
|
||||
- browser-asmjs
|
||||
- linux-arm64
|
||||
- linux-mips
|
||||
- windows-x64
|
||||
- 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: /.*/
|
||||
- dos
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
# The following tries to match the current code style, is imperfect for now
|
||||
# but good for new codes be added
|
||||
|
||||
IndentWidth: 2
|
||||
TabWidth: 8
|
||||
UseTab: Always
|
||||
SpaceBeforeParens: Always
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterEnum: true
|
||||
AfterStruct: false
|
||||
SplitEmptyFunction: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeElse: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AlignTrailingComments: true
|
||||
AlignEscapedNewlines: Left
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
SpaceAfterCStyleCast: true
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
BinPackParameters: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AccessModifierOffset: 0
|
||||
AlignTrailingComments: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignOperands: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
|
||||
# We like to have this only for function parameters and structs fields, not always
|
||||
# AlignConsecutiveDeclarations: true
|
10
.codecov.yml
10
.codecov.yml
|
@ -1,10 +0,0 @@
|
|||
comment: false
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
informational: true
|
||||
patch:
|
||||
default:
|
||||
informational: true
|
|
@ -1,23 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{c,cc,h,hh,rl}]
|
||||
tab_width = 8
|
||||
indent_size = 2
|
||||
indent_style = tab # should be space
|
||||
|
||||
[*.{py,sh}]
|
||||
indent_style = tab
|
||||
|
||||
[{Makefile.am,Makefile.sources,configure.ac}]
|
||||
tab_width = 8
|
||||
|
||||
[{meson.build,meson_options.txt}]
|
||||
tab_width = 8
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -1,6 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
|
@ -1,25 +0,0 @@
|
|||
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
|
|
@ -1,28 +0,0 @@
|
|||
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
|
|
@ -1,27 +0,0 @@
|
|||
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
|
|
@ -1,42 +0,0 @@
|
|||
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 }}
|
|
@ -1,71 +0,0 @@
|
|||
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
|
|
@ -1,60 +0,0 @@
|
|||
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
|
|
@ -1,61 +0,0 @@
|
|||
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
|
|
@ -1,73 +0,0 @@
|
|||
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
|
|
@ -0,0 +1,67 @@
|
|||
# Build Configuration for Travis
|
||||
dist: trusty
|
||||
|
||||
language: cpp
|
||||
|
||||
env:
|
||||
global:
|
||||
- CPPFLAGS=""
|
||||
- CFLAGS="-Werror --coverage"
|
||||
- CXXFLAGS="-Werror -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning
|
||||
- LDFLAGS="--coverage"
|
||||
- CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
|
||||
- NOCONFIGURE=1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- ./configure $CONFIGURE_OPTS --enable-gtk-doc
|
||||
- make
|
||||
- make check || (cat */test-suite.log test/*/test-suite.log && false)
|
||||
after_success:
|
||||
- bash .ci/run-coveralls.sh # for coveralls.io code coverage tracking
|
||||
- bash .ci/deploy-docs.sh
|
||||
|
||||
- os: linux
|
||||
compiler: clang
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- ./configure $CONFIGURE_OPTS
|
||||
- make
|
||||
- make check || (cat */test-suite.log test/*/test-suite.log && false)
|
||||
|
||||
- os: osx
|
||||
compiler: clang
|
||||
install:
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/345
|
||||
- export CXXFLAGS="$CXXFLAGS -Wno-deprecated-declarations"
|
||||
- brew update;
|
||||
# Workaround Travis/brew bug
|
||||
- brew uninstall libtool && brew install libtool
|
||||
- brew install ragel freetype glib gobject-introspection cairo icu4c graphite2
|
||||
- brew link --force icu4c # icu4c is keg-only
|
||||
script:
|
||||
- ./autogen.sh
|
||||
- ./configure $CONFIGURE_OPTS --with-coretext
|
||||
- make
|
||||
- make check || (cat */test-suite.log test/*/test-suite.log && false)
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.org#harfbuzz"
|
||||
email: harfbuzz@lists.freedesktop.org
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- pkg-config # for autogen.sh
|
||||
- ragel
|
||||
- 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
|
17
AUTHORS
17
AUTHORS
|
@ -1,14 +1,9 @@
|
|||
Behdad Esfahbod
|
||||
David Corbett
|
||||
David Turner
|
||||
Ebrahim Byagowi
|
||||
Garret Rieger
|
||||
Jonathan Kew
|
||||
Khaled Hosny
|
||||
Lars Knoll
|
||||
Martin Hosken
|
||||
Owen Taylor
|
||||
Roderick Sheeter
|
||||
Roozbeh Pournader
|
||||
Simon Hausmann
|
||||
Martin Hosken
|
||||
Jonathan Kew
|
||||
Lars Knoll
|
||||
Werner Lemberg
|
||||
Roozbeh Pournader
|
||||
Owen Taylor
|
||||
David Turner
|
||||
|
|
57
BUILD.md
57
BUILD.md
|
@ -1,29 +1,50 @@
|
|||
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 meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
|
||||
sudo apt-get install gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
|
||||
|
||||
whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
|
||||
|
||||
$ sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-devel
|
||||
sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel
|
||||
|
||||
and on ArchLinux and Manjaro:
|
||||
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).
|
||||
|
||||
$ sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
|
||||
on macOS, using MacPorts:
|
||||
|
||||
then use meson to build the project like `meson build && meson test -Cbuild`.
|
||||
sudo port install freetype glib2 cairo
|
||||
|
||||
On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson`
|
||||
then use meson like above.
|
||||
or using Homebrew:
|
||||
|
||||
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.
|
||||
brew install freetype glib cairo
|
||||
|
||||
Our CI configurations is also a good source of learning how to build HarfBuzz.
|
||||
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/`.
|
||||
|
||||
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.
|
||||
If you are bootstraping 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
|
||||
|
|
536
CMakeLists.txt
536
CMakeLists.txt
|
@ -1,12 +1,11 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
cmake_minimum_required(VERSION 2.8.0)
|
||||
project(harfbuzz)
|
||||
|
||||
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.")
|
||||
enable_testing()
|
||||
|
||||
## Limit framework build to Xcode generator
|
||||
if (BUILD_FRAMEWORK)
|
||||
# for a framework build on macOS, use:
|
||||
# cmake -DBUILD_FRAMEWORK=ON -Bbuild -H. -GXcode && cmake --build build
|
||||
# for a framework on macOS, use `cmake .. -DBUILD_FRAMEWORK:BOOL=true -G Xcode`
|
||||
if (NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
||||
message(FATAL_ERROR
|
||||
"You should use Xcode generator with BUILD_FRAMEWORK enabled")
|
||||
|
@ -35,19 +34,15 @@ endif ()
|
|||
## HarfBuzz build configurations
|
||||
option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
|
||||
option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
|
||||
option(HB_BUILTIN_UCDN "Use HarfBuzz provided UCDN" ON)
|
||||
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)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend on Windows" OFF)
|
||||
option(HB_HAVE_GDI "Enable GDI integration helpers on Windows" OFF)
|
||||
option(HB_HAVE_DIRECTWRITE "Enable DirectWrite shaper backend on Windows" OFF)
|
||||
endif ()
|
||||
option(HB_BUILD_UTILS "Build harfbuzz utils, needs cairo, freetype, and glib properly be installed" OFF)
|
||||
|
@ -56,8 +51,6 @@ if (HB_BUILD_UTILS)
|
|||
set (HB_HAVE_FREETYPE ON)
|
||||
endif ()
|
||||
|
||||
option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON)
|
||||
|
||||
option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
|
||||
if (HB_HAVE_GOBJECT)
|
||||
set (HB_HAVE_GLIB ON)
|
||||
|
@ -69,79 +62,88 @@ 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_BUILTIN_UCDN 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_DIRECTWRITE ON)
|
||||
elseif (APPLE)
|
||||
set (HB_HAVE_CORETEXT ON)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include_directories(AFTER
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_BINARY_DIR}/src
|
||||
)
|
||||
|
||||
# We need PYTHON_EXECUTABLE to be set for running the tests...
|
||||
include (FindPythonInterp)
|
||||
add_definitions(-DHAVE_OT)
|
||||
add_definitions(-DHAVE_FALLBACK)
|
||||
|
||||
|
||||
## 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)
|
||||
check_function_exists(${func_name} HAVE_${definition_to_add})
|
||||
if (${HAVE_${definition_to_add}})
|
||||
add_definitions(-DHAVE_${definition_to_add})
|
||||
set (RESULT OFF)
|
||||
check_function_exists(${func_name} RESULT)
|
||||
if (${RESULT})
|
||||
string(TOUPPER ${func_name} definiton_to_add)
|
||||
add_definitions(-DHAVE_${definiton_to_add})
|
||||
endif ()
|
||||
endforeach ()
|
||||
endmacro ()
|
||||
if (UNIX)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
|
||||
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
|
||||
|
||||
check_include_file(unistd.h HAVE_UNIST_H)
|
||||
if (${HAVE_UNIST_H})
|
||||
add_definitions(-DHAVE_UNIST_H)
|
||||
endif ()
|
||||
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)
|
||||
endif ()
|
||||
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(stdbool.h HAVE_STDBOOL_H)
|
||||
if (${HAVE_STDBOOL_H})
|
||||
add_definitions(-DHAVE_STDBOOL_H)
|
||||
#check_include_file(sys/mman.h HAVE_SYS_MMAN_H) enable this sometime
|
||||
#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 ()
|
||||
|
||||
# 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)
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS)
|
||||
add_definitions("-DHB_EXTERN=__declspec(dllexport) extern")
|
||||
endif ()
|
||||
|
||||
|
||||
## Detect if we are running inside a distribution or regular repository folder
|
||||
# if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
|
||||
# # perhaps we are on dist directory
|
||||
# set (IN_HB_DIST TRUE)
|
||||
# #set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
|
||||
# endif ()
|
||||
set (IN_HB_DIST FALSE)
|
||||
if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
|
||||
# perhaps we are on dist directory
|
||||
set (IN_HB_DIST TRUE)
|
||||
set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
|
||||
endif ()
|
||||
|
||||
|
||||
## Extract variables from Makefile files
|
||||
function (extract_make_variable variable makefile_source)
|
||||
string(REGEX MATCH "${variable} = ([^$]+)\\$" temp "${makefile_source}")
|
||||
string(REGEX MATCHALL "[^ \n\t\\]+" listVar "${CMAKE_MATCH_1}")
|
||||
string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${makefile_source})
|
||||
string(REGEX MATCHALL "[^ \n\t\\]+" listVar ${CMAKE_MATCH_1})
|
||||
set (${variable} ${listVar} PARENT_SCOPE)
|
||||
endfunction ()
|
||||
|
||||
# https://stackoverflow.com/a/27630120
|
||||
# http://stackoverflow.com/a/27630120
|
||||
function (add_prefix_to_list var prefix)
|
||||
set (listVar "")
|
||||
foreach (f ${${var}})
|
||||
|
@ -152,32 +154,39 @@ endfunction ()
|
|||
|
||||
file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES)
|
||||
file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES)
|
||||
file(READ ${PROJECT_SOURCE_DIR}/src/hb-ucdn/Makefile.sources UCDNSOURCES)
|
||||
|
||||
extract_make_variable(HB_BASE_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_BASE_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
extract_make_variable(HB_BASE_headers ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_BASE_headers "${PROJECT_SOURCE_DIR}/src/")
|
||||
|
||||
extract_make_variable(HB_SUBSET_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
|
||||
extract_make_variable(HB_SUBSET_headers ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_SUBSET_headers "${PROJECT_SOURCE_DIR}/src/")
|
||||
extract_make_variable(HB_FALLBACK_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_FALLBACK_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
extract_make_variable(HB_OT_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_OT_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
extract_make_variable(HB_OT_headers ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_OT_headers "${PROJECT_SOURCE_DIR}/src/")
|
||||
|
||||
extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES})
|
||||
#if (IN_HB_DIST)
|
||||
extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES})
|
||||
if (IN_HB_DIST)
|
||||
add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
#else ()
|
||||
# add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/")
|
||||
#endif ()
|
||||
add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
else ()
|
||||
add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/")
|
||||
add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/")
|
||||
endif ()
|
||||
|
||||
extract_make_variable(HB_VIEW_sources ${UTILSOURCES})
|
||||
add_prefix_to_list(HB_VIEW_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
extract_make_variable(HB_SHAPE_sources ${UTILSOURCES})
|
||||
add_prefix_to_list(HB_SHAPE_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
extract_make_variable(HB_SUBSET_CLI_sources ${UTILSOURCES})
|
||||
add_prefix_to_list(HB_SUBSET_CLI_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
|
||||
add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
|
||||
extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES})
|
||||
add_prefix_to_list(LIBHB_UCDN_sources "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
|
||||
|
||||
|
||||
file(READ configure.ac CONFIGUREAC)
|
||||
string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
|
||||
|
@ -186,15 +195,67 @@ set (HB_VERSION_MAJOR ${CMAKE_MATCH_2})
|
|||
set (HB_VERSION_MINOR ${CMAKE_MATCH_3})
|
||||
set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
|
||||
|
||||
|
||||
## Define ragel tasks
|
||||
if (NOT IN_HB_DIST)
|
||||
find_program(RAGEL "ragel" CMAKE_FIND_ROOT_PATH_BOTH)
|
||||
|
||||
if (RAGEL)
|
||||
message(STATUS "ragel found at: ${RAGEL}")
|
||||
else ()
|
||||
message(FATAL_ERROR "ragel not found, get it here -- http://www.complang.org/ragel/ or, use harfbuzz releases https://github.com/harfbuzz/harfbuzz/releases")
|
||||
endif ()
|
||||
|
||||
foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_RAGEL_GENERATED_sources})
|
||||
string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
|
||||
set (target_name ${CMAKE_MATCH_1})
|
||||
add_custom_command(OUTPUT ${ragel_output}
|
||||
COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
|
||||
)
|
||||
add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
|
||||
endforeach ()
|
||||
|
||||
mark_as_advanced(RAGEL)
|
||||
endif ()
|
||||
|
||||
|
||||
## Generate hb-version.h
|
||||
if (NOT IN_HB_DIST)
|
||||
set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
|
||||
set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
|
||||
set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
|
||||
configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY)
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${HB_VERSION_H}.tmp"
|
||||
"${HB_VERSION_H}"
|
||||
)
|
||||
file(REMOVE "${HB_VERSION_H}.tmp")
|
||||
endif ()
|
||||
|
||||
|
||||
## Define sources and headers of the project
|
||||
set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source
|
||||
set (subset_project_sources ${HB_SUBSET_sources})
|
||||
set (project_sources
|
||||
${HB_BASE_sources}
|
||||
${HB_BASE_RAGEL_GENERATED_sources}
|
||||
|
||||
${HB_FALLBACK_sources}
|
||||
${HB_OT_sources}
|
||||
${HB_OT_RAGEL_GENERATED_sources}
|
||||
)
|
||||
|
||||
set (project_extra_sources)
|
||||
set (project_headers ${HB_BASE_headers})
|
||||
set (subset_project_headers ${HB_SUBSET_headers})
|
||||
|
||||
set (project_headers
|
||||
${HB_VERSION_H}
|
||||
|
||||
${HB_BASE_headers}
|
||||
${HB_OT_headers}
|
||||
)
|
||||
|
||||
|
||||
## Find and include needed header folders and libraries
|
||||
if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
|
||||
if (HB_HAVE_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")
|
||||
|
@ -202,21 +263,16 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
|
|||
|
||||
list(APPEND THIRD_PARTY_LIBS ${FREETYPE_LIBRARIES})
|
||||
include_directories(AFTER ${FREETYPE_INCLUDE_DIRS})
|
||||
add_definitions(-DHAVE_FREETYPE=1)
|
||||
add_definitions(-DHAVE_FREETYPE=1 -DHAVE_FT_FACE_GETCHARVARIANTINDEX=1)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h)
|
||||
|
||||
# So check_funcs can find its headers
|
||||
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${FREETYPE_INCLUDE_DIRS})
|
||||
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${FREETYPE_LIBRARIES})
|
||||
|
||||
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)
|
||||
|
||||
|
@ -225,15 +281,22 @@ if (HB_HAVE_GRAPHITE2)
|
|||
|
||||
include_directories(${GRAPHITE2_INCLUDE_DIR})
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-graphite2.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-graphite2.h)
|
||||
|
||||
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 ()
|
||||
|
||||
if (HB_BUILTIN_UCDN)
|
||||
include_directories(src/hb-ucdn)
|
||||
add_definitions(-DHAVE_UCDN)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ucdn.cc)
|
||||
list(APPEND project_extra_sources ${LIBHB_UCDN_sources})
|
||||
endif ()
|
||||
|
||||
if (HB_HAVE_GLIB)
|
||||
add_definitions(-DHAVE_GLIB)
|
||||
|
||||
|
@ -247,19 +310,18 @@ if (HB_HAVE_GLIB)
|
|||
|
||||
include_directories(${GLIBCONFIG_INCLUDE_DIR} ${GLIB_INCLUDE_DIR})
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-glib.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-glib.h)
|
||||
|
||||
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/fdd7733f2f30eab7fe096a9791f98c60f62f49c0/Source/cmake/FindICU.cmake
|
||||
# https://github.com/WebKit/webkit/blob/master/Source/cmake/FindICU.cmake
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_ICU QUIET icu-uc)
|
||||
|
||||
|
@ -268,6 +330,7 @@ if (HB_HAVE_ICU)
|
|||
|
||||
include_directories(${ICU_INCLUDE_DIR})
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-icu.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
|
||||
|
||||
list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY})
|
||||
|
@ -279,71 +342,39 @@ if (APPLE AND HB_HAVE_CORETEXT)
|
|||
# Apple Advanced Typography
|
||||
add_definitions(-DHAVE_CORETEXT)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
|
||||
|
||||
if (HB_IOS)
|
||||
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)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
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)
|
||||
find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
|
||||
if (APPLICATION_SERVICES_FRAMEWORK)
|
||||
list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
|
||||
endif (APPLICATION_SERVICES_FRAMEWORK)
|
||||
|
||||
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND HB_HAVE_UNISCRIBE)
|
||||
add_definitions(-DHAVE_UNISCRIBE)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc)
|
||||
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_sources ${PROJECT_SOURCE_DIR}/src/hb-directwrite.cc)
|
||||
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 (FindPythonInterp)
|
||||
include (FindPerl)
|
||||
|
||||
|
||||
# Use the hints from glib-2.0.pc to find glib-mkenums
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_GLIB QUIET glib-2.0)
|
||||
|
@ -446,72 +477,41 @@ 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
|
||||
SOURCES ${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
|
||||
SOURCES ${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
|
||||
if (HB_HAVE_ICU)
|
||||
add_library(harfbuzz-icu ${PROJECT_SOURCE_DIR}/src/hb-icu.cc ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
|
||||
add_dependencies(harfbuzz-icu harfbuzz)
|
||||
target_link_libraries(harfbuzz-icu harfbuzz ${THIRD_PARTY_LIBS})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz harfbuzz-icu PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
## Define harfbuzz-subset library
|
||||
if (HB_BUILD_SUBSET)
|
||||
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})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (UNIX OR MINGW)
|
||||
# Make symbols link locally
|
||||
include (CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
|
||||
if (CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
|
||||
link_libraries(-Bsymbolic-functions)
|
||||
endif ()
|
||||
|
||||
# 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
|
||||
set (CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
|
||||
set_target_properties(harfbuzz PROPERTIES LINKER_LANGUAGE C)
|
||||
if (HB_BUILD_SUBSET)
|
||||
set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C)
|
||||
endif ()
|
||||
|
||||
# No threadsafe statics as we do it ourselves
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics")
|
||||
endif ()
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
|
||||
## Define harfbuzz-gobject library
|
||||
|
@ -525,14 +525,6 @@ if (HB_HAVE_GOBJECT)
|
|||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src)
|
||||
add_dependencies(harfbuzz-gobject harfbuzz)
|
||||
target_link_libraries(harfbuzz-gobject harfbuzz ${GOBJECT_LIBRARIES} ${THIRD_PARTY_LIBS})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz-gobject PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (BUILD_SHARED_LIBS AND WIN32 AND NOT MINGW)
|
||||
add_definitions("-DHB_DLL_EXPORT")
|
||||
endif ()
|
||||
|
||||
# On Windows, g-ir-scanner requires a DLL build in order for it to work
|
||||
|
@ -544,6 +536,7 @@ if (WIN32)
|
|||
endif ()
|
||||
|
||||
if (HB_HAVE_INTROSPECTION)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
|
||||
|
||||
|
@ -566,7 +559,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}/$<CONFIG>")
|
||||
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
|
||||
else ()
|
||||
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
|
||||
endif ()
|
||||
|
@ -611,25 +604,18 @@ if (HB_HAVE_INTROSPECTION)
|
|||
endif ()
|
||||
endforeach ()
|
||||
|
||||
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list)
|
||||
foreach (s ${introspected_sources})
|
||||
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list "${s}\n")
|
||||
endforeach ()
|
||||
|
||||
# Finally, build the introspection files...
|
||||
add_custom_command(
|
||||
TARGET harfbuzz-gobject
|
||||
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-gobject
|
||||
--c-include=hb-gobject.h
|
||||
--pkg-export=harfbuzz
|
||||
--cflags-begin
|
||||
-I${PROJECT_SOURCE_DIR}/src
|
||||
-I${PROJECT_BINARY_DIR}/src
|
||||
|
@ -639,8 +625,6 @@ if (HB_HAVE_INTROSPECTION)
|
|||
-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_EXTERN=
|
||||
|
@ -649,9 +633,9 @@ if (HB_HAVE_INTROSPECTION)
|
|||
--library=harfbuzz
|
||||
-L${hb_libpath}
|
||||
${extra_libs}
|
||||
--filelist ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list
|
||||
${introspected_sources}
|
||||
-o ${hb_libpath}/HarfBuzz-0.0.gir
|
||||
DEPENDS harfbuzz-gobject harfbuzz ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list
|
||||
DEPENDS harfbuzz-gobject harfbuzz
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
|
@ -700,9 +684,6 @@ if (HB_BUILD_UTILS)
|
|||
add_executable(hb-shape ${HB_SHAPE_sources})
|
||||
target_link_libraries(hb-shape harfbuzz)
|
||||
|
||||
add_executable(hb-subset ${HB_SUBSET_CLI_sources})
|
||||
target_link_libraries(hb-subset harfbuzz harfbuzz-subset)
|
||||
|
||||
add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
|
||||
target_link_libraries(hb-ot-shape-closure harfbuzz)
|
||||
|
||||
|
@ -720,82 +701,18 @@ 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
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
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
|
||||
)
|
||||
if (HB_HAVE_ICU)
|
||||
install(TARGETS harfbuzz-icu
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
FRAMEWORK DESTINATION Library/Frameworks
|
||||
)
|
||||
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)
|
||||
install(TARGETS harfbuzz-subset
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
endif ()
|
||||
install(TARGETS hb-view
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
install(TARGETS hb-subset
|
||||
install(TARGETS hb-view
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
|
@ -813,10 +730,9 @@ 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}/$<CONFIG>")
|
||||
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
|
||||
else ()
|
||||
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
|
||||
endif ()
|
||||
|
@ -831,3 +747,51 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
|
|||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set (CMAKE_CXX_FLAGS "-fcolor-diagnostics ${CMAKE_CXX_FLAGS}")
|
||||
set (CMAKE_C_FLAGS "-fcolor-diagnostics ${CMAKE_C_FLAGS}")
|
||||
endif ()
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set (CMAKE_CXX_FLAGS "-fdiagnostics-color ${CMAKE_CXX_FLAGS}")
|
||||
set (CMAKE_C_FLAGS "-fdiagnostics-color ${CMAKE_C_FLAGS}")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
## Tests
|
||||
if (UNIX)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
# does some "make" stuff inside
|
||||
#add_test(NAME check-defs.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-defs.sh)
|
||||
#set_tests_properties(check-defs.sh PROPERTIES ENVIRONMENT "libs=.")
|
||||
|
||||
# broken on cmake builds right now :(
|
||||
#add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
|
||||
#add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
|
||||
#set_tests_properties(check-symbols.sh check-libstdc++.sh PROPERTIES ENVIRONMENT "libs=.")
|
||||
|
||||
if (NOT APPLE)
|
||||
add_test(NAME check-static-inits.sh
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/CMakeFiles/harfbuzz.dir/src # ugly hack
|
||||
)
|
||||
set_tests_properties(check-static-inits.sh PROPERTIES ENVIRONMENT "libs=.")
|
||||
endif ()
|
||||
else ()
|
||||
message(WARN "Enable BUILD_SHARED_LIBS for more tests.")
|
||||
endif ()
|
||||
|
||||
if (IN_HB_DIST)
|
||||
add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
|
||||
add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
|
||||
endif ()
|
||||
|
||||
add_test(NAME check-externs.sh COMMAND ./check-externs.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
|
||||
add_test(NAME check-includes.sh COMMAND ./check-includes.sh WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
|
||||
endif ()
|
||||
|
||||
# Needs to come last so that variables defined above are passed to
|
||||
# subdirectories.
|
||||
add_subdirectory(test)
|
158
CONFIG.md
158
CONFIG.md
|
@ -1,158 +0,0 @@
|
|||
# Configuring HarfBuzz
|
||||
|
||||
Most of the time you will not need any custom configuration. The 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
|
||||
sure the relevant ones are enabled.
|
||||
|
||||
If you are building for custom environment (embedded, downloadable app, etc)
|
||||
where you mostly just want to call `hb_shape()` and the binary size of the
|
||||
resulting library is very important to you, the rest of this file guides you
|
||||
through your options to disable features you may not need, in exchange for
|
||||
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`. 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,
|
||||
the optimize-size builds perform *faster* as well, thanks to lower code
|
||||
footprint and caching effects. So, definitely try that even if size is not
|
||||
extremely tight but you have a huge application. For example, Chrome does
|
||||
that. Note that this configuration also automatically enables certain internal
|
||||
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, 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
|
||||
library into your app, make sure your linker removes unused functions. This
|
||||
can be tricky and differ from environment to environment, but you definitely
|
||||
want to make sure this happens. Otherwise, every unused public function will
|
||||
be adding unneeded bytes to your binary. The following pointers might come
|
||||
handy:
|
||||
|
||||
* https://lwn.net/Articles/741494/ (all of the four-part series)
|
||||
* https://elinux.org/images/2/2d/ELC2010-gc-sections_Denys_Vlasenko.pdf
|
||||
|
||||
Combining the above three build options should already shrink your library a lot.
|
||||
The rest of this file shows you ways to shrink the library even further at the
|
||||
expense of removing functionality (that may not be needed). The remaining
|
||||
options are all enabled by defining pre-processor macros, which can be done
|
||||
via `CXXFLAGS` or `CPPFLAGS` similarly.
|
||||
|
||||
|
||||
## Unicode-functions
|
||||
|
||||
Access to Unicode data can be configured at compile time as well as run-time.
|
||||
By default, HarfBuzz ships with its own compact subset of properties from
|
||||
Unicode Character Database that it needs. This is a highly-optimized
|
||||
implementation that depending on compile settings (optimize-size or not)
|
||||
takes around ~40kb or ~60kb. Using this implementation (default) is highly
|
||||
recommended, as HarfBuzz always ships with data from latest version of Unicode.
|
||||
This implementation can be disabled by defining `HB_NO_UCD`.
|
||||
|
||||
For example, if you are enabling ICU as a built-in option, or GLib, those
|
||||
can provide Unicode data as well, so defining `HB_NO_UCD` might save you
|
||||
space without reducing functionality (to the extent that the Unicode version
|
||||
of those implementations is recent.)
|
||||
|
||||
If, however, you provide your own Unicode data to HarfBuzz at run-time by
|
||||
calling `hb_buffer_set_unicode_funcs` on every buffer you create, and you do
|
||||
not rely on `hb_unicode_funcs_get_default()` results, you can disable the
|
||||
internal implementation by defining both `HB_NO_UCD` and `HB_NO_UNICODE_FUNCS`.
|
||||
The latter is needed to guard against accidentally building a library without
|
||||
any default Unicode implementations.
|
||||
|
||||
|
||||
## Font-functions
|
||||
|
||||
Access to certain font functionalities can also be configured at run-time. By
|
||||
default, HarfBuzz uses an efficient internal implementation of OpenType
|
||||
functionality for this. This internal implementation is called `hb-ot-font`.
|
||||
All newly-created `hb_font_t` objects by default use `hb-ot-font`. Using this
|
||||
is highly recommended, and is what fonts use by default when they are created.
|
||||
|
||||
Most embedded uses will probably use HarfBuzz with FreeType using `hb-ft.h`.
|
||||
In that case, or if you otherwise provide those functions by calling
|
||||
`hb_font_set_funcs()` on every font you create, you can disable `hb-ot-font`
|
||||
without loss of functionality by defining `HB_NO_OT_FONT`.
|
||||
|
||||
|
||||
## Shapers
|
||||
|
||||
Most HarfBuzz clients use it for the main shaper, called "ot". However, it
|
||||
is legitimate to want to compile HarfBuzz with only another backend, eg.
|
||||
CoreText, for example for an iOS app. For that, you want `HB_NO_OT_SHAPE`.
|
||||
If you are going down that route, check if you want `HB_NO_OT`.
|
||||
|
||||
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. 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 configuration (more below) disables thread-safety.
|
||||
|
||||
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`.
|
||||
|
||||
|
||||
## Pre-defined configurations
|
||||
|
||||
The [`hb-config.hh`](src/hb-config.hh) internal header supports three
|
||||
pre-defined configurations as well grouping of various configuration options.
|
||||
The pre-defined configurations are:
|
||||
|
||||
* `HB_MINI`: Disables shaping of AAT as well as legacy fonts. Ie. it produces
|
||||
a capable OpenType shaper only.
|
||||
|
||||
* `HB_LEAN`: Disables various non-shaping functionality in the library, as well
|
||||
as esoteric or rarely-used shaping features. See the definition for details.
|
||||
|
||||
* `HB_TINY`: Enables both `HB_MINI` and `HB_LEAN` configurations, as well as
|
||||
disabling thread-safety and debugging, and use even more size-optimized data
|
||||
tables.
|
||||
|
||||
|
||||
## Tailoring configuration
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
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 extents
|
||||
for CFF fonts, which many clients might not need.
|
20
COPYING
20
COPYING
|
@ -2,23 +2,17 @@ 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-2022 Google, Inc.
|
||||
Copyright © 2015-2020 Ebrahim Byagowi
|
||||
Copyright © 2019,2020 Facebook, Inc.
|
||||
Copyright © 2012,2015 Mozilla Foundation
|
||||
Copyright © 2010,2011,2012 Google, Inc.
|
||||
Copyright © 2012 Mozilla Foundation
|
||||
Copyright © 2011 Codethink Limited
|
||||
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
||||
Copyright © 2009 Keith Stribley
|
||||
Copyright © 2011 Martin Hosken and SIL International
|
||||
Copyright © 2009 Martin Hosken and SIL International
|
||||
Copyright © 2007 Chris Wilson
|
||||
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
|
||||
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
|
||||
|
||||
For full copyright notices consult the individual files in the package.
|
||||
|
||||
|
|
33
Makefile.am
33
Makefile.am
|
@ -4,28 +4,16 @@ NULL =
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src util test perf docs
|
||||
SUBDIRS = src util test docs
|
||||
|
||||
EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
harfbuzz.doap \
|
||||
README.md \
|
||||
README.python.md \
|
||||
README.python \
|
||||
BUILD.md \
|
||||
CONFIG.md \
|
||||
RELEASING.md \
|
||||
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 \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
|
@ -47,7 +35,7 @@ ChangeLog: $(srcdir)/ChangeLog
|
|||
$(srcdir)/ChangeLog:
|
||||
$(AM_V_GEN) if test -d "$(top_srcdir)/.git"; then \
|
||||
(GIT_DIR=$(top_srcdir)/.git \
|
||||
$(GIT) log $(CHANGELOG_RANGE) --stat) > $@.tmp \
|
||||
$(GIT) log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
|
||||
&& mv -f $@.tmp "$(srcdir)/ChangeLog" \
|
||||
|| ($(RM) $@.tmp; \
|
||||
echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
|
||||
|
@ -71,6 +59,8 @@ DISTCHECK_CONFIGURE_FLAGS = \
|
|||
--enable-introspection \
|
||||
$(NULL)
|
||||
|
||||
# TODO: Copy infrastructure from cairo
|
||||
|
||||
# TAR_OPTIONS is not set as env var for 'make dist'. How to fix that?
|
||||
TAR_OPTIONS = --owner=0 --group=0
|
||||
|
||||
|
@ -79,4 +69,17 @@ dist-hook: dist-clear-sticky-bits
|
|||
dist-clear-sticky-bits:
|
||||
chmod -R a-s $(distdir)
|
||||
|
||||
|
||||
tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.bz2
|
||||
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)
|
||||
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
[![Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
|
||||
[![CircleCI](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
|
||||
[![Coverity](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
|
||||
[![Coverage Status](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
|
||||
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
|
||||
|
||||
This is HarfBuzz, a text shaping library.
|
||||
|
||||
For bug reports, mailing list, and other information please visit:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see the file COPYING.
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
99
README.md
99
README.md
|
@ -1,99 +0,0 @@
|
|||
[![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 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&utm_medium=referral&utm_content=harfbuzz/harfbuzz&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)
|
||||
|
||||
# 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:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
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 testing and profiling, see [TESTING.md](TESTING.md).
|
||||
|
||||
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
|
||||
ain’t 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>
|
||||
|
||||
[![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
|
|
@ -1,58 +0,0 @@
|
|||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
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:
|
||||
|
||||
You want to follow the 32bit instructions. The 64bit equivalents are included
|
||||
for reference.
|
||||
|
||||
1. Install Wine.
|
||||
- Fedora: `dnf install wine`.
|
||||
|
||||
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`
|
||||
|
||||
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:
|
||||
|
||||
a) Install dependencies.
|
||||
- Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
|
||||
- Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
|
||||
|
||||
b) Configure:
|
||||
- `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
- 32bit: `../mingw-configure.sh i686`
|
||||
- 64bit: `../mingw-configure.sh x86_64`
|
||||
|
||||
c) Build as usual:
|
||||
- make
|
||||
|
||||
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)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
You want a Uniscribe from Windows 7 or older.
|
||||
|
||||
Put the DLL in the folder you are going to run the next command,
|
||||
|
||||
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:
|
||||
|
||||
https://github.com/harfbuzz/harfbuzz/issues/3671
|
|
@ -0,0 +1,30 @@
|
|||
To enable HarfBuzz bindings for Python among other languages, make sure
|
||||
you have latest version of gobject-introspection available. On Ubuntu,
|
||||
you can install that this way:
|
||||
|
||||
sudo apt-get install libgirepository1.0-dev
|
||||
|
||||
And then run autogen.sh (if building from git), and then:
|
||||
|
||||
./configure --with-gobject --enable-introspection
|
||||
|
||||
Make sure that gobject-introspection is enabled then in the final report.
|
||||
|
||||
Compile and install.
|
||||
|
||||
Make sure you have the installation lib dir in LD_LIBRARY_PATH, as needed
|
||||
for the linker to find the library.
|
||||
|
||||
Then make sure you also have GI_TYPELIB_PATH pointing to the resulting
|
||||
$prefix/lib/girepository-* directory.
|
||||
|
||||
Make sure you have pygobject installed. Then check that the following
|
||||
import works in your Python interpretter:
|
||||
|
||||
from gi.repository import HarfBuzz
|
||||
|
||||
If it does, you are ready to call HarfBuzz from Python! Congratulations.
|
||||
See src/sample.py.
|
||||
|
||||
The Python API will change. Let us know on the mailing list if you are
|
||||
using it, and send lots of feedback.
|
|
@ -1,31 +0,0 @@
|
|||
To enable HarfBuzz bindings for Python among other languages, make sure
|
||||
you have latest version of gobject-introspection available. On Ubuntu,
|
||||
you can install that this way:
|
||||
|
||||
```bash
|
||||
sudo apt-get install libgirepository1.0-dev
|
||||
```
|
||||
|
||||
And then run `meson setup` and make sure that `Introspection` is reported
|
||||
enabled in output.
|
||||
|
||||
Compile and install.
|
||||
|
||||
Make sure you have the installation lib dir in `LD_LIBRARY_PATH`, as needed
|
||||
for the linker to find the library.
|
||||
|
||||
Then make sure you also have `GI_TYPELIB_PATH` pointing to the resulting
|
||||
`$prefix/lib/girepository-*` directory.
|
||||
|
||||
Make sure you have pygobject installed. Then check that the following
|
||||
import works in your Python interpreter:
|
||||
|
||||
```python
|
||||
from gi.repository import HarfBuzz
|
||||
```
|
||||
|
||||
If it does, you are ready to call HarfBuzz from Python! Congratulations.
|
||||
See [`src/sample.py`](src/sample.py).
|
||||
|
||||
The Python API will change. Let us know on the mailing list if you are
|
||||
using it, and send lots of feedback.
|
134
RELEASING.md
134
RELEASING.md
|
@ -1,37 +1,125 @@
|
|||
# HarfBuzz release walk-through checklist:
|
||||
HarfBuzz release walk-through checklist:
|
||||
|
||||
- [ ] Open gitk and review changes since last release.
|
||||
1. Open gitk and review changes since last release.
|
||||
|
||||
- [ ] Print all public API changes:
|
||||
`git diff $(git describe | sed 's/-.*//').. src/*.h`
|
||||
* `git diff $(git describe | sed 's/-.*//').. src/*.h` prints all public API
|
||||
changes.
|
||||
|
||||
- [ ] Document them in NEWS.
|
||||
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
|
||||
Document them in NEWS. All API and API semantic changes should be clearly
|
||||
marked as API additions, API changes, or API deletions. Document
|
||||
deprecations.
|
||||
|
||||
- [ ] 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.
|
||||
If there's a backward-incompatible API change (including deletions for API
|
||||
used anywhere), that's a release blocker. Do NOT release.
|
||||
|
||||
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
|
||||
Do NOT release.
|
||||
2. Based on severity of changes, decide whether it's a minor or micro release
|
||||
number bump,
|
||||
|
||||
- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
|
||||
3. 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'.
|
||||
4. Bump version in configure.ac line 3,
|
||||
|
||||
- [ ] Make sure you have correct date and new version at the top of NEWS file.
|
||||
5. Do "make distcheck", if it passes, you get a tarball.
|
||||
Otherwise, fix things and commit them separately before making release,
|
||||
|
||||
- [ ] Bump version in line 3 of meson.build and configure.ac.
|
||||
6. "make release-files". Enter your GPG password. This creates a sha256 hash
|
||||
and signs it.
|
||||
|
||||
- [ ] 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).
|
||||
7. Now that you have release files built, commit NEWS and configure.ac changes.
|
||||
The commit message is simply the release number. Eg. "1.4.7"
|
||||
|
||||
- [ ] 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"
|
||||
8. 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.
|
||||
9. 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. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
|
||||
|
||||
- [ ] Push the commit and tag out: `git push --follow-tags`.
|
||||
b. Run `./MING32 --with-uniscribe` script (available below) to configure harfbuzz with mingw in a subdirector (eg. winbuild/),
|
||||
|
||||
c. make
|
||||
|
||||
d. Back in the parent directory, run `./UPDATE.sh` (available below) to build win32 bundle.
|
||||
|
||||
10. 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.bz2
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
|
||||
```
|
||||
|
||||
11. While doing that, quickly double-check the size of the .tar.bz2 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.
|
||||
|
||||
12. Push the commit and tag out: "git push --follow-tags". Make sure it's
|
||||
pushed both to freedesktop repo and github.
|
||||
|
||||
13. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
|
||||
edit the tag, upload artefacts and NEWS entry and save.
|
||||
|
||||
|
||||
## MING32
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
target=i686-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS=-I$HOME/.local/$target/include
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
```
|
||||
|
||||
## UPDATE.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
v=$1
|
||||
|
||||
if test "x$v" = x; then
|
||||
echo "usage: UPDATE.sh micro-version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir_prefix=harfbuzz-1.4.
|
||||
dir_suffix=-win32
|
||||
dir=$dir_prefix$v$dir_suffix
|
||||
dir_old=$dir_prefix$((v-1))$dir_suffix
|
||||
if test -d "$dir"; then
|
||||
echo "New dir $dir exists; not overwriting"
|
||||
exit 1
|
||||
fi
|
||||
if ! test -d "$dir_old"; then
|
||||
echo "Old dir $dir_old does NOT exist; aborting"
|
||||
exit 1
|
||||
fi
|
||||
set -ex
|
||||
cp -a "$dir_old" "$dir.tmp"
|
||||
rm -f "$dir.tmp"/GDX32.dll
|
||||
rm -f "$dir.tmp"/usp10.dll
|
||||
cp ../winbuild/src/.libs/libharfbuzz-0.dll{,.def} $dir.tmp/
|
||||
cp ../winbuild/util/.libs/hb-{shape,view}.exe $dir.tmp/
|
||||
i686-w64-mingw32-strip $dir.tmp/{hb-shape.exe,hb-view.exe,libharfbuzz-0.dll}
|
||||
mv $dir.tmp $dir
|
||||
zip -r $dir.zip $dir
|
||||
echo Bundle $dir.zip ready
|
||||
```
|
||||
|
|
20
SECURITY.md
20
SECURITY.md
|
@ -1,20 +0,0 @@
|
|||
# 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.
|
47
TESTING.md
47
TESTING.md
|
@ -1,47 +0,0 @@
|
|||
## 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
|
||||
CPPFLAGS='-DHB_DEBUG_SUBSET=100' meson setup build --reconfigure
|
||||
meson test -C build
|
||||
```
|
||||
|
||||
### Run tests with asan
|
||||
|
||||
```shell
|
||||
meson setup build -Db_sanitize=address --reconfigure
|
||||
meson compile -C build
|
||||
meson test -C build
|
||||
```
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```shell
|
||||
CPPFLAGS=-DHB_DEBUG_SUBSET=100 meson build --reconfigure
|
||||
ninja -C build
|
||||
```
|
||||
|
||||
## Test with the Fuzzer
|
||||
|
||||
FOr fuzzing, see `test/fuzzing/README.md`.
|
||||
|
||||
## Profiling
|
||||
|
||||
For profiling, see `perf/README.md`.
|
||||
|
2
THANKS
2
THANKS
|
@ -1,6 +1,6 @@
|
|||
Bradley Grainger
|
||||
Khaled Hosny
|
||||
Kenichi Ishibashi
|
||||
Ivan Kuckir <https://photopea.com/>
|
||||
Ryan Lortie
|
||||
Jeff Muizelaar
|
||||
suzuki toshiya
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
General fixes:
|
||||
=============
|
||||
|
||||
- AAT 'morx' implementation.
|
||||
|
||||
- Return "safe-to-break" bit from shaping.
|
||||
|
||||
- Implement 'rand' feature.
|
||||
|
||||
- mask propagation? (when ligation, "or" the masks).
|
||||
|
||||
|
||||
API issues:
|
||||
===========
|
||||
|
||||
- API to accept a list of languages?
|
||||
|
||||
- Add init_func to font_funcs. Adjust ft.
|
||||
|
||||
- 'const' for getter APIs? (use mutable internally)
|
||||
|
||||
- Remove hb_ot_shape_glyphs_closure()?
|
||||
|
||||
|
||||
API additions
|
||||
=============
|
||||
|
||||
- Language to/from script.
|
||||
|
||||
- blob_from_file?
|
||||
|
||||
- Add hb-cairo glue
|
||||
|
||||
- Add sanitize API (and a cached version, that saves result on blob user-data)
|
||||
|
||||
- BCP 47 language handling / API (language_matches?)
|
||||
|
||||
- Add hb_font_create_unscaled()?
|
||||
|
||||
- Add query / enumeration API for aalt-like features?
|
||||
|
||||
- SFNT api? get_num_faces? get_table_tags? (there's something in stash)
|
||||
|
||||
- Add segmentation API
|
||||
|
||||
- Add hb-fribidi glue?
|
||||
|
||||
|
||||
hb-view / hb-shape enhancements:
|
||||
===============================
|
||||
|
||||
- Add --width, --height, --auto-size, --ink-box, --align, etc?
|
||||
|
||||
|
||||
Tests to write:
|
||||
==============
|
||||
|
||||
- ot-layout enumeration API (needs font)
|
||||
|
||||
- Finish test-shape.c, grep for TODO
|
||||
|
||||
- Finish test-unicode.c, grep for TODO
|
||||
|
||||
- GObject, FreeType, etc
|
||||
|
||||
- hb_cache_t and relatives
|
||||
|
||||
- hb_feature_to/from_string
|
||||
- hb_buffer_[sg]et_contents
|
|
@ -0,0 +1,53 @@
|
|||
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
|
||||
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /c/msys2/mingw64/
|
||||
MINGW_CHOST: x86_64-w64-mingw32
|
||||
MSYS2_ARCH: x86_64
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /c/msys2/mingw32/
|
||||
MINGW_CHOST: i686-w64-mingw32
|
||||
MSYS2_ARCH: i686
|
||||
|
||||
install:
|
||||
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
|
||||
|
||||
build_script:
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
|
||||
- 'if "%compiler%"=="msvc" md build'
|
||||
- 'if "%compiler%"=="msvc" cd build'
|
||||
- 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin;c:\msys64\mingw64\bin' # msys2 is added just for having "ragel" on PATH
|
||||
|
||||
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%" ../'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -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" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
|
||||
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
|
||||
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
|
||||
- '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 --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make; make check || (cat */test-suite.log test/*/test-suite.log && false)"'
|
||||
|
||||
cache:
|
||||
- c:\tools\vcpkg\installed\
|
||||
|
||||
# disable automatic tests
|
||||
test: off
|
18
autogen.sh
18
autogen.sh
|
@ -7,24 +7,24 @@ test -n "$srcdir" || srcdir=.
|
|||
olddir=`pwd`
|
||||
cd $srcdir
|
||||
|
||||
#printf "checking for ragel... "
|
||||
#which ragel || {
|
||||
# echo "You need to install ragel... See http://www.complang.org/ragel/"
|
||||
# exit 1
|
||||
#}
|
||||
echo -n "checking for ragel... "
|
||||
which ragel || {
|
||||
echo "You need to install ragel... See http://www.complang.org/ragel/"
|
||||
exit 1
|
||||
}
|
||||
|
||||
printf "checking for pkg-config... "
|
||||
echo -n "checking for pkg-config... "
|
||||
which pkg-config || {
|
||||
echo "*** No pkg-config found, please install it ***"
|
||||
exit 1
|
||||
}
|
||||
|
||||
printf "checking for libtoolize... "
|
||||
echo -n "checking for libtoolize... "
|
||||
which glibtoolize || which libtoolize || {
|
||||
echo "*** No libtoolize (libtool) found, please install it ***"
|
||||
exit 1
|
||||
}
|
||||
printf "checking for gtkdocize... "
|
||||
echo -n "checking for gtkdocize... "
|
||||
if which gtkdocize ; then
|
||||
gtkdocize --copy || exit 1
|
||||
else
|
||||
|
@ -32,7 +32,7 @@ else
|
|||
echo "EXTRA_DIST = " > gtk-doc.make
|
||||
fi
|
||||
|
||||
printf "checking for autoreconf... "
|
||||
echo -n "checking for autoreconf... "
|
||||
which autoreconf || {
|
||||
echo "*** No autoreconf (autoconf) found, please install it ***"
|
||||
exit 1
|
||||
|
|
246
configure.ac
246
configure.ac
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[7.1.0],
|
||||
[1.7.4],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
@ -9,9 +9,8 @@ AC_CONFIG_MACRO_DIR([m4])
|
|||
AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-xz no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_SILENT_RULES([yes])
|
||||
AX_CODE_COVERAGE
|
||||
|
||||
# Initialize libtool
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
|
@ -19,13 +18,13 @@ LT_PREREQ([2.2])
|
|||
LT_INIT([disable-static])
|
||||
|
||||
# Check for programs
|
||||
AC_USE_SYSTEM_EXTENSIONS
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AX_CXX_COMPILE_STDCXX(11)
|
||||
AX_CXX_COMPILE_STDCXX(11, noext, optional)
|
||||
AC_SYS_LARGEFILE
|
||||
PKG_PROG_PKG_CONFIG([0.28])
|
||||
PKG_PROG_PKG_CONFIG([0.20])
|
||||
AM_MISSING_PROG([RAGEL], [ragel])
|
||||
AM_MISSING_PROG([GIT], [git])
|
||||
|
||||
|
@ -45,17 +44,19 @@ AC_SUBST(HB_VERSION)
|
|||
|
||||
# Libtool version
|
||||
m4_define([hb_version_int],
|
||||
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
|
||||
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
|
||||
AC_SUBST(HB_LIBTOOL_VERSION_INFO)
|
||||
|
||||
AC_ARG_WITH([libstdc++],
|
||||
[AS_HELP_STRING([--with-libstdc++=@<:@yes/no@:>@],
|
||||
[Allow linking with libstdc++ @<:@default=no@:>@])],
|
||||
[with_libstdcxx=$withval],
|
||||
[with_libstdcxx=no])
|
||||
AM_CONDITIONAL(WITH_LIBSTDCXX, [test "x$with_libstdcxx" = "xyes"])
|
||||
|
||||
# Documentation
|
||||
have_gtk_doc=false
|
||||
m4_ifdef([GTK_DOC_CHECK], [
|
||||
|
@ -68,8 +69,8 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
|
|||
])
|
||||
|
||||
# Functions and headers
|
||||
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale uselocale)
|
||||
AC_CHECK_HEADERS(unistd.h sys/mman.h stdbool.h xlocale.h)
|
||||
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l)
|
||||
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h)
|
||||
|
||||
# Compiler flags
|
||||
AC_CANONICAL_HOST
|
||||
|
@ -77,15 +78,13 @@ AC_CHECK_ALIGNOF([struct{char;}])
|
|||
if test "x$GCC" = "xyes"; then
|
||||
|
||||
# Make symbols link locally
|
||||
AX_CHECK_LINK_FLAG([[-Bsymbolic-functions]], [LDFLAGS="$LDFLAGS -Bsymbolic-functions"])
|
||||
LDFLAGS="$LDFLAGS -Bsymbolic-functions"
|
||||
|
||||
# Make it possible to not link to libstdc++
|
||||
# No threadsafe statics in C++ as we do it ourselves.
|
||||
# We don't use these features, so it's safe to disable them
|
||||
# even in the cases where we DO link to libstdc++.
|
||||
# Put -fno-rtti before $CXXFLAGS such that users can re-enable it
|
||||
# by overriding CXXFLAGS.
|
||||
CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics"
|
||||
# Make sure we don't link to libstdc++
|
||||
CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
|
||||
|
||||
# Assorted warnings
|
||||
CXXFLAGS="$CXXFLAGS -Wcast-align"
|
||||
|
||||
case "$host" in
|
||||
*-*-mingw*)
|
||||
|
@ -119,7 +118,9 @@ AC_MSG_RESULT([$hb_os_win32])
|
|||
AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes")
|
||||
|
||||
have_pthread=false
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
if test "$hb_os_win32" = no; then
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
fi
|
||||
if $have_pthread; then
|
||||
AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
|
||||
fi
|
||||
|
@ -127,6 +128,20 @@ AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
|
|||
|
||||
dnl ==========================================================================
|
||||
|
||||
have_ot=true
|
||||
if $have_ot; then
|
||||
AC_DEFINE(HAVE_OT, 1, [Have native OpenType Layout backend])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_OT, $have_ot)
|
||||
|
||||
have_fallback=true
|
||||
if $have_fallback; then
|
||||
AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_FALLBACK, $have_fallback)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(glib,
|
||||
[AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@],
|
||||
[Use glib @<:@default=auto@:>@])],,
|
||||
|
@ -164,7 +179,6 @@ if $have_gobject; then
|
|||
AC_SUBST(GLIB_MKENUMS)
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GOBJECT, $have_gobject)
|
||||
AC_SUBST(have_gobject)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
|
@ -194,10 +208,6 @@ 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])
|
||||
|
@ -218,21 +228,21 @@ AM_CONDITIONAL(HAVE_CAIRO_FT, $have_cairo_ft)
|
|||
|
||||
dnl ==========================================================================
|
||||
|
||||
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, :)
|
||||
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, :)
|
||||
fi
|
||||
if test "x$with_chafa" = "xyes" -a "x$have_chafa" != "xtrue"; then
|
||||
AC_MSG_ERROR([chafa support requested but not found])
|
||||
if test "x$with_fontconfig" = "xyes" -a "x$have_fontconfig" != "xtrue"; then
|
||||
AC_MSG_ERROR([fontconfig support requested but not found])
|
||||
fi
|
||||
if $have_chafa; then
|
||||
AC_DEFINE(HAVE_CHAFA, 1, [Have chafa terminal graphics library])
|
||||
if $have_fontconfig; then
|
||||
AC_DEFINE(HAVE_FONTCONFIG, 1, [Have fontconfig library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_CHAFA, $have_chafa)
|
||||
AM_CONDITIONAL(HAVE_FONTCONFIG, $have_fontconfig)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
|
@ -243,6 +253,25 @@ 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])
|
||||
|
@ -260,12 +289,27 @@ AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin")
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(ucdn,
|
||||
[AS_HELP_STRING([--with-ucdn=@<:@yes/no@:>@],
|
||||
[Use builtin UCDN library @<:@default=yes@:>@])],,
|
||||
[with_ucdn=yes])
|
||||
have_ucdn=false
|
||||
if test "x$with_ucdn" = "xyes"; then
|
||||
have_ucdn=true
|
||||
fi
|
||||
if $have_ucdn; then
|
||||
AC_DEFINE(HAVE_UCDN, 1, [Have UCDN Unicode functions])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_UCDN, $have_ucdn)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(graphite2,
|
||||
[AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@],
|
||||
[Use the graphite2 library @<:@default=no@:>@])],,
|
||||
[with_graphite2=no])
|
||||
have_graphite2=false
|
||||
GRAPHITE2_DEPS="graphite2 >= 1.2.0"
|
||||
GRAPHITE2_DEPS="graphite2"
|
||||
AC_SUBST(GRAPHITE2_DEPS)
|
||||
if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then
|
||||
PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :)
|
||||
|
@ -308,7 +352,9 @@ 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 FT_Get_Transform)
|
||||
AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates)
|
||||
AC_CHECK_FUNCS(FT_Set_Var_Blend_Coordinates)
|
||||
AC_CHECK_FUNCS(FT_Done_MM_Var)
|
||||
LIBS=$save_libs
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
|
||||
|
@ -337,28 +383,6 @@ AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe)
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(gdi,
|
||||
[AS_HELP_STRING([--with-gdi=@<:@yes/no/auto@:>@],
|
||||
[Provide GDI integration helpers @<:@default=no@:>@])],,
|
||||
[with_gdi=no])
|
||||
have_gdi=false
|
||||
if test "x$with_gdi" = "xyes" -o "x$with_gdi" = "xauto"; then
|
||||
AC_CHECK_HEADERS(windows.h, have_gdi=true)
|
||||
fi
|
||||
if test "x$with_gdi" = "xyes" -a "x$have_gdi" != "xtrue"; then
|
||||
AC_MSG_ERROR([gdi support requested but not found])
|
||||
fi
|
||||
if $have_gdi; then
|
||||
GDI_CFLAGS=
|
||||
GDI_LIBS="-lgdi32"
|
||||
AC_SUBST(GDI_CFLAGS)
|
||||
AC_SUBST(GDI_LIBS)
|
||||
AC_DEFINE(HAVE_GDI, 1, [Have GDI library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GDI, $have_gdi)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(directwrite,
|
||||
[AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@],
|
||||
[Use the DirectWrite library (experimental) @<:@default=no@:>@])],,
|
||||
|
@ -366,13 +390,17 @@ 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_1.h, have_directwrite=true)
|
||||
AC_CHECK_HEADERS(dwrite.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="-ldwrite"
|
||||
AC_SUBST(DIRECTWRITE_CXXFLAGS)
|
||||
AC_SUBST(DIRECTWRITE_LIBS)
|
||||
AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
|
||||
|
@ -417,70 +445,90 @@ 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
|
||||
src/harfbuzz-config.cmake
|
||||
src/hb-version.h
|
||||
src/hb-ucdn/Makefile
|
||||
util/Makefile
|
||||
test/Makefile
|
||||
test/api/Makefile
|
||||
test/fuzzing/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
|
||||
test/shaping/Makefile
|
||||
test/shaping/data/Makefile
|
||||
test/shaping/data/in-house/Makefile
|
||||
test/shaping/data/text-rendering-tests/Makefile
|
||||
docs/Makefile
|
||||
docs/version.xml
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo
|
||||
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:
|
||||
|
||||
Unicode callbacks (you want at least one):
|
||||
Builtin true
|
||||
Builtin (UCDN): ${have_ucdn}
|
||||
Glib: ${have_glib}
|
||||
ICU: ${have_icu}
|
||||
|
||||
Font callbacks (the more the merrier):
|
||||
Font callbacks (the more the better):
|
||||
FreeType: ${have_freetype}
|
||||
|
||||
Tools used for command-line utilities:
|
||||
Cairo: ${have_cairo}
|
||||
Chafa: ${have_chafa}
|
||||
Fontconfig: ${have_fontconfig}
|
||||
|
||||
Additional shapers:
|
||||
Additional shapers (the more the better):
|
||||
Graphite2: ${have_graphite2}
|
||||
|
||||
Platform shapers (not normally needed):
|
||||
CoreText: ${have_coretext}
|
||||
DirectWrite: ${have_directwrite}
|
||||
GDI: ${have_gdi}
|
||||
Uniscribe: ${have_uniscribe}
|
||||
DirectWrite: ${have_directwrite}
|
||||
|
||||
Other features:
|
||||
Documentation: ${enable_gtk_doc}
|
||||
Documentation: ${have_gtk_doc}
|
||||
GObject bindings: ${have_gobject}
|
||||
Introspection: ${have_introspection}
|
||||
])
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 8.6 KiB |
|
@ -1,8 +1,277 @@
|
|||
<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"/>
|
||||
<?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>
|
||||
|
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 31 KiB |
|
@ -29,12 +29,15 @@ 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|HB_DEPRECATED|HB_DEPRECATED_FOR()'
|
||||
--ignore-decorators="HB_EXTERN"
|
||||
|
||||
# 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@^.*/@@'`
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.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
|
||||
|
@ -59,6 +62,7 @@ CFILE_GLOB=$(top_srcdir)/src/hb-*.cc
|
|||
|
||||
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
|
||||
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
|
||||
EXTRA_HFILES=$(top_builddir)/src/hb-version.h
|
||||
|
||||
# Images to copy into HTML directory.
|
||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||||
|
@ -69,21 +73,17 @@ HTML_IMAGES= \
|
|||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
|
||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
|
||||
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 \
|
||||
usermanual-fonts-and-faces.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-hello-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-opentype-features.xml \
|
||||
usermanual-what-is-harfbuzz.xml \
|
||||
version.xml
|
||||
|
||||
# SGML files where gtk-doc abbreviations (#GtkWidget) are expanded
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
# These files must be listed here *and* in content_files
|
||||
# e.g. expand_content_files=running.sgml
|
||||
expand_content_files=
|
||||
|
@ -104,14 +104,14 @@ include $(top_srcdir)/gtk-doc.make
|
|||
|
||||
# Other files to distribute
|
||||
# e.g. EXTRA_DIST += version.xml.in
|
||||
EXTRA_DIST += version.xml.in meson.build
|
||||
EXTRA_DIST += version.xml.in
|
||||
|
||||
# Files not to distribute
|
||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
|
||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
|
||||
#DISTCLEANFILES +=
|
||||
|
||||
# Comment this out if you don't want 'make check' to test you doc status
|
||||
# Comment this out if you want 'make check' to test you doc status
|
||||
# and run some sanity checks
|
||||
if ENABLE_GTK_DOC
|
||||
TESTS_ENVIRONMENT = cd $(srcdir) && \
|
||||
|
|
|
@ -1,259 +0,0 @@
|
|||
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];
|
||||
|
||||
}
|
|
@ -11,37 +11,46 @@
|
|||
<title>HarfBuzz</title>
|
||||
<graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
|
||||
<para>
|
||||
HarfBuzz is a text shaping library. Using the HarfBuzz library allows
|
||||
programs to convert a sequence of Unicode input into
|
||||
properly formatted and positioned glyph output—for any writing
|
||||
system and language.
|
||||
HarfBuzz is an <ulink url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>
|
||||
text shaping engine.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The canonical source-code tree is available at
|
||||
<ulink url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
|
||||
See <xref linkend="download" endterm="download.title"/> for
|
||||
release tarballs.
|
||||
The current HarfBuzz codebase, formerly known as harfbuzz-ng, is
|
||||
versioned 1.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. The canonical
|
||||
source tree is available
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
|
||||
Also available on
|
||||
<ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
|
||||
See <xref linkend="download" endterm="download.title"/> for release tarballs.
|
||||
</para>
|
||||
<para>
|
||||
The old HarfBuzz codebase, these days known as harfbuzz-old, was
|
||||
derived from <ulink url="http://freetype.org/">FreeType</ulink>,
|
||||
<ulink url="http://pango.org/">Pango</ulink>, and
|
||||
<ulink url="http://qt-project.org/">Qt</ulink> and is available
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>.
|
||||
It is not actively developed or maintained, and is extremely buggy. All
|
||||
users are encouraged to switch over to the new HarfBuzz as soon as
|
||||
possible. There are no release tarballs of old HarfBuzz whatsoever.
|
||||
</para>
|
||||
</abstract>
|
||||
</bookinfo>
|
||||
|
||||
<part id="user-manual">
|
||||
<part>
|
||||
<title>User's manual</title>
|
||||
<xi:include href="usermanual-what-is-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-install-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-getting-started.xml"/>
|
||||
<xi:include href="usermanual-shaping-concepts.xml"/>
|
||||
<xi:include href="usermanual-object-model.xml"/>
|
||||
<xi:include href="usermanual-hello-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
|
||||
<xi:include href="usermanual-fonts-and-faces.xml"/>
|
||||
<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"/>
|
||||
<xi:include href="usermanual-opentype-features.xml"/>
|
||||
<xi:include href="usermanual-glyph-information.xml"/>
|
||||
</part>
|
||||
|
||||
<part id="reference-manual">
|
||||
<part>
|
||||
<partinfo>
|
||||
<releaseinfo>
|
||||
This document is for HarfBuzz &version;.
|
||||
|
@ -49,171 +58,153 @@
|
|||
<ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
|
||||
</releaseinfo>
|
||||
</partinfo>
|
||||
|
||||
<title>Reference manual</title>
|
||||
<chapter id="core-api">
|
||||
<title>Core API</title>
|
||||
<xi:include href="xml/hb-blob.xml"/>
|
||||
<xi:include href="xml/hb-buffer.xml"/>
|
||||
<chapter>
|
||||
<title>HarfBuzz API</title>
|
||||
<xi:include href="xml/hb.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-unicode.xml"/>
|
||||
<xi:include href="xml/hb-buffer.xml"/>
|
||||
<xi:include href="xml/hb-blob.xml"/>
|
||||
<xi:include href="xml/hb-face.xml"/>
|
||||
<xi:include href="xml/hb-font.xml"/>
|
||||
<xi:include href="xml/hb-map.xml"/>
|
||||
<xi:include href="xml/hb-set.xml"/>
|
||||
<xi:include href="xml/hb-shape-plan.xml"/>
|
||||
<xi:include href="xml/hb-shape.xml"/>
|
||||
<xi:include href="xml/hb-unicode.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-version.xml"/>
|
||||
</chapter>
|
||||
<xi:include href="xml/hb-deprecated.xml"/>
|
||||
|
||||
<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-set.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-ot.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-tag.xml"/>
|
||||
<xi:include href="xml/hb-ot-font.xml"/>
|
||||
<xi:include href="xml/hb-ot-shape.xml"/>
|
||||
<xi:include href="xml/hb-ot-var.xml"/>
|
||||
</chapter>
|
||||
<xi:include href="xml/hb-ot-math.xml"/>
|
||||
|
||||
<chapter id="apple-advanced-typography-api">
|
||||
<title>Apple Advanced Typography API</title>
|
||||
<xi:include href="xml/hb-aat-layout.xml"/>
|
||||
</chapter>
|
||||
<xi:include href="xml/hb-shape-plan.xml"/>
|
||||
|
||||
<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-graphite2.xml"/>
|
||||
<xi:include href="xml/hb-icu.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-ft.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-graphite2.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"/>
|
||||
<xi:include href="xml/hb-coretext.xml"/>
|
||||
|
||||
<xi:include href="xml/hb-gobject.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">
|
||||
<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"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.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>
|
||||
</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="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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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="deprecated-api-index" role="deprecated">
|
||||
<title>Index of deprecated API</title>
|
||||
<xi:include href="xml/api-index-deprecated.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
|
@ -1,64 +0,0 @@
|
|||
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
294
docs/repacker.md
|
@ -1,294 +0,0 @@
|
|||
# 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.
|
|
@ -1,178 +0,0 @@
|
|||
# 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 ();
|
||||
|
||||
```
|
|
@ -1,228 +0,0 @@
|
|||
# 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%
|
|
@ -1,44 +1,29 @@
|
|||
<?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="buffers-language-script-and-direction">
|
||||
<title>Buffers, language, script and direction</title>
|
||||
<para>
|
||||
The input to the HarfBuzz shaper is a series of Unicode characters, stored in a
|
||||
The input to HarfBuzz is a series of Unicode characters, stored in a
|
||||
buffer. In this chapter, we'll look at how to set up a buffer with
|
||||
the text that we want and how to customize the properties of the
|
||||
buffer. We'll also look at a piece of lower-level machinery that
|
||||
you will need to understand before proceeding: the functions that
|
||||
HarfBuzz uses to retrieve Unicode information.
|
||||
</para>
|
||||
<para>
|
||||
After shaping is complete, HarfBuzz puts its output back
|
||||
into the buffer. But getting that output requires setting up a
|
||||
face and a font first, so we will look at that in the next chapter
|
||||
instead of here.
|
||||
the text that we want and then customize the properties of the
|
||||
buffer.
|
||||
</para>
|
||||
<section id="creating-and-destroying-buffers">
|
||||
<title>Creating and destroying buffers</title>
|
||||
<para>
|
||||
As we saw in our <emphasis>Getting Started</emphasis> example, a
|
||||
buffer is created and
|
||||
initialized with <function>hb_buffer_create()</function>. This
|
||||
As we saw in our initial example, a buffer is created and
|
||||
initialized with <literal>hb_buffer_create()</literal>. This
|
||||
produces a new, empty buffer object, instantiated with some
|
||||
default values and ready to accept your Unicode strings.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages the memory of objects (such as buffers) that it
|
||||
creates, so you don't have to. When you have finished working on
|
||||
a buffer, you can call <function>hb_buffer_destroy()</function>:
|
||||
HarfBuzz manages the memory of objects that it creates (such as
|
||||
buffers), so you don't have to. When you have finished working on
|
||||
a buffer, you can call <literal>hb_buffer_destroy()</literal>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_t *buf = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buf);
|
||||
</programlisting>
|
||||
hb_buffer_t *buffer = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buffer);
|
||||
</programlisting>
|
||||
<para>
|
||||
This will destroy the object and free its associated memory -
|
||||
unless some other part of the program holds a reference to this
|
||||
|
@ -47,366 +32,46 @@
|
|||
else destroying it, you should increase its reference count:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
void somefunc(hb_buffer_t *buf) {
|
||||
buf = hb_buffer_reference(buf);
|
||||
...
|
||||
</programlisting>
|
||||
void somefunc(hb_buffer_t *buffer) {
|
||||
buffer = hb_buffer_reference(buffer);
|
||||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
And then decrease it once you're done with it:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
While we are on the subject of reference-counting buffers, it is
|
||||
worth noting that an individual buffer can only meaningfully be
|
||||
used by one thread at a time.
|
||||
</para>
|
||||
hb_buffer_destroy(buffer);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
To throw away all the data in your buffer and start from scratch,
|
||||
call <function>hb_buffer_reset(buf)</function>. If you want to
|
||||
call <literal>hb_buffer_reset(buffer)</literal>. If you want to
|
||||
throw away the string in the buffer but keep the options, you can
|
||||
instead call <function>hb_buffer_clear_contents(buf)</function>.
|
||||
instead call <literal>hb_buffer_clear_contents(buffer)</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="adding-text-to-the-buffer">
|
||||
<title>Adding text to the buffer</title>
|
||||
<para>
|
||||
Now we have a brand new HarfBuzz buffer. Let's start filling it
|
||||
with text! From HarfBuzz's perspective, a buffer is just a stream
|
||||
of Unicode code points, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, or
|
||||
UTF-32). HarfBuzz provides convenience functions that accept
|
||||
each of these encodings:
|
||||
<function>hb_buffer_add_utf8()</function>,
|
||||
<function>hb_buffer_add_utf16()</function>, and
|
||||
<function>hb_buffer_add_utf32()</function>. Other than the
|
||||
character encoding they accept, they function identically.
|
||||
of Unicode codepoints, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
|
||||
</para>
|
||||
<para>
|
||||
You can add UTF-8 text to a buffer by passing in the text array,
|
||||
the array's length, an offset into the array for the first
|
||||
character to add, and the length of the segment to add:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8 (hb_buffer_t *buf,
|
||||
const char *text,
|
||||
int text_length,
|
||||
unsigned int item_offset,
|
||||
int item_length)
|
||||
</programlisting>
|
||||
<para>
|
||||
So, in practice, you can say:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<para>
|
||||
This will append your new characters to
|
||||
<parameter>buf</parameter>, not replace its existing
|
||||
contents. Also, note that you can use <literal>-1</literal> in
|
||||
place of the first instance of <function>strlen(text)</function>
|
||||
if your text array is NULL-terminated. Similarly, you can also use
|
||||
<literal>-1</literal> as the final argument want to add its full
|
||||
contents.
|
||||
</para>
|
||||
<para>
|
||||
Whatever start <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> you provide, HarfBuzz will also
|
||||
attempt to grab the five characters <emphasis>before</emphasis>
|
||||
the offset point and the five characters
|
||||
<emphasis>after</emphasis> the designated end. These are the
|
||||
before and after "context" segments, which are used internally
|
||||
for HarfBuzz to make shaping decisions. They will not be part of
|
||||
the final output, but they ensure that HarfBuzz's
|
||||
script-specific shaping operations are correct. If there are
|
||||
fewer than five characters available for the before or after
|
||||
contexts, HarfBuzz will just grab what is there.
|
||||
</para>
|
||||
<para>
|
||||
For longer text runs, such as full paragraphs, it might be
|
||||
tempting to only add smaller sub-segments to a buffer and
|
||||
shape them in piecemeal fashion. Generally, this is not a good
|
||||
idea, however, because a lot of shaping decisions are
|
||||
dependent on this context information. For example, in Arabic
|
||||
and other connected scripts, HarfBuzz needs to know the code
|
||||
points before and after each character in order to correctly
|
||||
determine which glyph to return.
|
||||
</para>
|
||||
<para>
|
||||
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 (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
|
||||
<function>hb_buffer_add_codepoints()</function>. The arguments
|
||||
to this function are the same as those for the UTF
|
||||
encodings. But it is particularly important to note that
|
||||
HarfBuzz does not do validity checking on the text that is added
|
||||
to a buffer. Invalid code points will be replaced, but it is up
|
||||
to you to do any deep-sanity checking necessary.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="setting-buffer-properties">
|
||||
<title>Setting buffer properties</title>
|
||||
<para>
|
||||
Buffers containing input characters still need several
|
||||
properties set before HarfBuzz can shape their text correctly.
|
||||
</para>
|
||||
<para>
|
||||
Initially, all buffers are set to the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_INVALID</literal> content
|
||||
type. After adding text, the buffer should be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_UNICODE</literal> instead, which
|
||||
indicates that it contains un-shaped input
|
||||
characters. After shaping, the buffer will have the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal> content type.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_buffer_add_utf8()</function> and the
|
||||
other UTF functions set the content type of their buffer
|
||||
automatically. But if you are reusing a buffer you may want to
|
||||
check its state with
|
||||
<function>hb_buffer_get_content_type(buffer)</function>. If
|
||||
necessary you can set the content type with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
|
||||
</programlisting>
|
||||
<para>
|
||||
to prepare for shaping.
|
||||
</para>
|
||||
<para>
|
||||
Buffers also need to carry information about the script,
|
||||
language, and text direction of their contents. You can set
|
||||
these properties individually:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<para>
|
||||
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>
|
||||
<programlisting language="C">
|
||||
hb_segment_properties_t *savedprops;
|
||||
hb_buffer_get_segment_properties (buf, savedprops);
|
||||
...
|
||||
hb_buffer_set_segment_properties (buf2, savedprops);
|
||||
</programlisting>
|
||||
<para>
|
||||
HarfBuzz also provides getter functions to retrieve a buffer's
|
||||
direction, script, and language properties individually.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz recognizes four text directions in
|
||||
<type>hb_direction_t</type>: left-to-right
|
||||
(<literal>HB_DIRECTION_LTR</literal>), right-to-left (<literal>HB_DIRECTION_RTL</literal>),
|
||||
top-to-bottom (<literal>HB_DIRECTION_TTB</literal>), and
|
||||
bottom-to-top (<literal>HB_DIRECTION_BTT</literal>). For the
|
||||
script property, HarfBuzz uses identifiers based on the
|
||||
<ulink
|
||||
url="https://unicode.org/iso15924/">ISO 15924
|
||||
standard</ulink>. For languages, HarfBuzz uses tags based on the
|
||||
<ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
|
||||
</para>
|
||||
<para>
|
||||
Helper functions are provided to convert character strings into
|
||||
the necessary script and language tag types.
|
||||
</para>
|
||||
<para>
|
||||
Two additional buffer properties to be aware of are the
|
||||
"invisible glyph" and the replacement code point. The
|
||||
replacement code point is inserted into buffer output in place of
|
||||
any invalid code points encountered in the input. By default, it
|
||||
is the Unicode <literal>REPLACEMENT CHARACTER</literal> code
|
||||
point, <literal>U+FFFD</literal> "�". You can change this with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_replacement_codepoint(buf, replacement);
|
||||
</programlisting>
|
||||
<para>
|
||||
passing in the replacement Unicode code point as the
|
||||
<parameter>replacement</parameter> parameter.
|
||||
</para>
|
||||
<para>
|
||||
The invisible glyph is used to replace all output glyphs that
|
||||
are invisible. By default, the standard space character
|
||||
<literal>U+0020</literal> is used; you can replace this (for
|
||||
example, when using a font that provides script-specific
|
||||
spaces) with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_invisible_glyph(buf, replacement_glyph);
|
||||
</programlisting>
|
||||
<para>
|
||||
Do note that in the <parameter>replacement_glyph</parameter>
|
||||
parameter, you must provide the glyph ID of the replacement you
|
||||
wish to use, not the Unicode code point.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz supports a few additional flags you might want to set
|
||||
on your buffer under certain circumstances. The
|
||||
<literal>HB_BUFFER_FLAG_BOT</literal> and
|
||||
<literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
|
||||
that the buffer represents the beginning or end (respectively)
|
||||
of a text element (such as a paragraph or other block). Knowing
|
||||
this allows HarfBuzz to apply certain contextual font features
|
||||
when shaping, such as initial or final variants in connected
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
<literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
|
||||
tells HarfBuzz not to hide glyphs with the
|
||||
<literal>Default_Ignorable</literal> property in Unicode. This
|
||||
property designates control characters and other non-printing
|
||||
code points, such as joiners and variation selectors. Normally
|
||||
HarfBuzz replaces them in the output buffer with zero-width
|
||||
space glyphs (using the "invisible glyph" property discussed
|
||||
above); setting this flag causes them to be printed, which can
|
||||
be helpful for troubleshooting.
|
||||
</para>
|
||||
<para>
|
||||
Conversely, setting the
|
||||
<literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
|
||||
tells HarfBuzz to remove <literal>Default_Ignorable</literal>
|
||||
glyphs from the output buffer entirely. Finally, setting the
|
||||
<literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
|
||||
flag tells HarfBuzz not to insert the dotted-circle glyph
|
||||
(<literal>U+25CC</literal>, "◌"), which is normally
|
||||
inserted into buffer output when broken character sequences are
|
||||
encountered (such as combining marks that are not attached to a
|
||||
base character).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="what-about-the-other-scripts">
|
||||
<title>What about the other scripts?</title>
|
||||
<para>
|
||||
</para>
|
||||
</section>
|
||||
<section id="customizing-unicode-functions">
|
||||
<title>Customizing Unicode functions</title>
|
||||
<para>
|
||||
HarfBuzz requires some simple functions for accessing
|
||||
information from the Unicode Character Database (such as the
|
||||
<literal>General_Category</literal> (gc) and
|
||||
<literal>Script</literal> (sc) properties) that is useful
|
||||
for shaping, as well as some useful operations like composing and
|
||||
decomposing code points.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz includes its own internal, lightweight set of Unicode
|
||||
functions. At build time, it is also possible to compile support
|
||||
for some other options, such as the Unicode functions provided
|
||||
by GLib or the International Components for Unicode (ICU)
|
||||
library. Generally, this option is only of interest for client
|
||||
programs that have specific integration requirements or that do
|
||||
a significant amount of customization.
|
||||
</para>
|
||||
<para>
|
||||
If your program has access to other Unicode functions, however,
|
||||
such as through a system library or application framework, you
|
||||
might prefer to use those instead of the built-in
|
||||
options. HarfBuzz supports this by implementing its Unicode
|
||||
functions as a set of virtual methods that you can replace —
|
||||
without otherwise affecting HarfBuzz's functionality.
|
||||
</para>
|
||||
<para>
|
||||
The Unicode functions are specified in a structure called
|
||||
<literal>unicode_funcs</literal> which is attached to each
|
||||
buffer. But even though <literal>unicode_funcs</literal> is
|
||||
associated with a <type>hb_buffer_t</type>, the functions
|
||||
themselves are called by other HarfBuzz APIs that access
|
||||
buffers, so it would be unwise for you to hook different
|
||||
functions into different buffers.
|
||||
</para>
|
||||
<para>
|
||||
In addition, you can mark your <literal>unicode_funcs</literal>
|
||||
as immutable by calling
|
||||
<function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
|
||||
This is especially useful if your code is a
|
||||
library or framework that will have its own client programs. By
|
||||
marking your Unicode function choices as immutable, you prevent
|
||||
your own client programs from changing the
|
||||
<literal>unicode_funcs</literal> configuration and introducing
|
||||
inconsistencies and errors downstream.
|
||||
</para>
|
||||
<para>
|
||||
You can retrieve the Unicode-functions configuration for
|
||||
your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_t *ufunctions;
|
||||
ufunctions = hb_buffer_get_unicode_funcs(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
The current version of <literal>unicode_funcs</literal> uses six functions:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_combining_class_func_t</function>:
|
||||
returns the Canonical Combining Class of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_general_category_func_t</function>:
|
||||
returns the General Category (gc) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_mirroring_func_t</function>: returns
|
||||
the Mirroring Glyph code point (for bi-directional
|
||||
replacement) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_script_func_t</function>: returns the
|
||||
Script (sc) property of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_compose_func_t</function>: returns the
|
||||
canonical composition of a sequence of two code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_decompose_func_t</function>: returns
|
||||
the canonical decomposition of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Note, however, that future HarfBuzz releases may alter this set.
|
||||
</para>
|
||||
<para>
|
||||
Each Unicode function has a corresponding setter, with which you
|
||||
can assign a callback to your replacement function. For example,
|
||||
to replace
|
||||
<function>hb_unicode_general_category_func_t</function>, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)
|
||||
</programlisting>
|
||||
<para>
|
||||
Virtualizing this set of Unicode functions is primarily intended
|
||||
to improve portability. There is no need for every client
|
||||
program to make the effort to replace the default options, so if
|
||||
you are unsure, do not feel any pressure to customize
|
||||
<literal>unicode_funcs</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
</chapter>
|
|
@ -1,701 +1,304 @@
|
|||
<?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="clusters">
|
||||
<sect1 id="clusters">
|
||||
<title>Clusters</title>
|
||||
<section id="clusters-and-shaping">
|
||||
<title>Clusters and shaping</title>
|
||||
<para>
|
||||
In shaping text, a <emphasis>cluster</emphasis> is a sequence of
|
||||
code points that needs to be treated as a single, indivisible unit.
|
||||
</para>
|
||||
<para>
|
||||
When you add text to a HB buffer, each character is associated with
|
||||
a <emphasis>cluster value</emphasis>. This is an arbitrary number as
|
||||
far as HB is concerned.
|
||||
</para>
|
||||
<para>
|
||||
Most clients will use UTF-8, UTF-16, or UTF-32 indices, but the
|
||||
actual number does not matter. Moreover, it is not required for the
|
||||
cluster values to be monotonically increasing, but pretty much all
|
||||
of HB's tests are performed on monotonically increasing cluster
|
||||
numbers. Nevertheless, there is no such assumption in the code
|
||||
itself. With that in mind, let's examine what happens with cluster
|
||||
values during shaping under each cluster-level.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides three <emphasis>levels</emphasis> of clustering
|
||||
support. Level 0 is the default behavior and reproduces the behavior
|
||||
of the old HarfBuzz library. Level 1 tweaks this behavior slightly
|
||||
to produce better results, so level 1 clustering is recommended for
|
||||
code that is not required to implement backward compatibility with
|
||||
the old HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
Level 2 differs significantly in how it treats cluster values.
|
||||
Levels 0 and 1 both process ligatures and glyph decomposition by
|
||||
merging clusters; level 2 does not.
|
||||
</para>
|
||||
<para>
|
||||
The conceptual model for what the cluster values mean, in levels 0
|
||||
and 1, is this:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
the sequence of cluster values will always remain monotone
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
each value represents a single cluster
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
each cluster contains one or more glyphs and one or more
|
||||
characters
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Assuming that initial cluster numbers were monotonically increasing
|
||||
and distinct, then all adjacent glyphs having the same cluster
|
||||
number belong to the same cluster, and all characters belong to the
|
||||
cluster that has the highest number not larger than their initial
|
||||
cluster number. This will become clearer with an example.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="a-clustering-example-for-levels-0-and-1">
|
||||
<title>A clustering example for levels 0 and 1</title>
|
||||
<para>
|
||||
Let's say we start with the following character sequence and cluster
|
||||
values:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
We then map the characters to glyphs. For simplicity, let's assume
|
||||
that each character maps to the corresponding, identical-looking
|
||||
glyph:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now if, for example, <literal>B</literal> and <literal>C</literal>
|
||||
ligate, then the clusters to which they belong "merge".
|
||||
This merged cluster takes for its cluster number the minimum of all
|
||||
the cluster numbers of the clusters that went in. In this case, we
|
||||
get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC,D,E
|
||||
0,1 ,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now let's assume that the <literal>BC</literal> glyph decomposes
|
||||
into three components, and <literal>D</literal> also decomposes into
|
||||
two. The components each inherit the cluster value of their parent:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2,D0,D1,E
|
||||
0,1 ,1 ,1 ,3 ,3 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now if <literal>BC2</literal> and <literal>D0</literal> ligate, then
|
||||
their clusters (numbers 1 and 3) merge into
|
||||
<literal>min(1,3) = 1</literal>:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2D0,D1,E
|
||||
0,1 ,1 ,1 ,1 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
At this point, cluster 1 means: the character sequence
|
||||
<literal>BCD</literal> is represented by glyphs
|
||||
<literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
|
||||
further.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 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 when things
|
||||
reorder. In those cases, to maintain monotone clusters, HB merges
|
||||
the clusters of everything in the reordering sequence. For example,
|
||||
let's again start with the character sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
If <literal>D</literal> is reordered before <literal>B</literal>,
|
||||
then the <literal>B</literal>, <literal>C</literal>, and
|
||||
<literal>D</literal> clusters merge, and we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,1,1,1,4
|
||||
</programlisting>
|
||||
<para>
|
||||
This is clearly not ideal, but it is the only sensible way to
|
||||
maintain monotone indices and retain the true relationship between
|
||||
glyphs and characters.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="the-distinction-between-levels-0-and-1">
|
||||
<title>The distinction between levels 0 and 1</title>
|
||||
<para>
|
||||
So, the above is pretty much what cluster levels 0 and 1 do. The
|
||||
only difference between the two is this: in level 0, at the very
|
||||
beginning of the shaping process, we also merge clusters between
|
||||
base characters and all Unicode marks (combining or not) following
|
||||
them. E.g.:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,1 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
will become:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,0 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
This is the default behavior. We do it because Windows did it and
|
||||
old HarfBuzz did it, so this remained the default. But this behavior
|
||||
makes it impossible to color diacritic marks differently from their
|
||||
base characters. That's why in level 1 we do not perform this
|
||||
initial merging step.
|
||||
</para>
|
||||
<para>
|
||||
For clients, level 0 is more convenient if they rely on HarfBuzz
|
||||
clusters for cursor positioning. But that's wrong anyway: cursor
|
||||
positions should be determined based on Unicode grapheme boundaries,
|
||||
NOT shaping clusters. As such, level 1 clusters are preferred.
|
||||
</para>
|
||||
<para>
|
||||
One last note about levels 0 and 1. We currently don't allow a
|
||||
<literal>MultipleSubst</literal> lookup to replace a glyph with zero
|
||||
glyphs (i.e., to delete a glyph). But in some other situations,
|
||||
glyphs can be deleted. In those cases, if the glyph being deleted is
|
||||
the last glyph of its cluster, we make sure to merge the cluster
|
||||
with a neighboring cluster.
|
||||
</para>
|
||||
<para>
|
||||
This is, primarily, to make sure that the starting cluster of the
|
||||
text always has the cluster index pointing to the start of the text
|
||||
for the run; more than one client currently relies on this
|
||||
guarantee.
|
||||
</para>
|
||||
<para>
|
||||
Incidentally, Apple's CoreText does something else to maintain the
|
||||
same promise: it inserts a glyph with id 65535 at the beginning of
|
||||
the glyph string if the glyph corresponding to the first character
|
||||
in the run was deleted. HarfBuzz might do something similar in the
|
||||
future.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="level-2">
|
||||
<title>Level 2</title>
|
||||
<para>
|
||||
Level 2 is a different beast from levels 0 and 1. It is simple to
|
||||
describe, but hard to make sense of. It simply doesn't do any
|
||||
cluster merging whatsoever. When things ligate or otherwise multiple
|
||||
glyphs turn into one, the cluster value of the first glyph is
|
||||
retained.
|
||||
</para>
|
||||
<para>
|
||||
Here are a few examples of why processing cluster values produced at
|
||||
this level might be tricky:
|
||||
</para>
|
||||
<sect2 id="ligatures-with-combining-marks">
|
||||
<title>Ligatures with combining marks</title>
|
||||
<para>
|
||||
In text shaping, a <emphasis>cluster</emphasis> is a sequence of
|
||||
characters that needs to be treated as a single, indivisible
|
||||
unit. A single letter or symbol can be a cluster of its
|
||||
own. Other clusters correspond to longer subsequences of the
|
||||
input code points — such as a ligature or conjunct form
|
||||
— and require the shaper to ensure that the cluster is not
|
||||
broken during the shaping process.
|
||||
</para>
|
||||
<para>
|
||||
A cluster is distinct from a <emphasis>grapheme</emphasis>,
|
||||
which is the smallest unit of meaning in a writing system or
|
||||
script.
|
||||
</para>
|
||||
<para>
|
||||
The definitions of the two terms are similar. However, clusters
|
||||
are only relevant for script shaping and glyph layout. In
|
||||
contrast, graphemes are a property of the underlying script, and
|
||||
are of interest when client programs implement orthographic
|
||||
or linguistic functionality.
|
||||
</para>
|
||||
<para>
|
||||
For example, two individual letters are often two separate
|
||||
graphemes. When two letters form a ligature, however, they
|
||||
combine into a single glyph. They are then part of the same
|
||||
cluster and are treated as a unit by the shaping engine —
|
||||
even though the two original, underlying letters remain separate
|
||||
graphemes.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz is concerned with clusters, <emphasis>not</emphasis>
|
||||
with graphemes — although client programs using HarfBuzz
|
||||
may still care about graphemes for other reasons from time to time.
|
||||
</para>
|
||||
<para>
|
||||
During the shaping process, there are several shaping operations
|
||||
that may merge adjacent characters (for example, when two code
|
||||
points form a ligature or a conjunct form and are replaced by a
|
||||
single glyph) or split one character into several (for example,
|
||||
when decomposing a code point through the
|
||||
<literal>ccmp</literal> feature). Operations like these alter
|
||||
clusters; HarfBuzz tracks the changes to ensure that no clusters
|
||||
get lost or broken during shaping.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz records cluster information independently from how
|
||||
shaping operations affect the individual glyphs returned in an
|
||||
output buffer. Consequently, a client program using HarfBuzz can
|
||||
utilize the cluster information to implement features such as:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Correctly positioning the cursor within a shaped text run,
|
||||
even when characters have formed ligatures, composed or
|
||||
decomposed, reordered, or undergone other shaping operations.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Correctly highlighting a text selection that includes some,
|
||||
but not all, of the characters in a word.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Applying text attributes (such as color or underlining) to
|
||||
part, but not all, of a word.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Generating output document formats (such as PDF) with
|
||||
embedded text that can be fully extracted.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Determining the mapping between input characters and output
|
||||
glyphs, such as which glyphs are ligatures.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Performing line-breaking, justification, and other
|
||||
line-level or paragraph-level operations that must be done
|
||||
after shaping is complete, but which require examining
|
||||
character-level properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="working-with-harfbuzz-clusters">
|
||||
<title>Working with HarfBuzz clusters</title>
|
||||
<para>
|
||||
When you add text to a HarfBuzz buffer, each code point must be
|
||||
assigned a <emphasis>cluster value</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
This cluster value is an arbitrary number; HarfBuzz uses it only
|
||||
to distinguish between clusters. Many client programs will use
|
||||
the index of each code point in the input text stream as the
|
||||
cluster value. This is for the sake of convenience; the actual
|
||||
value does not matter.
|
||||
</para>
|
||||
<para>
|
||||
Some of the shaping operations performed by HarfBuzz —
|
||||
such as reordering, composition, decomposition, and substitution
|
||||
— may alter the cluster values of some characters. The
|
||||
final cluster values in the buffer at the end of the shaping
|
||||
process will indicate to client programs which subsequences of
|
||||
glyphs represent a cluster and, therefore, must not be
|
||||
separated.
|
||||
</para>
|
||||
<para>
|
||||
In addition, client programs can query the final cluster values
|
||||
to discern other potentially important information about the
|
||||
glyphs in the output buffer (such as whether or not a ligature
|
||||
was formed).
|
||||
</para>
|
||||
<para>
|
||||
For example, if the initial sequence of cluster values was:
|
||||
Imagine capital letters are bases and lower case letters are
|
||||
combining marks. With an input sequence like this:
|
||||
</para>
|
||||
<programlisting>
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
A,a,B,b,C,c
|
||||
0,1,2,3,4,5
|
||||
</programlisting>
|
||||
<para>
|
||||
and the final sequence of cluster values is:
|
||||
if <literal>A,B,C</literal> ligate, then here are the cluster
|
||||
values one would get under the various levels:
|
||||
</para>
|
||||
<para>
|
||||
level 0:
|
||||
</para>
|
||||
<programlisting>
|
||||
0,0,3,3
|
||||
</programlisting>
|
||||
ABC,a,b,c
|
||||
0 ,0,0,0
|
||||
</programlisting>
|
||||
<para>
|
||||
then there are two clusters in the output buffer: the first
|
||||
cluster includes the first two glyphs, and the second cluster
|
||||
includes the third and fourth glyphs. It is also evident that a
|
||||
ligature or conjunct has been formed, because there are fewer
|
||||
glyphs in the output buffer (four) than there were code points
|
||||
in the input buffer (five).
|
||||
</para>
|
||||
<para>
|
||||
Although client programs using HarfBuzz are free to assign
|
||||
initial cluster values in any manner they choose to, HarfBuzz
|
||||
does offer some useful guarantees if the cluster values are
|
||||
assigned in a monotonic (either non-decreasing or non-increasing)
|
||||
order.
|
||||
</para>
|
||||
<para>
|
||||
For buffers in the left-to-right (LTR)
|
||||
or top-to-bottom (TTB) text flow direction,
|
||||
HarfBuzz will preserve the monotonic property: client programs
|
||||
are guaranteed that monotonically increasing initial cluster
|
||||
values will be returned as monotonically increasing final
|
||||
cluster values.
|
||||
</para>
|
||||
<para>
|
||||
For buffers in the right-to-left (RTL)
|
||||
or bottom-to-top (BTT) text flow direction,
|
||||
the directionality of the buffer itself is reversed for final
|
||||
output as a matter of design. Therefore, HarfBuzz inverts the
|
||||
monotonic property: client programs are guaranteed that
|
||||
monotonically increasing initial cluster values will be
|
||||
returned as monotonically <emphasis>decreasing</emphasis> final
|
||||
cluster values.
|
||||
</para>
|
||||
<para>
|
||||
Client programs can adjust how HarfBuzz handles clusters during
|
||||
shaping by setting the
|
||||
<literal>cluster_level</literal> of the
|
||||
buffer. HarfBuzz offers three <emphasis>levels</emphasis> of
|
||||
clustering support for this property:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Level 0</emphasis> is the default.
|
||||
</para>
|
||||
<para>
|
||||
The distinguishing feature of level 0 behavior is that, at
|
||||
the beginning of processing the buffer, all code points that
|
||||
are categorized as <emphasis>marks</emphasis>,
|
||||
<emphasis>modifier symbols</emphasis>, or
|
||||
<emphasis>Emoji extended pictographic</emphasis> modifiers,
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
In essence, whenever a base character is followed by a mark
|
||||
character or a sequence of mark characters, those marks are
|
||||
reassigned to the same initial cluster value as the base
|
||||
character. This reassignment is referred to as
|
||||
"merging" the affected clusters. This behavior is based on
|
||||
the Grapheme Cluster Boundary specification in <ulink
|
||||
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
|
||||
<literal>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Level 1</emphasis> tweaks the old behavior
|
||||
slightly to produce better results. Therefore, level 1
|
||||
clustering is recommended for code that is not required to
|
||||
implement backward compatibility with the old HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
<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, coloring
|
||||
mark glyphs differently than their base).
|
||||
</para>
|
||||
<para>
|
||||
Client programs can specify level 1 behavior for a buffer by
|
||||
setting its <literal>cluster_level</literal> to
|
||||
<literal>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Level 2</emphasis> differs significantly in how it
|
||||
treats cluster values. In level 2, HarfBuzz never merges
|
||||
clusters.
|
||||
</para>
|
||||
<para>
|
||||
This difference can be seen most clearly when HarfBuzz processes
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Client programs can specify level 2 behavior for a buffer by
|
||||
setting its <literal>cluster_level</literal> to
|
||||
<literal>HB_BUFFER_CLUSTER_LEVEL_CHARACTERS</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As mentioned earlier, client programs using HarfBuzz often
|
||||
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).
|
||||
</para>
|
||||
<para>
|
||||
It is not <emphasis>required</emphasis> that the cluster values
|
||||
in a buffer be monotonically increasing. However, if the initial
|
||||
cluster values in a buffer are monotonic and the buffer is
|
||||
configured to use cluster level 0 or 1, then HarfBuzz
|
||||
guarantees that the final cluster values in the shaped buffer
|
||||
will also be monotonic. No such guarantee is made for cluster
|
||||
level 2.
|
||||
</para>
|
||||
<para>
|
||||
In levels 0 and 1, HarfBuzz implements the following conceptual
|
||||
model for cluster values:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
If the sequence of input cluster values is monotonic, the
|
||||
sequence of cluster values will remain monotonic.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Each cluster value represents a single cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Each cluster contains one or more glyphs and one or more
|
||||
characters.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
In practice, this model offers several benefits. Assuming that
|
||||
the initial cluster values were monotonically increasing
|
||||
and distinct before shaping began, then, in the final output:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
All adjacent glyphs having the same final cluster
|
||||
value belong to the same cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Each character belongs to the cluster that has the highest
|
||||
cluster value <emphasis>not larger than</emphasis> its
|
||||
initial cluster value.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="a-clustering-example-for-levels-0-and-1">
|
||||
<title>A clustering example for levels 0 and 1</title>
|
||||
<para>
|
||||
The basic shaping operations affect clusters in a predictable
|
||||
manner when using level 0 or level 1:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When two or more clusters <emphasis>merge</emphasis>, the
|
||||
resulting merged cluster takes as its cluster value the
|
||||
<emphasis>minimum</emphasis> of the incoming cluster values.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
When a cluster <emphasis>decomposes</emphasis>, all of the
|
||||
resulting child clusters inherit as their cluster value the
|
||||
cluster value of the parent cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
When a character is <emphasis>reordered</emphasis>, the
|
||||
reordered character and all clusters that the character
|
||||
moves past as part of the reordering are merged into one cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The functionality, guarantees, and benefits of level 0 and level
|
||||
1 behavior can be seen with some examples. First, let us examine
|
||||
what happens with cluster values when shaping involves cluster
|
||||
merging with ligatures and decomposition.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Let's say we start with the following character sequence (top row) and
|
||||
initial cluster values (bottom row):
|
||||
level 1:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
ABC,a,b,c
|
||||
0 ,0,0,5
|
||||
</programlisting>
|
||||
<para>
|
||||
During shaping, HarfBuzz maps these characters to glyphs from
|
||||
the font. For simplicity, let us assume that each character maps
|
||||
to the corresponding, identical-looking glyph:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now if, for example, <literal>B</literal> and <literal>C</literal>
|
||||
form a ligature, then the clusters to which they belong
|
||||
"merge". This merged cluster takes for its cluster
|
||||
value the minimum of all the cluster values of the clusters that
|
||||
went in to the ligature. In this case, we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC,D,E
|
||||
0,1 ,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
because 1 is the minimum of the set {1,2}, which were the
|
||||
cluster values of <literal>B</literal> and
|
||||
<literal>C</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Next, let us say that the <literal>BC</literal> ligature glyph
|
||||
decomposes into three components, and <literal>D</literal> also
|
||||
decomposes into two components. Whenever a cluster decomposes,
|
||||
its components each inherit the cluster value of their parent:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2,D0,D1,E
|
||||
0,1 ,1 ,1 ,3 ,3 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Next, if <literal>BC2</literal> and <literal>D0</literal> form a
|
||||
ligature, then their clusters (cluster values 1 and 3) merge into
|
||||
<literal>min(1,3) = 1</literal>:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2D0,D1,E
|
||||
0,1 ,1 ,1 ,1 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Note that the entirety of cluster 3 merges into cluster 1, not
|
||||
just the <literal>D0</literal> glyph. This reflects the fact
|
||||
that the cluster <emphasis>must</emphasis> be treated as an
|
||||
indivisible unit.
|
||||
</para>
|
||||
<para>
|
||||
At this point, cluster 1 means: the character sequence
|
||||
<literal>BCD</literal> is represented by glyphs
|
||||
<literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
|
||||
further.
|
||||
</para>
|
||||
</section>
|
||||
<section id="reordering-in-levels-0-and-1">
|
||||
<title>Reordering in levels 0 and 1</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
For example, let us again start with the character sequence (top
|
||||
row) and initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
If <literal>D</literal> is reordered to the position immediately
|
||||
before <literal>B</literal>, then HarfBuzz merges the
|
||||
<literal>B</literal>, <literal>C</literal>, and
|
||||
<literal>D</literal> clusters — all the clusters between
|
||||
the final position of the reordered glyph and its original
|
||||
position. This means that we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,1,1,1,4
|
||||
</programlisting>
|
||||
<para>
|
||||
as the final cluster sequence.
|
||||
</para>
|
||||
<para>
|
||||
Merging this many clusters is not ideal, but it is the only
|
||||
sensible way for HarfBuzz to maintain the guarantee that the
|
||||
sequence of cluster values remains monotonic and to retain the
|
||||
true relationship between glyphs and characters.
|
||||
</para>
|
||||
</section>
|
||||
<section id="the-distinction-between-levels-0-and-1">
|
||||
<title>The distinction between levels 0 and 1</title>
|
||||
<para>
|
||||
The preceding examples demonstrate the main effects of using
|
||||
cluster levels 0 and 1. The only difference between the two
|
||||
levels is this: in level 0, at the very beginning of the shaping
|
||||
process, HarfBuzz merges the cluster of each base character
|
||||
with the clusters of all Unicode marks (combining or not) and
|
||||
modifiers that follow it.
|
||||
</para>
|
||||
<para>
|
||||
For example, let us start with the following character sequence
|
||||
(top row) and accompanying initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,1 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
The <literal>acute</literal> is a Unicode mark. If HarfBuzz is
|
||||
using cluster level 0 on this sequence, then the
|
||||
<literal>A</literal> and <literal>acute</literal> clusters will
|
||||
merge, and the result will become:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,0 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
This merger is performed before any other script-shaping
|
||||
steps.
|
||||
</para>
|
||||
<para>
|
||||
This initial cluster merging is the default behavior of the
|
||||
Windows shaping engine, and the old HarfBuzz codebase copied
|
||||
that behavior to maintain compatibility. Consequently, it has
|
||||
remained the default behavior in the new HarfBuzz codebase.
|
||||
</para>
|
||||
<para>
|
||||
But this initial cluster-merging behavior makes it impossible
|
||||
for client programs to implement some features (such as to
|
||||
color diacritic marks differently from their base
|
||||
characters). That is why, in level 1, HarfBuzz does not perform
|
||||
the initial merging step.
|
||||
</para>
|
||||
<para>
|
||||
For client programs that rely on HarfBuzz cluster values to
|
||||
perform cursor positioning, level 0 is more convenient. But
|
||||
relying on cluster boundaries for cursor positioning is wrong: cursor
|
||||
positions should be determined based on Unicode grapheme
|
||||
boundaries, not on shaping-cluster boundaries. As such, using
|
||||
level 1 clustering behavior is recommended.
|
||||
</para>
|
||||
<para>
|
||||
One final facet of levels 0 and 1 is worth noting. HarfBuzz
|
||||
currently does not allow any
|
||||
<emphasis>multiple-substitution</emphasis> GSUB lookups to
|
||||
replace a glyph with zero glyphs (in other words, to delete a
|
||||
glyph).
|
||||
</para>
|
||||
<para>
|
||||
But, in some other situations, glyphs can be deleted. In
|
||||
those cases, if the glyph being deleted is the last glyph of its
|
||||
cluster, HarfBuzz makes sure to merge the deleted glyph's
|
||||
cluster with a neighboring cluster.
|
||||
</para>
|
||||
<para>
|
||||
This is done primarily to make sure that the starting cluster of the
|
||||
text always has the cluster index pointing to the start of the text
|
||||
for the run; more than one client program currently relies on this
|
||||
guarantee.
|
||||
</para>
|
||||
<para>
|
||||
Incidentally, Apple's CoreText does something different to
|
||||
maintain the same promise: it inserts a glyph with id 65535 at
|
||||
the beginning of the glyph string if the glyph corresponding to
|
||||
the first character in the run was deleted. HarfBuzz might do
|
||||
something similar in the future.
|
||||
</para>
|
||||
</section>
|
||||
<section id="level-2">
|
||||
<title>Level 2</title>
|
||||
<para>
|
||||
HarfBuzz's level 2 cluster behavior uses a significantly
|
||||
different model than that of level 0 and level 1.
|
||||
</para>
|
||||
<para>
|
||||
The level 2 behavior is easy to describe, but it may be
|
||||
difficult to understand in practical terms. In brief, level 2
|
||||
performs no merging of clusters whatsoever.
|
||||
</para>
|
||||
<para>
|
||||
This means that there is no initial base-and-mark merging step
|
||||
(as is done in level 0), and it means that reordering moves and
|
||||
ligature substitutions do not trigger a cluster merge.
|
||||
</para>
|
||||
<para>
|
||||
Only one shaping operation directly affects clusters when using
|
||||
level 2:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When a cluster <emphasis>decomposes</emphasis>, all of the
|
||||
resulting child clusters inherit as their cluster value the
|
||||
cluster value of the parent cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<programlisting>
|
||||
ABC,a,b,c
|
||||
0 ,1,3,5
|
||||
</programlisting>
|
||||
<para>
|
||||
When glyphs do form a ligature (or when some other feature
|
||||
substitutes multiple glyphs with one glyph) the cluster value
|
||||
of the first glyph is retained as the cluster value for the
|
||||
resulting ligature.
|
||||
Making sense of the last example is the hardest for a client,
|
||||
because there is nothing in the cluster values to suggest that
|
||||
<literal>B</literal> and <literal>C</literal> ligated with
|
||||
<literal>A</literal>.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="reordering">
|
||||
<title>Reordering</title>
|
||||
<para>
|
||||
Another tricky case is when things reorder. Under level 2:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now imagine <literal>D</literal> moves before
|
||||
<literal>B</literal>:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,3,1,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now, if <literal>D</literal> ligates with <literal>B</literal>, we
|
||||
get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,DB,C,E
|
||||
0,3 ,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
In a different scenario, <literal>A</literal> and
|
||||
<literal>B</literal> could have ligated
|
||||
<emphasis>before</emphasis> <literal>D</literal> reordered; that
|
||||
would have resulted in:
|
||||
</para>
|
||||
<programlisting>
|
||||
AB,D,C,E
|
||||
0 ,3,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
There's no way to differentiate between these two scenarios based
|
||||
on the cluster numbers alone.
|
||||
</para>
|
||||
<para>
|
||||
This occurrence sounds similar to a cluster merge, but it is
|
||||
different. In particular, no subsequent characters —
|
||||
including marks and modifiers — are affected. They retain
|
||||
their previous cluster values.
|
||||
Another problem happens with ligatures under level 2 if the
|
||||
direction of the text is forced to opposite of its natural
|
||||
direction (e.g. left-to-right Arabic). But that's too much of a
|
||||
corner case to worry about.
|
||||
</para>
|
||||
<para>
|
||||
Level 2 cluster behavior is ultimately less complex than level 0
|
||||
or level 1, but there are several cases for which processing
|
||||
cluster values produced at level 2 may be tricky.
|
||||
</para>
|
||||
<section id="ligatures-with-combining-marks-in-level-2">
|
||||
<title>Ligatures with combining marks in level 2</title>
|
||||
<para>
|
||||
The first example of how HarfBuzz's level 2 cluster behavior
|
||||
can be tricky is when the text to be shaped includes combining
|
||||
marks attached to ligatures.
|
||||
</para>
|
||||
<para>
|
||||
Let us start with an input sequence with the following
|
||||
characters (top row) and initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B,breve,C,circumflex
|
||||
0,1 ,2,3 ,4,5
|
||||
</programlisting>
|
||||
<para>
|
||||
If the sequence <literal>A,B,C</literal> forms a ligature,
|
||||
then these are the cluster values HarfBuzz will return under
|
||||
the various cluster levels:
|
||||
</para>
|
||||
<para>
|
||||
Level 0:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC,acute,breve,circumflex
|
||||
0 ,0 ,0 ,0
|
||||
</programlisting>
|
||||
<para>
|
||||
Level 1:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC,acute,breve,circumflex
|
||||
0 ,0 ,0 ,5
|
||||
</programlisting>
|
||||
<para>
|
||||
Level 2:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC,acute,breve,circumflex
|
||||
0 ,1 ,3 ,5
|
||||
</programlisting>
|
||||
<para>
|
||||
Making sense of the level 2 result is the hardest for a client
|
||||
program, because there is nothing in the cluster values that
|
||||
indicates that <literal>B</literal> and <literal>C</literal>
|
||||
formed a ligature with <literal>A</literal>.
|
||||
</para>
|
||||
<para>
|
||||
In contrast, the "merged" cluster values of the mark glyphs
|
||||
that are seen in the level 0 and level 1 output are evidence
|
||||
that a ligature substitution took place.
|
||||
</para>
|
||||
</section>
|
||||
<section id="reordering-in-level-2">
|
||||
<title>Reordering in level 2</title>
|
||||
<para>
|
||||
Another example of how HarfBuzz's level 2 cluster behavior
|
||||
can be tricky is when glyphs reorder. Consider an input sequence
|
||||
with the following characters (top row) and initial cluster
|
||||
values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now imagine <literal>D</literal> moves before
|
||||
<literal>B</literal> in a reordering operation. The cluster
|
||||
values will then be:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,3,1,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Next, if <literal>D</literal> forms a ligature with
|
||||
<literal>B</literal>, the output is:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,DB,C,E
|
||||
0,3 ,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
However, in a different scenario, in which the shaping rules
|
||||
of the script instead caused <literal>A</literal> and
|
||||
<literal>B</literal> to form a ligature
|
||||
<emphasis>before</emphasis> the <literal>D</literal> reordered, the
|
||||
result would be:
|
||||
</para>
|
||||
<programlisting>
|
||||
AB,D,C,E
|
||||
0 ,3,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
There is no way for a client program to differentiate between
|
||||
these two scenarios based on the cluster values
|
||||
alone. Consequently, client programs that use level 2 might
|
||||
need to undertake additional work in order to manage cursor
|
||||
positioning, text attributes, or other desired features.
|
||||
</para>
|
||||
</section>
|
||||
<section id="other-considerations-in-level-2">
|
||||
<title>Other considerations in level 2</title>
|
||||
<para>
|
||||
There may be other problems encountered with ligatures under
|
||||
level 2, such as if the direction of the text is forced to
|
||||
the opposite of its natural direction (for example, Arabic text
|
||||
that is forced into left-to-right directionality). But,
|
||||
generally speaking, these other scenarios are minor corner
|
||||
cases that are too obscure for most client programs to need to
|
||||
worry about.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
|
|
@ -1,518 +1,18 @@
|
|||
<?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="fonts-and-faces">
|
||||
<title>Fonts, faces, and output</title>
|
||||
<title>Fonts and faces</title>
|
||||
<section id="using-freetype">
|
||||
<title>Using FreeType</title>
|
||||
<para>
|
||||
In the previous chapter, we saw how to set up a buffer and fill
|
||||
it with text as Unicode code points. In order to shape this
|
||||
buffer text with HarfBuzz, you will need also need a font
|
||||
object.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides abstractions to help you cache and reuse the
|
||||
heavier parts of working with binary fonts, so we will look at
|
||||
how to do that. We will also look at how to work with the
|
||||
FreeType font-rendering library and at how you can customize
|
||||
HarfBuzz to work with other libraries.
|
||||
</para>
|
||||
<para>
|
||||
Finally, we will look at how to work with OpenType variable
|
||||
fonts, the latest update to the OpenType font format, and at
|
||||
some other recent additions to OpenType.
|
||||
</para>
|
||||
|
||||
<section id="fonts-and-faces-objects">
|
||||
<title>Font and face objects</title>
|
||||
<para>
|
||||
The outcome of shaping a run of text depends on the contents of
|
||||
a specific font file (such as the substitutions and positioning
|
||||
moves in the 'GSUB' and 'GPOS' tables), so HarfBuzz makes
|
||||
accessing those internals fast.
|
||||
</para>
|
||||
<para>
|
||||
An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
|
||||
in HarfBuzz. This data type is a wrapper around an
|
||||
<type>hb_blob_t</type> blob that holds the contents of a binary
|
||||
font file. Since HarfBuzz supports TrueType Collections and
|
||||
OpenType Collections (each of which can include multiple
|
||||
typefaces), a HarfBuzz face also requires an index number
|
||||
specifying which typeface in the file you want to use. Most of
|
||||
the font files you will encounter in the wild include just a
|
||||
single face, however, so most of the time you would pass in
|
||||
<literal>0</literal> as the index when you create a face:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_t* blob = hb_blob_create_from_file(file);
|
||||
...
|
||||
hb_face_t* face = hb_face_create(blob, 0);
|
||||
</programlisting>
|
||||
<para>
|
||||
On its own, a face object is not quite ready to use for
|
||||
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 more variation-axis settings (or a
|
||||
named instance) in order to get the output you need.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, you do this by creating a <emphasis>font</emphasis>
|
||||
object from your face.
|
||||
</para>
|
||||
<para>
|
||||
Font objects also have the advantage of being considerably
|
||||
lighter-weight than face objects (remember that a face contains
|
||||
the contents of a binary font file mapped into memory). As a
|
||||
result, you can cache and reuse a font object, but you could
|
||||
also create a new one for each additional size you needed.
|
||||
Creating new fonts incurs some additional overhead, of course,
|
||||
but whether or not it is excessive is your call in the end. In
|
||||
contrast, face objects are substantially larger, and you really
|
||||
should cache them and reuse them whenever possible.
|
||||
</para>
|
||||
<para>
|
||||
You can create a font object from a face object:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_t* hb_font = hb_font_create(hb_face);
|
||||
</programlisting>
|
||||
<para>
|
||||
After creating a font, there are a few properties you should
|
||||
set. Many fonts enable and disable hints based on the size it
|
||||
is used at, so setting this is important for font
|
||||
objects. <function>hb_font_set_ppem(font, x_ppem,
|
||||
y_ppem)</function> sets the pixels-per-EM value of the font. You
|
||||
can also set the point size of the font with
|
||||
<function>hb_font_set_ptem(font, ptem)</function>. HarfBuzz uses the
|
||||
industry standard 72 points per inch.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz lets you specify the degree subpixel precision you want
|
||||
through a scaling factor. You can set horizontal and
|
||||
vertical scaling factors on the
|
||||
font by calling <function>hb_font_set_scale(font, x_scale,
|
||||
y_scale)</function>.
|
||||
</para>
|
||||
<para>
|
||||
There may be times when you are handed a font object and need to
|
||||
access the face object that it comes from. For that, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_face = hb_font_get_face(hb_font);
|
||||
</programlisting>
|
||||
<para>
|
||||
You can also create a font object from an existing font object
|
||||
using the <function>hb_font_create_sub_font()</function>
|
||||
function. This creates a child font object that is initiated
|
||||
with the same attributes as its parent; it can be used to
|
||||
quickly set up a new font for the purpose of overriding a specific
|
||||
font-functions method.
|
||||
</para>
|
||||
<para>
|
||||
All face objects and font objects are lifecycle-managed by
|
||||
HarfBuzz. After creating a face, you increase its reference
|
||||
count with <function>hb_face_reference(face)</function> and
|
||||
decrease it with
|
||||
<function>hb_face_destroy(face)</function>. Likewise, you
|
||||
increase the reference count on a font with
|
||||
<function>hb_font_reference(font)</function> and decrease it
|
||||
with <function>hb_font_destroy(font)</function>.
|
||||
</para>
|
||||
<para>
|
||||
You can also attach user data to face objects and font objects.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="fonts-and-faces-custom-functions">
|
||||
<title>Customizing font functions</title>
|
||||
<section id="using-harfbuzzs-native-opentype-implementation">
|
||||
<title>Using HarfBuzz's native OpenType implementation</title>
|
||||
<para>
|
||||
During shaping, HarfBuzz frequently needs to query font objects
|
||||
to get at the contents and parameters of the glyphs in a font
|
||||
file. It includes a built-in set of functions that is tailored
|
||||
to working with OpenType fonts. However, as was the case with
|
||||
Unicode functions in the buffers chapter, HarfBuzz also wants to
|
||||
make it easy for you to assign a substitute set of font
|
||||
functions if you are developing a program to work with a library
|
||||
or platform that provides its own font functions.
|
||||
</para>
|
||||
<para>
|
||||
Therefore, the HarfBuzz API defines a set of virtual
|
||||
methods for accessing font-object properties, and you can
|
||||
replace the defaults with your own selections without
|
||||
interfering with the shaping process. Each font object in
|
||||
HarfBuzz includes a structure called
|
||||
<literal>font_funcs</literal> that serves as a vtable for the
|
||||
font object. The virtual methods in
|
||||
<literal>font_funcs</literal> are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_font_h_extents_func_t</function>: returns
|
||||
the extents of the font for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_font_v_extents_func_t</function>: returns
|
||||
the extents of the font for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_nominal_glyph_func_t</function>: returns
|
||||
the font's nominal glyph for a given code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_variation_glyph_func_t</function>: returns
|
||||
the font's glyph for a given code point when it is followed by a
|
||||
given Variation Selector.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_nominal_glyphs_func_t</function>: returns
|
||||
the font's nominal glyphs for a series of code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_advance_func_t</function>: returns
|
||||
the advance for a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_advance_func_t</function>: returns
|
||||
the advance for a glyph for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_advance_func_t</function>:returns
|
||||
the advance for a glyph for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs for horizontal text .
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_extents_func_t</function>: returns
|
||||
the extents for a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_contour_point_func_t</function>:
|
||||
returns the coordinates of a specific contour point from a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_name_func_t</function>: returns the
|
||||
name of a glyph (from its glyph index).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<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 create new font-functions by calling
|
||||
<function>hb_font_funcs_create()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
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 set with their own setter
|
||||
function, such as
|
||||
<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
|
||||
objects, and can be reference counted with
|
||||
<function>hb_font_funcs_reference()</function> and
|
||||
<function>hb_font_funcs_destroy()</function>. Just like other
|
||||
objects in HarfBuzz, you can set user-data for each
|
||||
font-functions structure and assign a destroy callback for
|
||||
it.
|
||||
</para>
|
||||
<para>
|
||||
You can also mark a font-functions structure as immutable,
|
||||
with <function>hb_font_funcs_make_immutable()</function>. This
|
||||
is especially useful if your code is a library or framework that
|
||||
will have its own client programs. By marking your
|
||||
font-functions structures as immutable, you prevent your client
|
||||
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">
|
||||
<title>Font objects and HarfBuzz's native OpenType implementation</title>
|
||||
<para>
|
||||
By default, whenever HarfBuzz creates a font object, it will
|
||||
configure the font to use a built-in set of font functions that
|
||||
supports contemporary OpenType font internals. If you want to
|
||||
work with OpenType or TrueType fonts, you should be able to use
|
||||
these functions without difficulty.
|
||||
</para>
|
||||
<para>
|
||||
Many of the methods in the font-functions structure deal with
|
||||
the fundamental properties of glyphs that are required for
|
||||
shaping text: extents (the maximums and minimums on each axis),
|
||||
origins (the <literal>(0,0)</literal> coordinate point which
|
||||
glyphs are drawn in reference to), and advances (the amount that
|
||||
the cursor needs to be moved after drawing each glyph, including
|
||||
any empty space for the glyph's side bearings).
|
||||
</para>
|
||||
<para>
|
||||
As you can see in the list of functions, there are separate "horizontal"
|
||||
and "vertical" variants depending on whether the text is set in
|
||||
the horizontal or vertical direction. For some scripts, fonts
|
||||
that are designed to support text set horizontally or vertically (for
|
||||
example, in Japanese) may include metrics for both text
|
||||
directions. When fonts don't include this information, HarfBuzz
|
||||
does its best to transform what the font provides.
|
||||
</para>
|
||||
<para>
|
||||
In addition to the direction-specific functions, HarfBuzz
|
||||
provides some higher-level functions for fetching information
|
||||
like extents and advances for a glyph. If you call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_get_glyph_advance_for_direction(font, direction, extents);
|
||||
</programlisting>
|
||||
<para>
|
||||
then you can provide any <type>hb_direction_t</type> as the
|
||||
<parameter>direction</parameter> parameter, and HarfBuzz will
|
||||
use the correct function variant for the text direction. There
|
||||
are similar higher-level versions of the functions for fetching
|
||||
extents, origin coordinates, and contour-point
|
||||
coordinates. There are also addition and subtraction functions
|
||||
for moving points with respect to the origin.
|
||||
</para>
|
||||
<para>
|
||||
There are also methods for fetching the glyph ID that
|
||||
corresponds to a Unicode code point (possibly when followed by a
|
||||
variation-selector code point), fetching the glyph name from the
|
||||
font, and fetching the glyph ID that corresponds to a glyph name
|
||||
you already have.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides functions for converting between glyph
|
||||
names and string
|
||||
variables. <function>hb_font_glyph_to_string(font, glyph, s,
|
||||
size)</function> retrieves the name for the glyph ID
|
||||
<parameter>glyph</parameter> from the font object. It generates a
|
||||
generic name of the form <literal>gidDDD</literal> (where DDD is
|
||||
the glyph index) if there is no name for the glyph in the
|
||||
font. The <function>hb_font_glyph_from_string(font, s, len,
|
||||
glyph)</function> takes an input string <parameter>s</parameter>
|
||||
and looks for a glyph with that name in the font, returning its
|
||||
glyph ID in the <parameter>glyph</parameter>
|
||||
output parameter. It automatically parses
|
||||
<literal>gidDDD</literal> and <literal>uniUUUU</literal> strings.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="fonts-and-faces-variable">
|
||||
<title>Working with OpenType Variable Fonts</title>
|
||||
<section id="using-your-own-font-functions">
|
||||
<title>Using your own font functions</title>
|
||||
<para>
|
||||
If you are working with OpenType Variable Fonts, there are a few
|
||||
additional functions you should use to specify the
|
||||
variation-axis settings of your font object. Without doing so,
|
||||
your variable font's font object can still be used, but only at
|
||||
the default setting for every axis (which, of course, is
|
||||
sometimes what you want, but does not cover general usage).
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages variation settings in the
|
||||
<type>hb_variation_t</type> data type, which holds a <property>tag</property> for the
|
||||
variation-axis identifier tag and a <property>value</property> for its
|
||||
setting. You can retrieve the list of variation axes in a font
|
||||
binary from the face object (not from a font object, notably) by
|
||||
calling <function>hb_ot_var_get_axis_count(face)</function> to
|
||||
find the number of axes, then using
|
||||
<function>hb_ot_var_get_axis_infos()</function> to collect the
|
||||
axis structures:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
axes = hb_ot_var_get_axis_count(face);
|
||||
...
|
||||
hb_ot_var_get_axis_infos(face, 0, axes, axes_array);
|
||||
</programlisting>
|
||||
<para>
|
||||
For each axis returned in the array, you can can access the
|
||||
identifier in its <property>tag</property>. HarfBuzz also has
|
||||
tag definitions predefined for the five standard axes specified
|
||||
in OpenType (<literal>ital</literal> for italic,
|
||||
<literal>opsz</literal> for optical size,
|
||||
<literal>slnt</literal> for slant, <literal>wdth</literal> for
|
||||
width, and <literal>wght</literal> for weight). Each axis also
|
||||
has a <property>min_value</property>, a
|
||||
<property>default_value</property>, and a <property>max_value</property>.
|
||||
</para>
|
||||
<para>
|
||||
To set your font object's variation settings, you call the
|
||||
<function>hb_font_set_variations()</function> function with an
|
||||
array of <type>hb_variation_t</type> variation settings. Let's
|
||||
say our font has weight and width axes. We need to specify each
|
||||
of the axes by tag and assign a value on the axis:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
unsigned int variation_count = 2;
|
||||
hb_variation_t variation_data[variation_count];
|
||||
variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WIDTH;
|
||||
variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
|
||||
variation_data[0].value = 80;
|
||||
variation_data[1].value = 750;
|
||||
...
|
||||
hb_font_set_variations(font, variation_data, variation_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
That should give us a slightly condensed font ("normal" on the
|
||||
<literal>wdth</literal> axis is 100) at a noticeably bolder
|
||||
weight ("regular" is 400 on the <literal>wght</literal> axis).
|
||||
</para>
|
||||
<para>
|
||||
In practice, though, you should always check that the value you
|
||||
want to set on the axis is within the
|
||||
[<property>min_value</property>,<property>max_value</property>]
|
||||
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.
|
||||
</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>
|
||||
</chapter>
|
|
@ -1,312 +0,0 @@
|
|||
<?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="getting-started">
|
||||
<title>Getting started with HarfBuzz</title>
|
||||
<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
|
||||
<function>hb_shape()</function>. This function takes a font, a
|
||||
buffer containing a string of Unicode codepoints and
|
||||
(optionally) a list of font features as its input. It replaces
|
||||
the codepoints in the buffer with the corresponding glyphs from
|
||||
the font, correctly ordered and positioned, and with any of the
|
||||
optional font features applied.
|
||||
</para>
|
||||
<para>
|
||||
In addition to holding the pre-shaping input (the Unicode
|
||||
codepoints that comprise the input string) and the post-shaping
|
||||
output (the glyphs and positions), a HarfBuzz buffer has several
|
||||
properties that affect shaping. The most important are the
|
||||
text-flow direction (e.g., left-to-right, right-to-left,
|
||||
top-to-bottom, or bottom-to-top), the script tag, and the
|
||||
language tag.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For input string buffers, flags are available to denote when the
|
||||
buffer represents the beginning or end of a paragraph, to
|
||||
indicate whether or not to visibly render Unicode <literal>Default
|
||||
Ignorable</literal> codepoints, and to modify the cluster-merging
|
||||
behavior for the buffer. For shaped output buffers, the
|
||||
individual X and Y offsets and <literal>advances</literal>
|
||||
(the logical dimensions) of each glyph are
|
||||
accessible. HarfBuzz also flags glyphs as
|
||||
<literal>UNSAFE_TO_BREAK</literal> if breaking the string at
|
||||
that glyph (e.g., in a line-breaking or hyphenation process)
|
||||
would require re-shaping the text.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz also provides methods to compare the contents of
|
||||
buffers, join buffers, normalize buffer contents, and handle
|
||||
invalid codepoints, as well as to determine the state of a
|
||||
buffer (e.g., input codepoints or output glyphs). Buffer
|
||||
lifecycles are managed and all buffers are reference-counted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Although the default <function>hb_shape()</function> function is
|
||||
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>
|
||||
|
||||
<para>
|
||||
HarfBuzz can read TrueType fonts, TrueType collections, OpenType
|
||||
fonts, and OpenType collections. Functions are provided to query
|
||||
font objects about metrics, Unicode coverage, available tables and
|
||||
features, and variation selectors. Individual glyphs can also be
|
||||
queried for metrics, variations, and glyph names. OpenType
|
||||
variable fonts are supported, and HarfBuzz allows you to set
|
||||
variation-axis coordinates on font objects.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz provides glue code to integrate with various other
|
||||
libraries, including FreeType, GObject, and CoreText. Support
|
||||
for integrating with Uniscribe and DirectWrite is experimental
|
||||
at present.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="terminology">
|
||||
<title>Terminology</title>
|
||||
<para>
|
||||
|
||||
</para>
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term>script</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In text shaping, a <emphasis>script</emphasis> is a
|
||||
writing system: a set of symbols, rules, and conventions
|
||||
that is used to represent a language or multiple
|
||||
languages.
|
||||
</para>
|
||||
<para>
|
||||
In general computing lingo, the word "script" can also
|
||||
be used to mean an executable program (usually one
|
||||
written in a human-readable programming language). For
|
||||
the sake of clarity, HarfBuzz documents will always use
|
||||
more specific terminology when referring to this
|
||||
meaning, such as "Python script" or "shell script." In
|
||||
all other instances, "script" refers to a writing system.
|
||||
</para>
|
||||
<para>
|
||||
For developers using HarfBuzz, it is important to note
|
||||
the distinction between a script and a language. Most
|
||||
scripts are used to write a variety of different
|
||||
languages, and many languages may be written in more
|
||||
than one script.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>shaper</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In HarfBuzz, a <emphasis>shaper</emphasis> is a
|
||||
handler for a specific script-shaping model. HarfBuzz
|
||||
implements separate shapers for Indic, Arabic, Thai and
|
||||
Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
|
||||
Universal Shaping Engine (USE), and a default shaper for
|
||||
scripts with no script-specific shaping model.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>cluster</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In text shaping, a <emphasis>cluster</emphasis> is a
|
||||
sequence of codepoints that must be treated as an
|
||||
indivisible unit. Clusters can include code-point
|
||||
sequences that form a ligature or base-and-mark
|
||||
sequences. Tracking and preserving clusters is important
|
||||
when shaping operations might separate or reorder
|
||||
code points.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides three cluster
|
||||
<emphasis>levels</emphasis> that implement different
|
||||
approaches to the problem of preserving clusters during
|
||||
shaping operations.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>grapheme</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In linguistics, a <emphasis>grapheme</emphasis> is one
|
||||
of the indivisible units that make up a writing system or
|
||||
script. Often, graphemes are individual symbols (letters,
|
||||
numbers, punctuation marks, logograms, etc.) but,
|
||||
depending on the writing system, a particular grapheme
|
||||
might correspond to a sequence of several Unicode code
|
||||
points.
|
||||
</para>
|
||||
<para>
|
||||
In practice, HarfBuzz and other text-shaping engines
|
||||
are not generally concerned with graphemes. However, it
|
||||
is important for developers using HarfBuzz to recognize
|
||||
that there is a difference between graphemes and shaping
|
||||
clusters (see above). The two concepts may overlap
|
||||
frequently, but there is no guarantee that they will be
|
||||
identical.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>syllable</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In linguistics, a <emphasis>syllable</emphasis> is an
|
||||
a sequence of sounds that makes up a building block of a
|
||||
particular language. Every language has its own set of
|
||||
rules describing what constitutes a valid syllable.
|
||||
</para>
|
||||
<para>
|
||||
For text-shaping purposes, the various definitions of
|
||||
"syllable" are important because script-specific shaping
|
||||
operations may be applied at the syllable level. For
|
||||
example, a reordering rule might specify that a vowel
|
||||
mark be reordered to the beginning of the syllable.
|
||||
</para>
|
||||
<para>
|
||||
Syllables will consist of one or more Unicode code
|
||||
points. The definition of a syllable for a particular
|
||||
writing system might correspond to how HarfBuzz
|
||||
identifies clusters (see above) for the same writing
|
||||
system. However, it is important for developers using
|
||||
HarfBuzz to recognize that there is a difference between
|
||||
syllables and shaping clusters. The two concepts may
|
||||
overlap frequently, but there is no guarantee that they
|
||||
will be identical.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section id="a-simple-shaping-example">
|
||||
<title>A simple shaping example</title>
|
||||
|
||||
<para>
|
||||
Below is the simplest HarfBuzz shaping example possible.
|
||||
</para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para>
|
||||
Create a buffer and put your text in it.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb.h>
|
||||
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, -1, 0, -1);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Set the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font from a font file.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
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">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
unsigned int glyph_count;
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_position_t cursor_x = 0;
|
||||
hb_position_t cursor_y = 0;
|
||||
for (unsigned int i = 0; i < 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;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(font);
|
||||
hb_face_destroy(face);
|
||||
hb_blob_destroy(blob);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
This example shows enough to get us started using HarfBuzz. In
|
||||
the sections that follow, we will use the remainder of
|
||||
HarfBuzz's API to refine and extend the example and improve its
|
||||
text-shaping capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -1,9 +1,3 @@
|
|||
<?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">
|
||||
]>
|
||||
<sect1 id="glyph-information">
|
||||
<title>Glyph information</title>
|
||||
<sect2 id="names-and-numbers">
|
||||
|
@ -11,4 +5,4 @@
|
|||
<para>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
</sect1>
|
|
@ -0,0 +1,183 @@
|
|||
<chapter id="hello-harfbuzz">
|
||||
<title>Hello, HarfBuzz</title>
|
||||
<para>
|
||||
Here's the simplest HarfBuzz that can possibly work. We will improve
|
||||
it later.
|
||||
</para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para>
|
||||
Create a buffer and put your text in it.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb.h>
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Guess the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_guess_segment_properties(buf);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font, using FreeType for now.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb-ft.h>
|
||||
FT_New_Face(ft_library, font_path, index, &face)
|
||||
hb_font_t *font = hb_ft_font_create(face);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="4">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
for (i = 0; i < 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);
|
||||
cursor_x += x_advance;
|
||||
cursor_y += y_advance;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(hb_ft_font);
|
||||
</programlisting>
|
||||
<section id="what-harfbuzz-doesnt-do">
|
||||
<title>What HarfBuzz doesn't do</title>
|
||||
<para>
|
||||
The code above will take a UTF8 string, shape it, and give you the
|
||||
information required to lay it out correctly on a single
|
||||
horizontal (or vertical) line using the font provided. That is the
|
||||
extent of HarfBuzz's responsibility.
|
||||
</para>
|
||||
<para>
|
||||
If you are implementing a text layout engine you may have other
|
||||
responsibilities, that HarfBuzz will not help you with:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with bidirectionality. If you want to
|
||||
lay out text with mixed Hebrew and English, you will need to
|
||||
ensure that the buffer provided to HarfBuzz has those
|
||||
characters in the correct layout order. This will be different
|
||||
from the logical order in which the Unicode text is stored. In
|
||||
other words, the user will hit the keys in the following
|
||||
sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A B C [space] ג ב א [space] D E F
|
||||
</programlisting>
|
||||
<para>
|
||||
but will expect to see in the output:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC אבג DEF
|
||||
</programlisting>
|
||||
<para>
|
||||
This reordering is called <emphasis>bidi processing</emphasis>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to reorder a string from logical order into presentation order.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as ICU and fribidi can do
|
||||
this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
Similarly if you change font, font size, script, language or
|
||||
direction within your string, you will need to shape each run
|
||||
independently and then output them independently. HarfBuzz
|
||||
expects to shape a run of characters sharing the same
|
||||
properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation or
|
||||
justification. As mentioned above, it lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line. If you
|
||||
want to layout text in paragraphs, you will probably want to send
|
||||
each word of your text to HarfBuzz to determine its shaped width
|
||||
after glyph substitutions, then work out how many words will fit
|
||||
on a line, and then finally output each word of the line separated
|
||||
by a space of the correct size to fully justify the paragraph.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need - what you then do with the glyphs that your font
|
||||
returns is up to you. The example we saw above enough to get us
|
||||
started using HarfBuzz. Now we are going to use the remainder of
|
||||
HarfBuzz's API to refine that example and improve our text shaping
|
||||
capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -1,349 +1,70 @@
|
|||
<?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="install-harfbuzz">
|
||||
<title>Installing HarfBuzz</title>
|
||||
|
||||
<title>Install HarfBuzz</title>
|
||||
<section id="download">
|
||||
<title id="download.title">Downloading HarfBuzz</title>
|
||||
<title id="download.title">Download</title>
|
||||
<para>
|
||||
The HarfBuzz source code is hosted at <ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
|
||||
For tarball releases of HarfBuzz, look
|
||||
<ulink url="http://www.freedesktop.org/software/harfbuzz/release/">here</ulink>.
|
||||
At the same place you will
|
||||
also find Win32 binary bundles that include libharfbuzz DLL, hb-view.exe,
|
||||
hb-shape.exe, and all dependencies.
|
||||
</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/releases">github.com/harfbuzz/harfbuzz/releases</ulink>.
|
||||
The canonical source tree is available
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
|
||||
Also available on <ulink url="https://github.com/harfbuzz/harfbuzz">github</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 <ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz/discussions">GitHub</ulink> as well.
|
||||
The API that comes with <filename class='headerfile'>hb.h</filename> will
|
||||
not change incompatibly. Other, peripheral, headers are more likely to go
|
||||
through minor modifications, but again, will do our best to never change
|
||||
API in an incompatible way. We will never break the ABI.
|
||||
</para>
|
||||
<para>
|
||||
The API included in the <filename
|
||||
class='headerfile'>hb.h</filename> file will not change in a
|
||||
compatibility-breaking way in any release. However, other,
|
||||
peripheral headers are more likely to go through minor
|
||||
modifications. We will do our best to never change APIs in an
|
||||
incompatible way. We will <emphasis>never</emphasis> break the ABI.
|
||||
If you are not sure whether Pango or HarfBuzz is right for you, read
|
||||
<ulink url="http://mces.blogspot.in/2009/11/pango-vs-harfbuzz.html">this</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="building">
|
||||
<title>Building HarfBuzz</title>
|
||||
|
||||
<section id="building.linux">
|
||||
<title>Building on Linux</title>
|
||||
<title>Building</title>
|
||||
<para>
|
||||
<emphasis>(1)</emphasis> To build HarfBuzz on Linux, you must first install the
|
||||
development packages for FreeType, Cairo, and GLib. The exact
|
||||
commands required for this step will vary depending on
|
||||
the Linux distribution you use.
|
||||
On Linux, install the development packages for FreeType, Cairo, and GLib.
|
||||
For example, on Ubuntu / Debian, you would do:
|
||||
<programlisting>
|
||||
<command>sudo apt-get install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package>
|
||||
</programlisting>
|
||||
whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
|
||||
<programlisting>
|
||||
<command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package>
|
||||
</programlisting>
|
||||
or using MacPorts:
|
||||
<programlisting>
|
||||
<command>sudo port install</command> <package>freetype glib2 cairo</package>
|
||||
</programlisting>
|
||||
</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>
|
||||
On Fedora, RHEL, CentOS, or other Red-Hat–based systems, you would run:
|
||||
<programlisting><command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package></programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>(2)</emphasis> The next step depends on whether you
|
||||
are building from the source in a downloaded release tarball or
|
||||
from the source directly from the git repository.
|
||||
If you are using a tarball, you can now proceed to running
|
||||
<command>configure</command> and <command>make</command> as with any
|
||||
other standard package. That should leave you with a shared library in
|
||||
<filename>src/</filename>, and a few utility programs including hb-view
|
||||
and hb-shape under <filename>util/</filename>.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(a)</emphasis> If you downloaded the HarfBuzz
|
||||
source code in a tarball, you can now extract the source.
|
||||
If you are bootstrapping from git, you need a few more tools before you
|
||||
can run <filename>autogen.sh</filename> for the first time. Namely,
|
||||
pkg-config and <ulink url="http://www.complang.org/ragel/">ragel</ulink>.
|
||||
Again, on Ubuntu / Debian:
|
||||
<programlisting>
|
||||
<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
|
||||
</programlisting>
|
||||
and on Fedora, RHEL, CentOS:
|
||||
<programlisting>
|
||||
<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
or using MacPorts:
|
||||
<programlisting>
|
||||
<command>sudo port install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
From a shell in the top-level directory of the extracted source
|
||||
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
|
||||
library in the <filename>src/</filename> directory, and a few
|
||||
utility programs including <command>hb-view</command> and
|
||||
<command>hb-shape</command> under the <filename>util/</filename>
|
||||
directory.
|
||||
</para>
|
||||
<para>
|
||||
<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>.
|
||||
</para>
|
||||
<para>
|
||||
On Ubuntu or Debian, run:
|
||||
<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>meson pkgconfig gtk-doc</package></programlisting>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
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>
|
||||
|
||||
|
||||
<section id="building.windows">
|
||||
<title>Building on Windows</title>
|
||||
|
||||
<para>
|
||||
<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>
|
||||
|
||||
|
||||
<section id="building.macos">
|
||||
<title>Building on macOS</title>
|
||||
|
||||
<para>
|
||||
There are two ways to build HarfBuzz on Mac systems: MacPorts
|
||||
and Homebrew. The process is similar to the process used on a
|
||||
Linux system.
|
||||
</para>
|
||||
<para>
|
||||
<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>
|
||||
</para>
|
||||
<para>
|
||||
If you are using Homebrew, you should run:
|
||||
<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
|
||||
source in a downloaded release tarball or from the source directly
|
||||
from the git repository.
|
||||
</para>
|
||||
<para>
|
||||
<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>meson build</command></programlisting>
|
||||
followed by:
|
||||
<programlisting><command>meson compile -C build</command></programlisting>
|
||||
to build HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(b)</emphasis> Alternatively, if you are building
|
||||
HarfBuzz from the source in the HarfBuzz git repository, then
|
||||
you must install several built-time dependencies before
|
||||
proceeding.
|
||||
</para>
|
||||
<para>If you are
|
||||
using MacPorts, you should run:
|
||||
<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>meson pkgconfig gtk-doc</package></programlisting>
|
||||
Finally, you can run:
|
||||
<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>meson build</command></programlisting>
|
||||
followed by:
|
||||
<programlisting><command>meson compile -C build</command></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
This should leave you with a shared
|
||||
library in the <filename>src/</filename> directory, and a few
|
||||
utility programs including <command>hb-view</command> and
|
||||
<command>hb-shape</command> under the <filename>util/</filename>
|
||||
directory.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="configuration">
|
||||
<title>Configuration options</title>
|
||||
|
||||
<para>
|
||||
The instructions in the "Building HarfBuzz" section will build
|
||||
the source code under its default configuration. If needed,
|
||||
the following additional configuration options are available.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term><command>-Dglib=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GLib
|
||||
library. The default setting is to check for the
|
||||
presence of GLib and, if it is found, build with
|
||||
GLib support. GLib is native to GNU/Linux systems but is
|
||||
available on other operating system as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dgobject=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/gobject/stable/">GObject</ulink>. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GObject
|
||||
library. The default setting is to check for the
|
||||
presence of GObject and, if it is found, build with
|
||||
GObject support. GObject is native to GNU/Linux systems but is
|
||||
available on other operating system as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dcairo=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://cairographics.org/">Cairo</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Cairo
|
||||
graphics-rendering library. The default setting is to
|
||||
check for the presence of Cairo and, if it is found,
|
||||
build with Cairo support.
|
||||
</para>
|
||||
<para>
|
||||
Note: Cairo is used only by the HarfBuzz
|
||||
command-line utilities, and not by the HarfBuzz library.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<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>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the
|
||||
<emphasis>International Components for
|
||||
Unicode</emphasis> (ICU) library, which provides access
|
||||
to Unicode Character Database (UCD) properties as well
|
||||
as normalization and conversion functions. The default
|
||||
setting is to check for the presence of ICU and, if it
|
||||
is found, build with ICU support.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dgraphite=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Graphite2
|
||||
library, which provides support for the Graphite shaping
|
||||
model.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dfreetype=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the FreeType
|
||||
font-rendering library. The default setting is to check for the
|
||||
presence of FreeType and, if it is found, build with
|
||||
FreeType support.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dgdi=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
|
||||
library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Uniscribe
|
||||
font-rendering library. Uniscribe is available on
|
||||
Windows systems. Uniscribe support is used only for
|
||||
testing purposes and does not need to be enabled for
|
||||
HarfBuzz to run on Windows systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<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>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the DirectWrite
|
||||
font-rendering library. DirectWrite is available on
|
||||
Windows systems. DirectWrite support is used only for
|
||||
testing purposes and does not need to be enabled for
|
||||
HarfBuzz to run on Windows systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<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>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the CoreText
|
||||
library. CoreText is available on macOS and iOS systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Ddocs=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
|
|
|
@ -1,647 +0,0 @@
|
|||
<?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
|
||||
— 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 <hb-glib.h>
|
||||
...
|
||||
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 <hb-ft.h>
|
||||
...
|
||||
FT_New_Face(ft_library, font_path, index, &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 — 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 — even to the point of
|
||||
duplicating known shaping bugs or deviations from the
|
||||
specification — 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> — a handle to the underlying logical
|
||||
font — 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>
|
|
@ -1,266 +0,0 @@
|
|||
<?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="object-model">
|
||||
<title>The HarfBuzz object model</title>
|
||||
<section id="object-model-intro">
|
||||
<title>An overview of data types in HarfBuzz</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
|
||||
types include integer types, enums, and small structs. Exposing
|
||||
a struct in the public API makes it impossible to expand the
|
||||
struct in the future. As such, exposing structs is reserved for
|
||||
cases where it’s extremely inefficient to do otherwise.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
|
||||
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
|
||||
category and are non-opaque.
|
||||
</para>
|
||||
<para>
|
||||
For all non-opaque structs where future extensibility may be
|
||||
necessary, reserved members are included to hold space for
|
||||
possible future members. As such, it’s 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.
|
||||
</para>
|
||||
<para>
|
||||
Important value types provided by HarfBuzz include the structs
|
||||
for working with Unicode code points, glyphs, and tags for font
|
||||
tables and features, as well as the enums for many Unicode and
|
||||
OpenType properties.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="object-model-object-types">
|
||||
<title>Objects in HarfBuzz</title>
|
||||
<para>
|
||||
<emphasis>Object types:</emphasis> Opaque struct types are used
|
||||
for what HarfBuzz loosely calls "objects." This doesn’t have
|
||||
much to do with the terminology from object-oriented programming
|
||||
(OOP), although some of the concepts are similar.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, all object types provide certain
|
||||
lifecycle-management APIs. Objects are reference-counted, and
|
||||
constructed with various <function>create()</function> methods, referenced via
|
||||
<function>reference()</function> and dereferenced using
|
||||
<function>destroy()</function>.
|
||||
</para>
|
||||
<para>
|
||||
For example,
|
||||
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.
|
||||
</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>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
|
||||
data. Blobs are typically used to hold the contents of a
|
||||
binary font file.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>faces</emphasis>, which represent typefaces from a
|
||||
font file, but without specific parameters (such as size) set.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>fonts</emphasis>, which represent instances of a
|
||||
face with all of their parameters specified.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>buffers</emphasis>, which hold Unicode code points
|
||||
for characters (before shaping) and the shaped glyph output
|
||||
(after shaping).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>shape plans</emphasis>, which store the settings
|
||||
that HarfBuzz will use when shaping a particular text
|
||||
segment. Shape plans are not generally used by client
|
||||
programs directly, but as we will see in a later chapter,
|
||||
they are still valuable to understand.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-lifecycle">
|
||||
<title>Object lifecycle management</title>
|
||||
<para>
|
||||
Each object type in HarfBuzz provides a
|
||||
<function>create()</function> method. Some object types provide
|
||||
additional variants of <function>create()</function> to handle
|
||||
special cases or to speed up common tasks; those variants are
|
||||
documented in the API reference. For example,
|
||||
<function>hb_blob_create_from_file()</function> constructs a new
|
||||
blob directly from the contents of a file.
|
||||
</para>
|
||||
<para>
|
||||
All objects are created with an initial reference count of
|
||||
<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
|
||||
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
|
||||
the object and free all of the associated memory.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
<function>destroy()</function> the <literal>NULL</literal>
|
||||
value.
|
||||
</para>
|
||||
<para>
|
||||
Some objects are thread-safe after they have been constructed
|
||||
and set up. The general pattern is to
|
||||
<function>create()</function> the object, make a few
|
||||
<function>set_*()</function> calls to set up the
|
||||
object, and then use it without further modification.
|
||||
</para>
|
||||
<para>
|
||||
To ensure that such an object is not modified, client programs
|
||||
can explicitly mark an object as immutable. HarfBuzz provides
|
||||
<function>make_immutable()</function> methods to mark an object
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Note also that there are no "make mutable" methods. If client
|
||||
programs need to alter an object previously marked as immutable,
|
||||
they will need to make a duplicate of the original.
|
||||
</para>
|
||||
<para>
|
||||
Finally, object constructors (and, indeed, as much of the
|
||||
shaping API as possible) will never return
|
||||
<literal>NULL</literal>. Instead, if there is an allocation
|
||||
error, each constructor will return an “empty” object
|
||||
singleton.
|
||||
</para>
|
||||
<para>
|
||||
These empty-object singletons are inert and safe (although
|
||||
typically useless) to pass around. This design choice avoids
|
||||
having to check for <literal>NULL</literal> pointers all
|
||||
throughout the code.
|
||||
</para>
|
||||
<para>
|
||||
In addition, this “empty” object singleton can also be accessed
|
||||
using the <function>get_empty()</function> method of the object
|
||||
type in question.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="object-model-user-data">
|
||||
<title>User data</title>
|
||||
<para>
|
||||
To better integrate with client programs, HarfBuzz's objects
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
Each object type has a <function>set_user_data()</function>
|
||||
method and a <function>get_user_data()</function> method. The
|
||||
<function>set_user_data()</function> methods take a client-provided
|
||||
<literal>key</literal> and a pointer,
|
||||
<literal>user_data</literal>, pointing to the data itself. Once
|
||||
the key-data pair has been attached to the object, the
|
||||
<function>get_user_data()</function> method can be called with
|
||||
the key, returning the <function>user_data</function> pointer.
|
||||
</para>
|
||||
<para>
|
||||
The <function>set_user_data()</function> methods also support an
|
||||
optional <function>destroy</function> callback. Client programs
|
||||
can set the <function>destroy</function> callback and receive
|
||||
notification from HarfBuzz whenever the object is destructed.
|
||||
</para>
|
||||
<para>
|
||||
Finally, each <function>set_user_data()</function> method allows
|
||||
the client program to set a <literal>replace</literal> Boolean
|
||||
indicating whether or not the function call should replace any
|
||||
existing <literal>user_data</literal>
|
||||
associated with the specified key.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-blobs">
|
||||
<title>Blobs</title>
|
||||
<para>
|
||||
While most of HarfBuzz's object types are specific to the
|
||||
shaping process, <emphasis>blobs</emphasis> are somewhat
|
||||
different.
|
||||
</para>
|
||||
<para>
|
||||
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 HarfBuzz's
|
||||
reference-counting and <function>destroy</function>
|
||||
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, 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.
|
||||
</para>
|
||||
<para>
|
||||
Most of the time, blobs are read-only, facilitating their use in
|
||||
immutable objects.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
|
@ -1,336 +1,13 @@
|
|||
<?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="shaping-and-shape-plans">
|
||||
<title>Shaping and shape plans</title>
|
||||
<para>
|
||||
Once you have your face and font objects configured as desired and
|
||||
your input buffer is filled with the characters you need to shape,
|
||||
all you need to do is call <function>hb_shape()</function>.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz will return the shaped version of the text in the same
|
||||
buffer that you provided, but it will be in output mode. At that
|
||||
point, you can iterate through the glyphs in the buffer, drawing
|
||||
each one at the specified position or handing them off to the
|
||||
appropriate graphics library.
|
||||
</para>
|
||||
<para>
|
||||
For the most part, HarfBuzz's shaping step is straightforward from
|
||||
the outside. But that doesn't mean there will never be cases where
|
||||
you want to look under the hood and see what is happening on the
|
||||
inside. HarfBuzz provides facilities for doing that, too.
|
||||
</para>
|
||||
|
||||
<section id="shaping-buffer-output">
|
||||
<title>Shaping and buffer output</title>
|
||||
<para>
|
||||
The <function>hb_shape()</function> function call takes four arguments: the font
|
||||
object to use, the buffer of characters to shape, an array of
|
||||
user-specified features to apply, and the length of that feature
|
||||
array. The feature array can be NULL, so for the sake of
|
||||
simplicity we will start with that case.
|
||||
</para>
|
||||
<para>
|
||||
Internally, HarfBuzz looks at the tables of the font file to
|
||||
determine where glyph classes, substitutions, and positioning
|
||||
are defined, using that information to decide which
|
||||
<emphasis>shaper</emphasis> to use (<literal>ot</literal> for
|
||||
OpenType fonts, <literal>aat</literal> for Apple Advanced
|
||||
Typography fonts, and so on). It also looks at the direction,
|
||||
script, and language properties of the segment to figure out
|
||||
which script-specific shaping model is needed (at least, in
|
||||
shapers that support multiple options).
|
||||
</para>
|
||||
<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 <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
|
||||
<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 <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
|
||||
GPOS tables to all be applied. HarfBuzz implements the
|
||||
script-specific shaping models in internal functions, rather
|
||||
than in the public API.
|
||||
</para>
|
||||
<para>
|
||||
The algorithms
|
||||
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, 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>
|
||||
<para>
|
||||
In general, though, all that you need to know is that
|
||||
<function>hb_shape()</function> returns the results of shaping
|
||||
in the same buffer that you provided. The buffer's content type
|
||||
will now be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
|
||||
that it contains shaped output, rather than input text. You can
|
||||
now extract the glyph information and positioning arrays:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
The glyph information array holds a <type>hb_glyph_info_t</type>
|
||||
for each output glyph, which has two fields:
|
||||
<parameter>codepoint</parameter> and
|
||||
<parameter>cluster</parameter>. Whereas, in the input buffer,
|
||||
the <parameter>codepoint</parameter> field contained the Unicode
|
||||
code point, it now contains the glyph ID of the corresponding
|
||||
glyph in the font. The <parameter>cluster</parameter> field is
|
||||
an integer that you can use to help identify when shaping has
|
||||
reordered, split, or combined code points; we will say more
|
||||
about that in the next chapter.
|
||||
</para>
|
||||
<para>
|
||||
The glyph positions array holds a corresponding
|
||||
<type>hb_glyph_position_t</type> for each output glyph,
|
||||
containing four fields: <parameter>x_advance</parameter>,
|
||||
<parameter>y_advance</parameter>,
|
||||
<parameter>x_offset</parameter>, and
|
||||
<parameter>y_offset</parameter>. The advances tell you how far
|
||||
you need to move the drawing point after drawing this glyph,
|
||||
depending on whether you are setting horizontal text (in which
|
||||
case you will have x advances) or vertical text (for which you
|
||||
will have y advances). The x and y offsets tell you where to
|
||||
move to start drawing the glyph; usually you will have both and
|
||||
x and a y offset, regardless of the text direction.
|
||||
</para>
|
||||
<para>
|
||||
Most of the time, you will rely on a font-rendering library or
|
||||
other graphics library to do the actual drawing of glyphs, so
|
||||
you will need to iterate through the glyphs in the buffer and
|
||||
pass the corresponding values off.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-opentype-features">
|
||||
<section id="opentype-features">
|
||||
<title>OpenType features</title>
|
||||
<para>
|
||||
OpenType features enable fonts to include smart behavior,
|
||||
implemented as "lookup" rules stored in the GSUB and GPOS
|
||||
tables. The OpenType specification defines a long list of
|
||||
standard features that fonts can use for these behaviors; each
|
||||
feature has a four-character reserved name and a well-defined
|
||||
semantic meaning.
|
||||
</para>
|
||||
<para>
|
||||
Some OpenType features are defined for the purpose of supporting
|
||||
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>
|
||||
<para>
|
||||
Other features are more generic and can apply to several (or
|
||||
any) script, and shaping engines are expected to implement
|
||||
them. By default, HarfBuzz activates several of these features
|
||||
on every text run. They include <literal>abvm</literal>,
|
||||
<literal>blwm</literal>, <literal>ccmp</literal>,
|
||||
<literal>locl</literal>, <literal>mark</literal>,
|
||||
<literal>mkmk</literal>, and <literal>rlig</literal>.
|
||||
</para>
|
||||
<para>
|
||||
In addition, if the text direction is horizontal, HarfBuzz
|
||||
also applies the <literal>calt</literal>,
|
||||
<literal>clig</literal>, <literal>curs</literal>,
|
||||
<literal>dist</literal>, <literal>kern</literal>,
|
||||
<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.
|
||||
</para>
|
||||
<para>
|
||||
Still other features are designed to be purely optional and left
|
||||
up to the application or the end user to enable or disable as desired.
|
||||
</para>
|
||||
<para>
|
||||
You can adjust the set of features that HarfBuzz applies to a
|
||||
buffer by supplying an array of <type>hb_feature_t</type>
|
||||
features as the third argument to
|
||||
<function>hb_shape()</function>. For a simple case, let's just
|
||||
enable the <literal>dlig</literal> feature, which turns on any
|
||||
"discretionary" ligatures in the font:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_feature_t userfeatures[1];
|
||||
userfeatures[0].tag = HB_TAG('d','l','i','g');
|
||||
userfeatures[0].value = 1;
|
||||
userfeatures[0].start = HB_FEATURE_GLOBAL_START;
|
||||
userfeatures[0].end = HB_FEATURE_GLOBAL_END;
|
||||
</programlisting>
|
||||
<para>
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> and
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> are macros we can use
|
||||
to indicate that the features will be applied to the entire
|
||||
buffer. We could also have used a literal <literal>0</literal>
|
||||
for the start and a <literal>-1</literal> to indicate the end of
|
||||
the buffer (or have selected other start and end positions, if needed).
|
||||
</para>
|
||||
<para>
|
||||
When we pass the <varname>userfeatures</varname> array to
|
||||
<function>hb_shape()</function>, any discretionary ligature
|
||||
substitutions from our font that match the text in our buffer
|
||||
will get performed:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_shape(font, buf, userfeatures, num_features);
|
||||
</programlisting>
|
||||
<para>
|
||||
Just like we enabled the <literal>dlig</literal> feature by
|
||||
setting its <parameter>value</parameter> to
|
||||
<literal>1</literal>, you would disable a feature by setting its
|
||||
<parameter>value</parameter> to <literal>0</literal>. Some
|
||||
features can take other <parameter>value</parameter> settings;
|
||||
be sure you read the full specification of each feature tag to
|
||||
understand what it does and how to control it.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-shaper-selection">
|
||||
<title>Shaper selection</title>
|
||||
<para>
|
||||
The basic version of <function>hb_shape()</function> determines
|
||||
its shaping strategy based on examining the capabilities of the
|
||||
font file. OpenType font tables cause HarfBuzz to try the
|
||||
<literal>ot</literal> shaper, while AAT font tables cause HarfBuzz to try the
|
||||
<literal>aat</literal> shaper.
|
||||
</para>
|
||||
<para>
|
||||
In the real world, however, a font might include some unusual
|
||||
mix of tables, or one of the tables might simply be broken for
|
||||
the script you need to shape. So, sometimes, you might not
|
||||
want to rely on HarfBuzz's process for deciding what to do, and
|
||||
just tell <function>hb_shape()</function> what you want it to try.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_shape_full()</function> is an alternate shaping
|
||||
function that lets you supply a list of shapers for HarfBuzz to
|
||||
try, in order, when shaping your buffer. For example, if you
|
||||
have determined that HarfBuzz's attempts to work around broken
|
||||
tables gives you better results than the AAT shaper itself does,
|
||||
you might move the AAT shaper to the end of your list of
|
||||
preferences and call <function>hb_shape_full()</function>
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
char *shaperprefs[3] = {"ot", "default", "aat"};
|
||||
...
|
||||
hb_shape_full(font, buf, userfeatures, num_features, shaperprefs);
|
||||
</programlisting>
|
||||
<para>
|
||||
to get results you are happier with.
|
||||
</para>
|
||||
<para>
|
||||
You may also want to call
|
||||
<function>hb_shape_list_shapers()</function> to get a list of
|
||||
the shapers that were built at compile time in your copy of HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-plans-and-caching">
|
||||
<section id="plans-and-caching">
|
||||
<title>Plans and caching</title>
|
||||
<para>
|
||||
Internally, HarfBuzz uses a structure called a shape plan to
|
||||
track its decisions about how to shape the contents of a
|
||||
buffer. The <function>hb_shape()</function> function builds up the shape plan by
|
||||
examining segment properties and by inspecting the contents of
|
||||
the font.
|
||||
</para>
|
||||
<para>
|
||||
This process can involve some decision-making and
|
||||
trade-offs — for example, HarfBuzz inspects the GSUB and GPOS
|
||||
lookups for the script and language tags set on the segment
|
||||
properties, but it falls back on the lookups under the
|
||||
<literal>DFLT</literal> tag (and sometimes other common tags)
|
||||
if there are actually no lookups for the tag requested.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also includes some work-arounds for
|
||||
handling well-known older font conventions that do not follow
|
||||
OpenType or Unicode specifications, for buggy system fonts, and for
|
||||
peculiarities of Microsoft Uniscribe. All of that means that a
|
||||
shape plan, while not something that you should edit directly in
|
||||
client code, still might be an object that you want to
|
||||
inspect. Furthermore, if resources are tight, you might want to
|
||||
cache the shape plan that HarfBuzz builds for your buffer and
|
||||
font, so that you do not have to rebuild it for every shaping call.
|
||||
</para>
|
||||
<para>
|
||||
You can create a cacheable shape plan with
|
||||
<function>hb_shape_plan_create_cached(face, props,
|
||||
user_features, num_user_features, shaper_list)</function>, where
|
||||
<parameter>face</parameter> is a face object (not a font object,
|
||||
notably), <parameter>props</parameter> is an
|
||||
<type>hb_segment_properties_t</type>,
|
||||
<parameter>user_features</parameter> is an array of
|
||||
<type>hb_feature_t</type>s (with length
|
||||
<parameter>num_user_features</parameter>), and
|
||||
<parameter>shaper_list</parameter> is a list of shapers to try.
|
||||
</para>
|
||||
<para>
|
||||
Shape plans are objects in HarfBuzz, so there are
|
||||
reference-counting functions and user-data attachment functions
|
||||
you can
|
||||
use. <function>hb_shape_plan_reference(shape_plan)</function>
|
||||
increases the reference count on a shape plan, while
|
||||
<function>hb_shape_plan_destroy(shape_plan)</function> decreases
|
||||
the reference count, destroying the shape plan when the last
|
||||
reference is dropped.
|
||||
</para>
|
||||
<para>
|
||||
You can attach user data to a shaper (with a key) using the
|
||||
<function>hb_shape_plan_set_user_data(shape_plan,key,data,destroy,replace)</function>
|
||||
function, optionally supplying a <function>destroy</function>
|
||||
callback to use. You can then fetch the user data attached to a
|
||||
shape plan with
|
||||
<function>hb_shape_plan_get_user_data(shape_plan, key)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
</chapter>
|
|
@ -1,368 +0,0 @@
|
|||
<?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="shaping-concepts">
|
||||
<title>Shaping concepts</title>
|
||||
<section id="text-shaping-concepts">
|
||||
<title>Text shaping</title>
|
||||
<para>
|
||||
Text shaping is the process of transforming a sequence of Unicode
|
||||
codepoints that represent individual characters (letters,
|
||||
diacritics, tone marks, numbers, symbols, etc.) into the
|
||||
orthographically and linguistically correct two-dimensional layout
|
||||
of glyph shapes taken from a specified font.
|
||||
</para>
|
||||
<para>
|
||||
For some writing systems (or <emphasis>scripts</emphasis>) and
|
||||
languages, the process is simple, requiring the shaper to do
|
||||
little more than advance the horizontal position forward by the
|
||||
correct amount for each successive glyph.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The exact rules and necessary operations for a particular script
|
||||
constitute a shaping <emphasis>model</emphasis>. OpenType
|
||||
specifies a set of shaping models that covers all of
|
||||
Unicode. Other shaping models are available, however, including
|
||||
Graphite and Apple Advanced Typography (AAT).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="script-specific-shaping">
|
||||
<title>Script-specific shaping</title>
|
||||
<para>
|
||||
In many scripts, transforming the input
|
||||
sequence into the final layout often requires some combination of
|
||||
operations—such as context-dependent substitutions,
|
||||
context-dependent mark positioning, glyph-to-glyph joining,
|
||||
glyph reordering, or glyph stacking.
|
||||
</para>
|
||||
<para>
|
||||
In some scripts, the shaping rules require that a text
|
||||
run be divided into syllables before the operations can be
|
||||
applied. Other scripts may apply shaping operations over
|
||||
entire words or over the entire text run, with no subdivision
|
||||
required.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-operations">
|
||||
<title>Shaping operations</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
The specific conditions that trigger a given operation for a
|
||||
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 script shaping models.
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
A <emphasis>reordering</emphasis> operation moves a glyph
|
||||
from its original ("logical") position in the sequence to
|
||||
some other ("visual") position.
|
||||
</para>
|
||||
<para>
|
||||
The shaping model for a given script might involve
|
||||
more than one reordering step.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A <emphasis>joining</emphasis> operation replaces a glyph
|
||||
with an alternate form that is designed to connect with one
|
||||
or more of the adjacent glyphs in the sequence.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A contextual <emphasis>substitution</emphasis> operation
|
||||
replaces either a single glyph or a subsequence of several
|
||||
glyphs with an alternate glyph. This substitution is
|
||||
performed when the original glyph or subsequence of glyphs
|
||||
occurs in a specified position with respect to the
|
||||
surrounding sequence. For example, one substitution might be
|
||||
performed only when the target glyph is the first glyph in
|
||||
the sequence, while another substitution is performed only
|
||||
when a different target glyph occurs immediately after a
|
||||
particular string pattern.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A contextual <emphasis>positioning</emphasis> operation
|
||||
moves the horizontal and/or vertical position of a
|
||||
glyph. This positioning move is performed when the glyph
|
||||
occurs in a specified position with respect to the
|
||||
surrounding sequence.
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
scripts may use contextual positioning operations to
|
||||
correctly place base glyphs as well, such as
|
||||
when the script uses <emphasis>stacking</emphasis> characters.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="unicode-character-categories">
|
||||
<title>Unicode character categories</title>
|
||||
<para>
|
||||
Shaping models are typically specified with respect to how
|
||||
scripts are defined in the Unicode standard.
|
||||
</para>
|
||||
<para>
|
||||
Every codepoint in the Unicode Character Database (UCD) is
|
||||
assigned a <emphasis>Unicode General Category</emphasis> (UGC),
|
||||
which provides the most fundamental information about the
|
||||
codepoint: whether the codepoint represents a
|
||||
<emphasis>Letter</emphasis>, a <emphasis>Mark</emphasis>, a
|
||||
<emphasis>Number</emphasis>, <emphasis>Punctuation</emphasis>, a
|
||||
<emphasis>Symbol</emphasis>, a <emphasis>Separator</emphasis>,
|
||||
or something else (<emphasis>Other</emphasis>).
|
||||
</para>
|
||||
<para>
|
||||
These UGC properties are "Major" categories. Each codepoint is
|
||||
further assigned to a "minor" category within its Major
|
||||
category, such as "Letter, uppercase" (<literal>Lu</literal>) or
|
||||
"Letter, modifier" (<literal>Lm</literal>).
|
||||
</para>
|
||||
<para>
|
||||
Shaping models are concerned primarily with Letter and Mark
|
||||
codepoints. The minor categories of Mark codepoints are
|
||||
particularly important for shaping. Marks can be nonspacing
|
||||
(<literal>Mn</literal>), spacing combining
|
||||
(<literal>Mc</literal>), or enclosing (<literal>Me</literal>).
|
||||
</para>
|
||||
<para>
|
||||
In addition to the UGC property, codepoints in the Indic and
|
||||
Southeast Asian scripts are also assigned
|
||||
<emphasis>Unicode Indic Syllabic Category</emphasis> (UISC) and
|
||||
<emphasis>Unicode Indic Positional Category</emphasis> (UIPC)
|
||||
properties that provide more detailed information needed for
|
||||
shaping.
|
||||
</para>
|
||||
<para>
|
||||
The UISC property sub-categorizes Letters and Marks according to
|
||||
common script-shaping behaviors. For example, UISC distinguishes
|
||||
between consonant letters, vowel letters, and vowel marks. The
|
||||
UIPC property sub-categorizes Mark codepoints by the relative visual
|
||||
position that they occupy (above, below, right, left, or in
|
||||
multiple positions).
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
properties into account.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="text-runs">
|
||||
<title>Text runs</title>
|
||||
<para>
|
||||
Real-world text usually contains codepoints from a mixture of
|
||||
different Unicode scripts (including punctuation, numbers, symbols,
|
||||
white-space characters, and other codepoints that do not belong
|
||||
to any script). Real-world text may also be marked up with
|
||||
formatting that changes font properties (including the font,
|
||||
font style, and font size).
|
||||
</para>
|
||||
<para>
|
||||
For shaping purposes, all real-world text streams must be first
|
||||
segmented into runs that have a uniform set of properties.
|
||||
</para>
|
||||
<para>
|
||||
In particular, shaping models always assume that every codepoint
|
||||
in a text run has the same <emphasis>direction</emphasis>,
|
||||
<emphasis>script</emphasis> tag, and
|
||||
<emphasis>language</emphasis> tag.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="opentype-shaping-models">
|
||||
<title>OpenType shaping models</title>
|
||||
<para>
|
||||
OpenType provides shaping models for the following scripts:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>default</emphasis> shaping model handles all
|
||||
scripts with no script-specific shaping model, and may also be used as a fallback for
|
||||
handling unrecognized scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Indic</emphasis> shaping model handles the Indic
|
||||
scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
|
||||
Malayalam, Oriya, Tamil, and Telugu.
|
||||
</para>
|
||||
<para>
|
||||
The Indic shaping model was revised significantly in
|
||||
2005. To denote the change, a new set of <emphasis>script
|
||||
tags</emphasis> was assigned for Bengali, Devanagari,
|
||||
Gujarati, Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and
|
||||
Telugu. For the sake of clarity, the term "Indic2" is
|
||||
sometimes used to refer to the current, revised shaping
|
||||
model.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Arabic</emphasis> shaping model supports
|
||||
Arabic, Mongolian, N'Ko, Syriac, and several other connected
|
||||
or cursive scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Thai/Lao</emphasis> shaping model supports
|
||||
the Thai and Lao scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Khmer</emphasis> shaping model supports the
|
||||
Khmer script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Myanmar</emphasis> shaping model supports the
|
||||
Myanmar (or Burmese) script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Tibetan</emphasis> shaping model supports the
|
||||
Tibetan script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Hangul</emphasis> shaping model supports the
|
||||
Hangul script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Hebrew</emphasis> shaping model supports the
|
||||
Hebrew script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Universal Shaping Engine</emphasis> (USE)
|
||||
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
|
||||
Viet, and many others.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Text runs that do not fall under one of the above shaping
|
||||
models may still require processing by a shaping engine. Of
|
||||
particular note is <emphasis>Emoji</emphasis> shaping, which
|
||||
may involve variation-selector sequences and glyph
|
||||
substitution. Emoji shaping is handled by the default
|
||||
shaping model.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="graphite-shaping">
|
||||
<title>Graphite shaping</title>
|
||||
<para>
|
||||
In contrast to OpenType shaping, Graphite shaping does not
|
||||
specify a predefined set of shaping models or a set of supported
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
Instead, each Graphite font contains a complete set of rules that
|
||||
implement the required shaping model for the intended
|
||||
script. These rules include finite-state machines to match
|
||||
sequences of codepoints to the shaping operations to perform.
|
||||
</para>
|
||||
<para>
|
||||
Graphite shaping can perform the same shaping operations used in
|
||||
OpenType shaping, as well as other functions that have not been
|
||||
defined for OpenType shaping.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="aat-shaping">
|
||||
<title>AAT shaping</title>
|
||||
<para>
|
||||
In contrast to OpenType shaping, AAT shaping does not specify a
|
||||
predefined set of shaping models or a set of supported scripts.
|
||||
</para>
|
||||
<para>
|
||||
Instead, each AAT font includes a complete set of rules that
|
||||
implement the desired shaping model for the intended
|
||||
script. These rules include finite-state machines to match glyph
|
||||
sequences and the shaping operations to perform.
|
||||
</para>
|
||||
<para>
|
||||
Notably, AAT shaping rules are expressed for glyphs in the font,
|
||||
not for Unicode codepoints. AAT shaping can perform the same
|
||||
shaping operations used in OpenType shaping, as well as other
|
||||
functions that have not been defined for OpenType shaping.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
|
@ -1,218 +0,0 @@
|
|||
<?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="utilities">
|
||||
<title>Utilities</title>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<section id="utilities-command-line-tools">
|
||||
<title>Command-line tools</title>
|
||||
<para>
|
||||
HarfBuzz include three command-line tools:
|
||||
<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>
|
||||
|
||||
<section id="utilities-command-line-hbshape">
|
||||
<title>hb-shape</title>
|
||||
<para>
|
||||
<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. <command>hb-shape</command> does
|
||||
<emphasis>not</emphasis> render the results of the shaping call
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
You can specify the font to be used for shaping and, with
|
||||
command-line options, you can add various aspects of the
|
||||
internal state to the output that is sent to the terminal. The
|
||||
general format is
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-shape</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
The default output format is plain text (although JSON output
|
||||
can be selected instead by specifying the option
|
||||
<optional>--output-format=json</optional>). The default output
|
||||
syntax reports each glyph name (or glyph index if there is no
|
||||
name) followed by its cluster value, its horizontal and vertical
|
||||
position displacement, and its horizontal and vertical advances.
|
||||
</para>
|
||||
<para>
|
||||
Output options exist to skip any of these elements in the
|
||||
output, and to include additional data, such as Unicode
|
||||
code-point values, glyph extents, glyph flags, or interim
|
||||
shaping results.
|
||||
</para>
|
||||
<para>
|
||||
Output can also be redirected to a file, or input read from a
|
||||
file. Additional options enable you to enable or disable
|
||||
specific font features, to set variation-font axis values, to
|
||||
alter the language, script, direction, and clustering settings
|
||||
used, to enable sanity checks, or to change which shaping engine is used.
|
||||
</para>
|
||||
<para>
|
||||
For a complete explanation of the options available, run
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-shape</command> <parameter>--help</parameter>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="utilities-command-line-hbview">
|
||||
<title>hb-view</title>
|
||||
<para>
|
||||
<emphasis><command>hb-view</command></emphasis> allows you to
|
||||
see the shaped output of an input string in rendered
|
||||
form. Like <command>hb-shape</command>,
|
||||
<command>hb-view</command> takes a font file and a text string
|
||||
as its arguments:
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-view</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
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>
|
||||
switch, you can write the output to a PNG, SVG, or PDF file
|
||||
(among other formats).
|
||||
</para>
|
||||
<para>
|
||||
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
|
||||
used, enable sanity checks, or change which shaping engine is
|
||||
used.
|
||||
</para>
|
||||
<para>
|
||||
You can also set the foreground and background colors used for
|
||||
the output, independently control the width of all four
|
||||
margins, alter the line spacing, and annotate the output image
|
||||
with
|
||||
</para>
|
||||
<para>
|
||||
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 <command>hb-shape</command> to figure out exactly
|
||||
why something does not appear as expected.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="utilities-command-line-hbsubset">
|
||||
<title>hb-subset</title>
|
||||
<para>
|
||||
<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 <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>
|
||||
<programlisting>
|
||||
<command>hb-subset</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
For example, to create a subset of Noto Serif that just includes the
|
||||
numerals and the lowercase Latin alphabet, you could run
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-subset</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>NotoSerif-Regular.ttf</parameter>
|
||||
<parameter>0123456789abcdefghijklmnopqrstuvwxyz</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
There are options available to remove hinting from the
|
||||
subsetted font and to specify a list of variation-axis settings.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="utilities-common-types-apis">
|
||||
<title>Common data types and APIs</title>
|
||||
<para>
|
||||
HarfBuzz includes several APIs for working with general-purpose
|
||||
data that you may find convenient to leverage in your own
|
||||
software. They include set operations and integer-to-integer
|
||||
mapping operations.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz uses set operations for internal bookkeeping, such as
|
||||
when it collects all of the glyph IDs covered by a particular
|
||||
font feature. You can also use the set API to build sets, add
|
||||
and remove elements, test whether or not sets contain particular
|
||||
elements, or compute the unions, intersections, or differences
|
||||
between sets.
|
||||
</para>
|
||||
<para>
|
||||
All set elements are integers (specifically,
|
||||
<type>hb_codepoint_t</type> 32-bit unsigned ints), and there are
|
||||
functions for fetching the minimum and maximum element from a
|
||||
set. The set API also includes some functions that might not
|
||||
be part of a generic set facility, such as the ability to add a
|
||||
contiguous range of integer elements to a set in bulk, and the
|
||||
ability to fetch the next-smallest or next-largest element.
|
||||
</para>
|
||||
<para>
|
||||
The HarfBuzz set API includes some conveniences as well. All
|
||||
sets are lifecycle-managed, just like other HarfBuzz
|
||||
objects. You increase the reference count on a set with
|
||||
<function>hb_set_reference()</function> and decrease it with
|
||||
<function>hb_set_destroy()</function>. You can also attach
|
||||
user data to a set, just like you can to blobs, buffers, faces,
|
||||
fonts, and other objects, and set destroy callbacks.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides an API for keeping track of
|
||||
integer-to-integer mappings. As with the set API, each integer is
|
||||
stored as an unsigned 32-bit <type>hb_codepoint_t</type>
|
||||
element. Maps, like other objects, are reference counted with
|
||||
reference and destroy functions, and you can attach user data to
|
||||
them. The mapping operations include adding and deleting
|
||||
integer-to-integer key:value pairs to the map, testing for the
|
||||
presence of a key, fetching the population of the map, and so on.
|
||||
</para>
|
||||
<para>
|
||||
There are several other internal HarfBuzz facilities that are
|
||||
exposed publicly and which you may want to take advantage of
|
||||
while processing text. HarfBuzz uses a common
|
||||
<type>hb_tag_t</type> for a variety of OpenType tag identifiers (for
|
||||
scripts, languages, font features, table names, variation-axis
|
||||
names, and more), and provides functions for converting strings
|
||||
to tags and vice-versa.
|
||||
</para>
|
||||
<para>
|
||||
Finally, HarfBuzz also includes data type for Booleans, bit
|
||||
masks, and other simple types.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
|
@ -1,441 +1,115 @@
|
|||
<?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="what-is-harfbuzz">
|
||||
<title>What is HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz is a <emphasis>text-shaping engine</emphasis>. If you
|
||||
give HarfBuzz a font and a string containing a sequence of Unicode
|
||||
codepoints, HarfBuzz selects and positions the corresponding
|
||||
glyphs from the font, applying all of the necessary layout rules
|
||||
and font features. HarfBuzz then returns the string to you in the
|
||||
form that is correctly arranged for the language and writing
|
||||
system.
|
||||
HarfBuzz is a <emphasis>text shaping engine</emphasis>. It solves
|
||||
the problem of selecting and positioning glyphs from a font given a
|
||||
Unicode string.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can properly shape all of the world's major writing
|
||||
systems. It runs on all major operating systems and software
|
||||
platforms and it supports the major font formats in use
|
||||
today.
|
||||
</para>
|
||||
<section id="what-is-text-shaping">
|
||||
<title>What is text shaping?</title>
|
||||
<section id="why-do-i-need-it">
|
||||
<title>Why do I need it?</title>
|
||||
<para>
|
||||
Text shaping is the process of translating a string of character
|
||||
codes (such as Unicode codepoints) into a properly arranged
|
||||
sequence of glyphs that can be rendered onto a screen or into
|
||||
final output form for inclusion in a document.
|
||||
</para>
|
||||
<para>
|
||||
The shaping process is dependent on the input string, the active
|
||||
font, the script (or writing system) that the string is in, and
|
||||
the language that the string is in.
|
||||
</para>
|
||||
<para>
|
||||
Modern software systems generally only deal with strings in the
|
||||
Unicode encoding scheme (although legacy systems and documents may
|
||||
involve other encodings).
|
||||
</para>
|
||||
<para>
|
||||
There are several font formats that a program might
|
||||
encounter, each of which has a set of standard text-shaping
|
||||
rules.
|
||||
</para>
|
||||
<para>The dominant format is <ulink
|
||||
url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>. The
|
||||
OpenType specification defines a series of <ulink url="https://github.com/n8willis/opentype-shaping-documents">shaping models</ulink> for
|
||||
various scripts from around the world. These shaping models depend on
|
||||
the font incorporating certain features as
|
||||
<emphasis>lookups</emphasis> in its <literal>GSUB</literal>
|
||||
and <literal>GPOS</literal> tables.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, OpenType fonts can include shaping features for
|
||||
the <ulink url="https://graphite.sil.org/">Graphite</ulink> shaping model.
|
||||
</para>
|
||||
<para>
|
||||
TrueType fonts can also include OpenType shaping
|
||||
features. Alternatively, TrueType fonts can also include <ulink url="https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html">Apple
|
||||
Advanced Typography</ulink> (AAT) tables to implement shaping
|
||||
support. AAT fonts are generally only found on macOS and iOS systems.
|
||||
</para>
|
||||
<para>
|
||||
Text strings will usually be tagged with a script and language
|
||||
tag that provide the context needed to perform text shaping
|
||||
correctly. The necessary <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags">script</ulink>
|
||||
and <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags">language</ulink>
|
||||
tags are defined by OpenType.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-do-i-need-a-shaping-engine">
|
||||
<title>Why do I need a shaping engine?</title>
|
||||
<para>
|
||||
Text shaping is an integral part of preparing text for
|
||||
display. Before a Unicode sequence can be rendered, the
|
||||
codepoints in the sequence must be mapped to the corresponding
|
||||
glyphs provided in the font, and those glyphs must be positioned
|
||||
correctly relative to each other. For many of the scripts
|
||||
supported in Unicode, these steps involve script-specific layout
|
||||
rules, including complex joining, reordering, and positioning
|
||||
behavior. Implementing these rules is the job of the shaping engine.
|
||||
</para>
|
||||
<para>
|
||||
Text shaping is a fairly low-level operation. HarfBuzz is
|
||||
used directly by text-handling libraries like <ulink
|
||||
url="https://www.pango.org/">Pango</ulink>, as well as by the layout
|
||||
engines in Firefox, LibreOffice, and Chromium. Unless you are
|
||||
<emphasis>writing</emphasis> one of these layout engines
|
||||
yourself, you will probably not need to use HarfBuzz: normally,
|
||||
a layout engine, toolkit, or other library will turn text into
|
||||
glyphs for you.
|
||||
Text shaping is an integral part of preparing text for display. It
|
||||
is a fairly low level operation; HarfBuzz is used directly by
|
||||
graphic rendering libraries such as Pango, and the layout engines
|
||||
in Firefox, LibreOffice and Chromium. Unless you are
|
||||
<emphasis>writing</emphasis> one of these layout engines yourself,
|
||||
you will probably not need to use HarfBuzz - normally higher level
|
||||
libraries will turn text into glyphs for you.
|
||||
</para>
|
||||
<para>
|
||||
However, if you <emphasis>are</emphasis> writing a layout engine
|
||||
or graphics library yourself, then you will need to perform text
|
||||
shaping, and this is where HarfBuzz can help you.
|
||||
</para>
|
||||
<para>
|
||||
Here are some specific scenarios where a text-shaping engine
|
||||
like HarfBuzz helps you:
|
||||
or graphics library yourself, you will need to perform text
|
||||
shaping, and this is where HarfBuzz can help you. Here are some
|
||||
reasons why you need it:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
OpenType fonts contain a set of glyphs (that is, shapes
|
||||
to represent the letters, numbers, punctuation marks, and
|
||||
all other symbols), which are indexed by a <literal>glyph ID</literal>.
|
||||
</para>
|
||||
<para>
|
||||
A particular glyph ID within the font does not necessarily
|
||||
correlate to a predictable Unicode codepoint. For instance,
|
||||
some fonts have the letter "a" as glyph ID 1, but
|
||||
many others do not. In order to retrieve the right glyph
|
||||
from the font to display "a", you need to consult
|
||||
the table inside the font (the <literal>cmap</literal>
|
||||
table) that maps Unicode codepoints to glyph IDs. In other
|
||||
words, <emphasis>text shaping turns codepoints into glyph
|
||||
IDs</emphasis>.
|
||||
OpenType fonts contain a set of glyphs, indexed by glyph ID.
|
||||
The glyph ID within the font does not necessarily relate to a
|
||||
Unicode codepoint. For instance, some fonts have the letter
|
||||
"a" as glyph ID 1. To pull the right glyph out of
|
||||
the font in order to display it, you need to consult a table
|
||||
within the font (the "cmap" table) which maps
|
||||
Unicode codepoints to glyph IDs. Text shaping turns codepoints
|
||||
into glyph IDs.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Many OpenType fonts contain ligatures: combinations of
|
||||
characters that are rendered as a single unit. For instance,
|
||||
it is common for the "f, i" letter
|
||||
sequence to appear in print as the single ligature glyph
|
||||
"fi".
|
||||
</para>
|
||||
<para>
|
||||
Whether you should render an "f, i" sequence
|
||||
as <literal>fi</literal> or as "fi" does not
|
||||
depend on the input text. Instead, it depends on the whether
|
||||
or not the font includes an "fi" glyph and on the
|
||||
level of ligature application you wish to perform. The font
|
||||
and the amount of ligature application used are under your
|
||||
control. In other words, <emphasis>text shaping involves
|
||||
querying the font's ligature tables and determining what
|
||||
substitutions should be made</emphasis>.
|
||||
characters which are rendered together. For instance, it's
|
||||
common for the <literal>fi</literal> combination to appear in
|
||||
print as the single ligature "fi". Whether you should
|
||||
render text as <literal>fi</literal> or "fi" does not
|
||||
depend on the input text, but on the capabilities of the font
|
||||
and the level of ligature application you wish to perform.
|
||||
Text shaping involves querying the font's ligature tables and
|
||||
determining what substitutions should be made.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
While ligatures like "fi" are optional typographic
|
||||
refinements, some languages <emphasis>require</emphasis> certain
|
||||
While ligatures like "fi" are typographic
|
||||
refinements, some languages <emphasis>require</emphasis> such
|
||||
substitutions to be made in order to display text correctly.
|
||||
</para>
|
||||
<para>
|
||||
For example, in Tamil, when the letter "TTA" (ட)
|
||||
letter is followed by the vowel sign "U" (ு), the pair
|
||||
must be replaced by the single glyph "டு". The
|
||||
sequence of Unicode characters "ட,ு" needs to be
|
||||
substituted with a single "டு" glyph from the
|
||||
font.
|
||||
</para>
|
||||
<para>
|
||||
But "டு" does not have a Unicode codepoint. To
|
||||
find this glyph, you need to consult the table inside
|
||||
the font (the <literal>GSUB</literal> table) that contains
|
||||
substitution information. In other words, <emphasis>text shaping
|
||||
chooses the correct glyph for a sequence of characters
|
||||
provided</emphasis>.
|
||||
In Tamil, when the letter "TTA" (ட) letter is
|
||||
followed by "U" (உ), the combination should appear
|
||||
as the single glyph "டு". The sequence of Unicode
|
||||
characters "டஉ" needs to be rendered as a single
|
||||
glyph from the font - text shaping chooses the correct glyph
|
||||
from the sequence of characters provided.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Similarly, each Arabic character has four different variants
|
||||
corresponding to the different positions it might appear in
|
||||
within a sequence. Inside a font, there will be separate
|
||||
glyphs for the initial, medial, final, and isolated forms of
|
||||
each letter, each at a different glyph ID.
|
||||
</para>
|
||||
<para>
|
||||
Unicode only assigns one codepoint per character, so a
|
||||
Unicode string will not tell you which glyph variant to use
|
||||
for each character. To decide, you need to analyze the whole
|
||||
string and determine the appropriate glyph for each character
|
||||
based on its position. In other words, <emphasis>text
|
||||
shaping chooses the correct form of the letter by its
|
||||
position and returns the correct glyph from the font</emphasis>.
|
||||
Similarly, each Arabic character has four different variants:
|
||||
within a font, there will be glyphs for the initial, medial,
|
||||
final, and isolated forms of each letter. Unicode only encodes
|
||||
one codepoint per character, and so a Unicode string will not
|
||||
tell you which glyph to use. Text shaping chooses the correct
|
||||
form of the letter and returns the correct glyph from the font
|
||||
that you need to render.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Other languages involve marks and accents that need to be
|
||||
rendered in specific positions relative a base character. For
|
||||
instance, the Moldovan language includes the Cyrillic letter
|
||||
"zhe" (ж) with a breve accent, like so: "ӂ".
|
||||
</para>
|
||||
<para>
|
||||
Some fonts will provide this character as a single
|
||||
zhe-with-breve glyph, but other fonts will not and, instead,
|
||||
will expect the rendering engine to form the character by
|
||||
superimposing the separate "ж" and "˘"
|
||||
glyphs.
|
||||
</para>
|
||||
<para>
|
||||
But exactly where you should draw the breve depends on the
|
||||
height and width of the preceding zhe glyph. To find the
|
||||
right position, you need to consult the table inside
|
||||
the font (the <literal>GPOS</literal> table) that contains
|
||||
positioning information.
|
||||
In other words, <emphasis>text shaping tells you whether you
|
||||
have a precomposed glyph within your font or if you need to
|
||||
compose a glyph yourself out of combining marks—and,
|
||||
if so, where to position those marks.</emphasis>
|
||||
Other languages have marks and accents which need to be
|
||||
rendered in certain positions around a base character. For
|
||||
instance, the Moldovan language has the Cyrillic letter
|
||||
"zhe" (ж) with a breve accent, like so: ӂ. Some
|
||||
fonts will contain this character as an individual glyph,
|
||||
whereas other fonts will not contain a zhe-with-breve glyph
|
||||
but expect the rendering engine to form the character by
|
||||
overlaying the two glyphs ж and ˘. Where you should draw the
|
||||
combining breve depends on the height of the preceding glyph.
|
||||
Again, for Arabic, the correct positioning of vowel marks
|
||||
depends on the height of the character on which you are
|
||||
placing the mark. Text shaping tells you whether you have a
|
||||
precomposed glyph within your font or if you need to compose a
|
||||
glyph yourself out of combining marks, and if so, where to
|
||||
position those marks.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If tasks like these are something that you need to do, then you
|
||||
need a text shaping engine. You could use Uniscribe if you are
|
||||
writing Windows software; you could use CoreText on macOS; or
|
||||
you could use HarfBuzz.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
In the rest of this manual, the text will assume that the reader
|
||||
is that implementor of a text-layout engine.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="what-does-harfbuzz-do">
|
||||
<title>What does HarfBuzz do?</title>
|
||||
<para>
|
||||
HarfBuzz provides text shaping through a cross-platform
|
||||
C API that accepts sequences of Unicode codepoints as input. Currently,
|
||||
the following OpenType shaping models are supported:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Indic (covering Devanagari, Bengali, Gujarati,
|
||||
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and Telugu)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Arabic (covering Arabic, N'Ko, Syriac, and Mongolian)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Thai and Lao
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Khmer
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Myanmar
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Tibetan
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Hangul
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Hebrew
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The Universal Shaping Engine or <emphasis>USE</emphasis>
|
||||
(covering complex scripts not covered by the above shaping
|
||||
models)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
A default shaping model for non-complex scripts
|
||||
(covering Latin, Cyrillic, Greek, Armenian, Georgian, Tifinagh,
|
||||
and many others)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Emoji (including emoji modifier sequences, flag sequences,
|
||||
and ZWJ sequences)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
In addition to OpenType shaping, HarfBuzz supports the latest
|
||||
version of Graphite shaping (the "Graphite 2" model) and AAT
|
||||
shaping.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz can read and understand TrueType fonts (.ttf), TrueType
|
||||
collections (.ttc), and OpenType fonts (.otf, including those
|
||||
fonts that contain TrueType-style outlines and those that
|
||||
contain PostScript CFF or CFF2 outlines).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz is designed and tested to run on top of the FreeType
|
||||
font renderer. It can run on Linux, Android, Windows, macOS, and
|
||||
iOS systems.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In addition to its core shaping functionality, HarfBuzz provides
|
||||
functions for accessing other font features, including optional
|
||||
GSUB and GPOS OpenType features, as well as
|
||||
all color-font formats (<literal>CBDT</literal>,
|
||||
<literal>sbix</literal>, <literal>COLR/CPAL</literal>, and
|
||||
<literal>SVG-OT</literal>) and OpenType variable fonts. HarfBuzz
|
||||
also includes a font-subsetting feature. HarfBuzz can perform
|
||||
some low-level math-shaping operations, although it does not
|
||||
currently perform full shaping for mathematical typesetting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A suite of command-line utilities is also provided in the
|
||||
source-code tree, designed to help users test and debug
|
||||
HarfBuzz's features on real-world fonts and input.
|
||||
If this is something that you need to do, then you need a text
|
||||
shaping engine: you could use Uniscribe if you are using Windows;
|
||||
you could use CoreText on OS X; or you could use HarfBuzz. In the
|
||||
rest of this manual, we are going to assume that you are the
|
||||
implementor of a text layout engine.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="what-harfbuzz-doesnt-do">
|
||||
<title>What HarfBuzz doesn't do</title>
|
||||
<para>
|
||||
HarfBuzz will take a Unicode string, shape it, and give you the
|
||||
information required to lay it out correctly on a single
|
||||
horizontal (or vertical) line using the font provided. That is the
|
||||
extent of HarfBuzz's responsibility.
|
||||
</para>
|
||||
<para>
|
||||
It is important to note that if you are implementing a complete
|
||||
text-layout engine you may have other responsibilities that
|
||||
HarfBuzz will <emphasis>not</emphasis> help you with. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with bidirectionality. If you want to
|
||||
lay out text that includes a mix of Hebrew and English, you
|
||||
will need to ensure that each buffer provided to HarfBuzz
|
||||
has all of its characters in the same order and that the
|
||||
directionality of the buffer is set correctly. This may mean
|
||||
segmenting the text before it is placed into HarfBuzz buffers. In
|
||||
other words, the user will hit the keys in the following
|
||||
sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A B C [space] ג ב א [space] D E F
|
||||
</programlisting>
|
||||
<para>
|
||||
but will expect to see in the output:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC אבג DEF
|
||||
</programlisting>
|
||||
<para>
|
||||
This reordering is called <emphasis>bidi processing</emphasis>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to process a string of mixed directionality.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as <ulink
|
||||
url="http://icu-project.org/">ICU</ulink> and <ulink
|
||||
url="http://fribidi.org/">fribidi</ulink> can do this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, then you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, if you change the font, font size, script,
|
||||
language, or direction within your string, then you will
|
||||
need to shape each run independently and output them
|
||||
independently. HarfBuzz expects to shape a run of characters
|
||||
that all share the same properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation, or
|
||||
justification. As mentioned above, HarfBuzz lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout-engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need—what you then do with the glyphs that your font
|
||||
returns is up to you.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-is-it-called-harfbuzz">
|
||||
<title>Why is it called HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz began its life as text-shaping code within the FreeType
|
||||
project (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations), but was then
|
||||
extracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, who named it HarfBuzz. Originally, it was a
|
||||
shaping engine for OpenType fonts—"HarfBuzz" is
|
||||
the Persian for "open type".
|
||||
HarfBuzz began its life as text shaping code within the FreeType
|
||||
project, (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations) but was then
|
||||
abstracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, and named HarfBuzz. Originally, it was a shaping
|
||||
engine for OpenType fonts - "HarfBuzz" is the Persian
|
||||
for "open type".
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
7
git.mk
7
git.mk
|
@ -204,7 +204,7 @@ git-mk-update:
|
|||
# Actual .gitignore generation:
|
||||
###############################################################################
|
||||
|
||||
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.ac
|
||||
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
|
||||
@echo "git.mk: Generating $@"
|
||||
@{ \
|
||||
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
|
||||
|
@ -375,9 +375,8 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk $(top_srcdir)/configure.a
|
|||
} | \
|
||||
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
|
||||
sed 's@/[.]/@/@g' | \
|
||||
LC_ALL=C sort | uniq > .gitignore.tmp && \
|
||||
(mv .gitignore.tmp $@ || (echo "WARNING: Cannot create $@ file; skipping"; \
|
||||
$(RM) .gitignore.tmp));
|
||||
LC_ALL=C sort | uniq > $@.tmp && \
|
||||
mv $@.tmp $@;
|
||||
|
||||
all: $(srcdir)/.gitignore gitignore-recurse-maybe
|
||||
gitignore: $(srcdir)/.gitignore gitignore-recurse
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
<shortdesc xml:lang="en">Text shaping library</shortdesc>
|
||||
|
||||
<homepage
|
||||
rdf:resource="https://github.com/harfbuzz/harfbuzz" />
|
||||
rdf:resource="http://harfbuzz.org/" />
|
||||
<mailing-list
|
||||
rdf:resource="https://github.com/harfbuzz/harfbuzz/discussions" />
|
||||
<download-page
|
||||
rdf:resource="https://github.com/harfbuzz/harfbuzz/releases" />
|
||||
rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
|
||||
<!--download-page
|
||||
rdf:resource=""/-->
|
||||
<bug-database
|
||||
rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
|
||||
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the linker or gives an error.
|
||||
# (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
|
||||
# when the check is done. The check is thus made with the flags: "LDFLAGS
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_LINK_IFELSE.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||
# gives unlimited permission to copy, distribute and modify the configure
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 5
|
||||
|
||||
AC_DEFUN([AX_CHECK_LINK_FLAG],
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS $4 $1"
|
||||
AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
LDFLAGS=$ax_check_save_flags])
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_LINK_FLAGS
|
|
@ -1,264 +0,0 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CODE_COVERAGE()
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,
|
||||
# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included
|
||||
# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every
|
||||
# build target (program or library) which should be built with code
|
||||
# coverage support. Also defines CODE_COVERAGE_RULES which should be
|
||||
# substituted in your Makefile; and $enable_code_coverage which can be
|
||||
# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined
|
||||
# and substituted, and corresponds to the value of the
|
||||
# --enable-code-coverage option, which defaults to being disabled.
|
||||
#
|
||||
# Test also for gcov program and create GCOV variable that could be
|
||||
# substituted.
|
||||
#
|
||||
# Note that all optimization flags in CFLAGS must be disabled when code
|
||||
# coverage is enabled.
|
||||
#
|
||||
# Usage example:
|
||||
#
|
||||
# configure.ac:
|
||||
#
|
||||
# AX_CODE_COVERAGE
|
||||
#
|
||||
# Makefile.am:
|
||||
#
|
||||
# @CODE_COVERAGE_RULES@
|
||||
# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ...
|
||||
# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...
|
||||
# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...
|
||||
# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...
|
||||
#
|
||||
# This results in a "check-code-coverage" rule being added to any
|
||||
# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module
|
||||
# has been configured with --enable-code-coverage). Running `make
|
||||
# check-code-coverage` in that directory will run the module's test suite
|
||||
# (`make check`) and build a code coverage report detailing the code which
|
||||
# was touched, then print the URI for the report.
|
||||
#
|
||||
# In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined
|
||||
# instead of CODE_COVERAGE_LIBS. They are both still defined, but use of
|
||||
# CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is
|
||||
# deprecated. They have the same value.
|
||||
#
|
||||
# This code was derived from Makefile.decl in GLib, originally licenced
|
||||
# under LGPLv2.1+.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2012, 2016 Philip Withnall
|
||||
# Copyright (c) 2012 Xan Lopez
|
||||
# Copyright (c) 2012 Christian Persch
|
||||
# Copyright (c) 2012 Paolo Borelli
|
||||
# Copyright (c) 2012 Dan Winship
|
||||
# Copyright (c) 2015 Bastien ROUCARIES
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#serial 25
|
||||
|
||||
AC_DEFUN([AX_CODE_COVERAGE],[
|
||||
dnl Check for --enable-code-coverage
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
|
||||
# allow to override gcov location
|
||||
AC_ARG_WITH([gcov],
|
||||
[AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],
|
||||
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],
|
||||
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])
|
||||
|
||||
AC_MSG_CHECKING([whether to build with code coverage support])
|
||||
AC_ARG_ENABLE([code-coverage],
|
||||
AS_HELP_STRING([--enable-code-coverage],
|
||||
[Whether to enable code coverage support]),,
|
||||
enable_code_coverage=no)
|
||||
|
||||
AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes])
|
||||
AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])
|
||||
AC_MSG_RESULT($enable_code_coverage)
|
||||
|
||||
AS_IF([ test "$enable_code_coverage" = "yes" ], [
|
||||
# check for gcov
|
||||
AC_CHECK_TOOL([GCOV],
|
||||
[$_AX_CODE_COVERAGE_GCOV_PROG_WITH],
|
||||
[:])
|
||||
AS_IF([test "X$GCOV" = "X:"],
|
||||
[AC_MSG_ERROR([gcov is needed to do coverage])])
|
||||
AC_SUBST([GCOV])
|
||||
|
||||
dnl Check if gcc is being used
|
||||
AS_IF([ test "$GCC" = "no" ], [
|
||||
AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])
|
||||
])
|
||||
|
||||
AC_CHECK_PROG([LCOV], [lcov], [lcov])
|
||||
AC_CHECK_PROG([GENHTML], [genhtml], [genhtml])
|
||||
|
||||
AS_IF([ test -z "$LCOV" ], [
|
||||
AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed])
|
||||
])
|
||||
|
||||
AS_IF([ test -z "$GENHTML" ], [
|
||||
AC_MSG_ERROR([Could not find genhtml from the lcov package])
|
||||
])
|
||||
|
||||
dnl Build the code coverage flags
|
||||
dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility
|
||||
CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
|
||||
CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
CODE_COVERAGE_LIBS="-lgcov"
|
||||
CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS"
|
||||
|
||||
AC_SUBST([CODE_COVERAGE_CPPFLAGS])
|
||||
AC_SUBST([CODE_COVERAGE_CFLAGS])
|
||||
AC_SUBST([CODE_COVERAGE_CXXFLAGS])
|
||||
AC_SUBST([CODE_COVERAGE_LIBS])
|
||||
AC_SUBST([CODE_COVERAGE_LDFLAGS])
|
||||
|
||||
[CODE_COVERAGE_RULES_CHECK='
|
||||
-$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check
|
||||
$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture
|
||||
']
|
||||
[CODE_COVERAGE_RULES_CAPTURE='
|
||||
$(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS)
|
||||
$(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS)
|
||||
-@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp
|
||||
$(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS)
|
||||
@echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html"
|
||||
']
|
||||
[CODE_COVERAGE_RULES_CLEAN='
|
||||
clean: code-coverage-clean
|
||||
distclean: code-coverage-clean
|
||||
code-coverage-clean:
|
||||
-$(LCOV) --directory $(top_builddir) -z
|
||||
-rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY)
|
||||
-find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete
|
||||
']
|
||||
], [
|
||||
[CODE_COVERAGE_RULES_CHECK='
|
||||
@echo "Need to reconfigure with --enable-code-coverage"
|
||||
']
|
||||
CODE_COVERAGE_RULES_CAPTURE="$CODE_COVERAGE_RULES_CHECK"
|
||||
CODE_COVERAGE_RULES_CLEAN=''
|
||||
])
|
||||
|
||||
[CODE_COVERAGE_RULES='
|
||||
# Code coverage
|
||||
#
|
||||
# Optional:
|
||||
# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.
|
||||
# Multiple directories may be specified, separated by whitespace.
|
||||
# (Default: $(top_builddir))
|
||||
# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated
|
||||
# by lcov for code coverage. (Default:
|
||||
# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info)
|
||||
# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage
|
||||
# reports to be created. (Default:
|
||||
# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage)
|
||||
# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,
|
||||
# set to 0 to disable it and leave empty to stay with the default.
|
||||
# (Default: empty)
|
||||
# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov
|
||||
# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
|
||||
# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov
|
||||
# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
|
||||
# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov
|
||||
# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the
|
||||
# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
|
||||
# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov
|
||||
# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
|
||||
# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering
|
||||
# lcov instance. (Default: empty)
|
||||
# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov
|
||||
# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
|
||||
# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the
|
||||
# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
|
||||
# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml
|
||||
# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
|
||||
# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore
|
||||
#
|
||||
# The generated report will be titled using the $(PACKAGE_NAME) and
|
||||
# $(PACKAGE_VERSION). In order to add the current git hash to the title,
|
||||
# use the git-version-gen script, available online.
|
||||
|
||||
# Optional variables
|
||||
CODE_COVERAGE_DIRECTORY ?= $(top_builddir)
|
||||
CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info
|
||||
CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage
|
||||
CODE_COVERAGE_BRANCH_COVERAGE ?=
|
||||
CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
|
||||
--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
|
||||
CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
|
||||
CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)"
|
||||
CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
|
||||
CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
|
||||
CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=
|
||||
CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
|
||||
CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\
|
||||
$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
|
||||
--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
|
||||
CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
|
||||
CODE_COVERAGE_IGNORE_PATTERN ?=
|
||||
|
||||
GITIGNOREFILES ?=
|
||||
GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY)
|
||||
|
||||
code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V))
|
||||
code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\
|
||||
$(CODE_COVERAGE_OUTPUT_FILE);
|
||||
code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V))
|
||||
code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\
|
||||
$(CODE_COVERAGE_IGNORE_PATTERN);
|
||||
code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V))
|
||||
code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY);
|
||||
code_coverage_quiet = $(code_coverage_quiet_$(V))
|
||||
code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_quiet_0 = --quiet
|
||||
|
||||
# sanitizes the test-name: replaces with underscores: dashes and dots
|
||||
code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1)))
|
||||
|
||||
# Use recursive makes in order to ignore errors during check
|
||||
check-code-coverage:'"$CODE_COVERAGE_RULES_CHECK"'
|
||||
|
||||
# Capture code coverage data
|
||||
code-coverage-capture: code-coverage-capture-hook'"$CODE_COVERAGE_RULES_CAPTURE"'
|
||||
|
||||
# Hook rule executed before code-coverage-capture, overridable by the user
|
||||
code-coverage-capture-hook:
|
||||
|
||||
'"$CODE_COVERAGE_RULES_CLEAN"'
|
||||
|
||||
A''M_DISTCHECK_CONFIGURE_FLAGS ?=
|
||||
A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage
|
||||
|
||||
.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean
|
||||
']
|
||||
|
||||
AC_SUBST([CODE_COVERAGE_RULES])
|
||||
m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])])
|
||||
])
|
|
@ -422,7 +422,7 @@ namespace cxx11
|
|||
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// http://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
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
|
||||
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
|
||||
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||||
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
|
||||
fi
|
||||
if test -n "$PKG_CONFIG"; then
|
||||
_pkg_min_version=m4_default([$1], [0.9.0])
|
||||
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||||
AC_MSG_RESULT([yes])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
#
|
||||
# Similar to PKG_CHECK_MODULES, make sure that the first instance of
|
||||
# this or PKG_CHECK_MODULES is called, or make sure to call
|
||||
# PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
|
||||
m4_ifval([$2], [$2], [:])
|
||||
m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$PKG_CONFIG"; then
|
||||
if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
else
|
||||
PKG_CHECK_EXISTS([$3],
|
||||
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
|
||||
[pkg_failed=yes])
|
||||
fi
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
_pkg_short_errors_supported=yes
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||||
|
||||
pkg_failed=no
|
||||
AC_MSG_CHECKING([for $1])
|
||||
|
||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||||
|
||||
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
|
||||
and $1[]_LIBS to avoid the need to call pkg-config.
|
||||
See the pkg-config man page for more details.])
|
||||
|
||||
if test $pkg_failed = yes; then
|
||||
_PKG_SHORT_ERRORS_SUPPORTED
|
||||
if test $_pkg_short_errors_supported = yes; then
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
|
||||
else
|
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
|
||||
fi
|
||||
# Put the nasty error message in config.log where it belongs
|
||||
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
|
||||
|
||||
ifelse([$4], , [AC_MSG_ERROR(dnl
|
||||
[Package requirements ($2) were not met:
|
||||
|
||||
$$1_PKG_ERRORS
|
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||||
installed software in a non-standard prefix.
|
||||
|
||||
_PKG_TEXT
|
||||
])],
|
||||
[AC_MSG_RESULT([no])
|
||||
$4])
|
||||
elif test $pkg_failed = untried; then
|
||||
ifelse([$4], , [AC_MSG_FAILURE(dnl
|
||||
[The pkg-config script could not be found or is too old. Make sure it
|
||||
is in your PATH or set the PKG_CONFIG environment variable to the full
|
||||
path to pkg-config.
|
||||
|
||||
_PKG_TEXT
|
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
|
||||
[$4])
|
||||
else
|
||||
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
|
||||
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
|
||||
AC_MSG_RESULT([yes])
|
||||
ifelse([$3], , :, [$3])
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
441
meson.build
441
meson.build
|
@ -1,441 +0,0 @@
|
|||
project('harfbuzz', 'c', 'cpp',
|
||||
meson_version: '>= 0.55.0',
|
||||
version: '7.1.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'],
|
||||
]
|
||||
|
||||
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
|
|
@ -1,46 +0,0 @@
|
|||
# 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')
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
case $1 in
|
||||
i686 | x86_64) ;;
|
||||
*) echo "Usage: $0 i686|x86_64" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
target=$1-w64-mingw32
|
||||
shift
|
||||
|
||||
exec "$(dirname "$0")"/configure \
|
||||
--build=`../config.guess` \
|
||||
--host=$target \
|
||||
--prefix=$HOME/.local/$target \
|
||||
CC= \
|
||||
CXX= \
|
||||
CPP= \
|
||||
LD= \
|
||||
CFLAGS="-static-libgcc" \
|
||||
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 \
|
||||
"$@"
|
|
@ -1,23 +0,0 @@
|
|||
# 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
|
|
@ -1,54 +0,0 @@
|
|||
# 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
|
|
@ -1,245 +0,0 @@
|
|||
#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,
|
||||
glyph_shape,
|
||||
};
|
||||
|
||||
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 glyph_shape:
|
||||
{
|
||||
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 (glyph_shape, benchmark::kMicrosecond);
|
||||
|
||||
#undef TEST_OPERATION
|
||||
|
||||
benchmark::RunSpecifiedBenchmarks();
|
||||
benchmark::Shutdown();
|
||||
|
||||
if (tests != default_tests)
|
||||
free (tests);
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* 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();
|
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* 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();
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* 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();
|
|
@ -1,180 +0,0 @@
|
|||
#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);
|
||||
}
|
|
@ -1,259 +0,0 @@
|
|||
#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);
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,62 +0,0 @@
|
|||
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)
|
File diff suppressed because it is too large
Load Diff
12391
perf/texts/en-words.txt
12391
perf/texts/en-words.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,923 +0,0 @@
|
|||
شازده کوچولو
|
||||
اثر آنتوان دو سنتگزوپهری
|
||||
برگردان احمد شاملو
|
||||
|
||||
|
||||
اهدانامچه
|
||||
به لئون ورث Leon Werth
|
||||
از بچهها عذر میخواهم که این کتاب را به یکی از بزرگترها هدیه کردهام. برای این کار یک دلیل حسابی دارم: این «بزرگتر» بهترین دوست من تو همه دنیا است. یک دلیل دیگرم هم آن که این «بزرگتر» همه چیز را میتواند بفهمد حتا کتابهایی را که برای بچهها نوشته باشند. عذر سومم این است که این «بزرگتر» تو فرانسه زندگی میکند و آنجا گشنگی و تشنگی میکشد و سخت محتاج دلجویی است. اگر همهی این عذرها کافی نباشد اجازه میخواهم این کتاب را تقدیم آن بچهای کنم که این آدمبزرگ یک روزی بوده. آخر هر آدم بزرگی هم روزی روزگاری بچهای بوده (گیرم کمتر کسی از آنها این را به یاد میآورد). پس من هم اهدانامچهام را به این شکل تصحیح میکنم:
|
||||
|
||||
به لئون ورث
|
||||
موقعی که پسربچه بود
|
||||
آنتوان دو سنتگزوپهری
|
||||
|
||||
من هم برگردان فارسی این شعر بزرگ را به دو بچهی دوستداشتنی دیگر تقدیم میکنم: دکتر جهانگیر کازرونی و دکتر محمدجواد گلبن
|
||||
|
||||
احمد شاملو
|
||||
|
||||
۱
|
||||
یک بار شش سالم که بود تو کتابی به اسم قصههای واقعی -که دربارهی جنگل بِکر نوشته شده بود- تصویر محشری دیدم از یک مار بوآ که داشت حیوانی را میبلعید. آن تصویر یک چنین چیزی بود:
|
||||
|
||||
یک مار بوآ که دارد حیوانی را میبلعد
|
||||
تو کتاب آمده بود که: «مارهای بوآ شکارشان را همین جور درسته قورت میدهند. بی این که بجوندش. بعد دیگر نمیتوانند از جا بجنبند و تمام شش ماهی را که هضمش طول میکشد میگیرند میخوابند».
|
||||
|
||||
این را که خواندم، راجع به چیزهایی که تو جنگل اتفاق میافتد کلی فکر کردم و دست آخر توانستم با یک مداد رنگی اولین نقاشیم را از کار درآرم. یعنی نقاشی شمارهی یکم را که این جوری بود:
|
||||
|
||||
نقاشی شمارهی یکم — مار شبیه به کلاه
|
||||
شاهکارم را نشان بزرگتر ها دادم و پرسیدم از دیدنش ترستان بر میدارد؟
|
||||
جوابم دادند: -چرا کلاه باید آدم را بترساند؟
|
||||
|
||||
نقاشی من کلاه نبود، یک مار بوآ بود که داشت یک فیل را هضم میکرد. آن وقت برای فهم بزرگترها برداشتم توی شکم بوآ را کشیدم. آخر همیشه باید به آنها توضیحات داد. نقاشی دومم این جوری بود:
|
||||
|
||||
نقاشی دوم — مار و فیل درونش
|
||||
بزرگترها بم گفتند کشیدن مار بوآی باز یا بسته را بگذارم کنار و عوضش حواسم را بیشتر جمع جغرافی و تاریخ و حساب و دستور زبان کنم. و این جوری شد که تو شش سالگی دور کار ظریف نقاشی را قلم گرفتم. از این که نقاشی شمارهی یک و نقاشی شمارهی دو ام یخشان نگرفت دلسرد شده بودم. بزرگترها اگر به خودشان باشد هیچ وقت نمیتوانند از چیزی سر درآرند. برای بچهها هم خسته کننده است که همین جور مدام هر چیزی را به آنها توضیح بدهند.
|
||||
|
||||
ناچار شدم برای خودم کار دیگری پیدا کنم و این بود که رفتم خلبانی یاد گرفتم. بگویی نگویی تا حالا به همه جای دنیا پرواز کرده ام و راستی راستی جغرافی خیلی بم خدمت کرده. میتوانم به یک نظر چین و آریزونا را از هم تمیز بدهم. اگر آدم تو دل شب سرگردان شده باشد جغرافی خیلی به دادش میرسد.
|
||||
|
||||
از این راه است که من تو زندگیم با گروه گروه آدمهای حسابی برخورد داشتهام. پیش خیلی از بزرگترها زندگی کردهام و آنها را از خیلی نزدیک دیدهام گیرم این موضوع باعث نشده در بارهی آنها عقیدهی بهتری پیدا کنم.
|
||||
|
||||
هر وقت یکیشان را گیر آوردهام که یک خرده روشن بین به نظرم آمده با نقاشی شمارهی یکم که هنوز هم دارمش محکش زدهام ببینم راستی راستی چیزی بارش هست یا نه. اما او هم طبق معمول در جوابم در آمده که: «این یک کلاه است». آن وقت دیگر من هم نه از مارهای بوآ باش اختلاط کردهام نه از جنگلهای بکر دست نخورده نه از ستارهها. خودم را تا حد او آوردهام پایین و باش از بریج و گلف و سیاست و انواع کرات حرف زدهام. او هم از این که با یک چنین شخص معقولی آشنایی به هم رسانده سخت خوشوقت شده.
|
||||
|
||||
۲
|
||||
این جوری بود که روزگارم تو تنهایی میگذشت بی این که راستی راستی یکی را داشته باشم که باش دو کلمه حرف بزنم، تااین که زد و شش سال پیش در کویر صحرا حادثهیی برایم اتفاق افتاد؛ یک چیز موتور هواپیمایم شکسته بود و چون نه تعمیرکاری همراهم بود نه مسافری یکه و تنها دست به کار شدم تا از پس چنان تعمیر مشکلی برآیم. مسالهی مرگ و زندگی بود. آبی که داشتم زورکی هشت روز را کفاف میداد.
|
||||
|
||||
شب اول را هزار میل دورتر از هر آبادی مسکونی رو ماسهها به روز آوردم پرت افتادهتر از هر کشتی شکستهیی که وسط اقیانوس به تخته پارهیی چسبیده باشد. پس لابد میتوانید حدس بزنید چه جور هاج و واج ماندم وقتی کلهی آفتاب به شنیدن صدای ظریف عجیبی که گفت: «بی زحمت یک برّه برام بکش!» از خواب پریدم.
|
||||
-ها؟
|
||||
-یک برّه برام بکش...
|
||||
|
||||
چنان از جا جستم که انگار صاعقه بم زده. خوب که چشمهام را مالیدم و نگاه کردم آدم کوچولوی بسیار عجیبی را دیدم که با وقار تمام تو نخ من بود. این بهترین شکلی است که بعد ها توانستم از او در آرم، گیرم البته آنچه من کشیدهام کجا و خود او کجا! تقصیر من چیست؟ بزرگتر ها تو شش سالگی از نقاشی دلسردم کردند و جز بوآی باز و بسته یاد نگرفتم چیزی بکشم.
|
||||
|
||||
با چشمهایی که از تعجب گرد شده بود به این حضور ناگهانی خیره شدم. یادتان نرود که من از نزدیکترین آبادی مسکونی هزار میل فاصله داشتم و این آدمیزاد کوچولوی من هم اصلا به نظر نمیآمد که راه گم کرده باشد یا از خستگی دم مرگ باشد یا از گشنگی دم مرگ باشد یا از تشنگی دم مرگ باشد یا از وحشت دم مرگ باشد. هیچ چیزش به بچهیی نمیبُرد که هزار میل دور از هر آبادی مسکونی تو دل صحرا گم شده باشد.
|
||||
|
||||
این بهترین شکلی است که بعدها از او در آوردم.
|
||||
وقتی بالاخره صدام در آمد، گفتم:
|
||||
-آخه... تو این جا چه میکنی؟
|
||||
و آن وقت او خیلی آرام، مثل یک چیز خیلی جدی، دوباره در آمد که:
|
||||
-بی زحمت واسهی من یک برّه بکش.
|
||||
آدم وقتی تحت تاثیر شدید رازی قرار گرفت جرات نافرمانی نمیکند. گرچه تو آن نقطهی هزار میل دورتر از هر آبادی مسکونی و با قرار داشتن در معرض خطر مرگ این نکته در نظرم بی معنی جلوه کرد باز کاغذ و خودنویسی از جیبم در آوردم اما تازه یادم آمد که آنچه من یاد گرفتهام بیشتر جغرافیا و تاریخ و حساب و دستور زبان است، و با کج خلقی مختصری به آن موجود کوچولو گفتم نقاشی بلد نیستم.
|
||||
بم جواب داد: -عیب ندارد، یک بَرّه برام بکش.
|
||||
|
||||
از آنجایی که هیچ وقت تو عمرم بَرّه نکشیده بودم یکی از آن دو تا نقاشیای را که بلد بودم برایش کشیدم. آن بوآی بسته را. ولی چه یکهای خوردم وقتی آن موجود کوچولو در آمد که: -نه! نه! فیلِ تو شکم یک بوآ نمیخواهم. بوآ خیلی خطرناک است فیل جا تنگ کن. خانهی من خیلی کوچولوست، من یک بره لازم دارم. برام یک بره بکش.برهی مریض
|
||||
-خب، کشیدم.
|
||||
با دقت نگاهش کرد و گفت:
|
||||
-نه! این که همین حالاش هم حسابی مریض است. یکی دیگر بکش.قوچ
|
||||
-کشیدم.
|
||||
لبخند با نمکی زد و در نهایت گذشت گفت:
|
||||
-خودت که میبینی... این بره نیست، قوچ است. شاخ دارد نه...برهی پیر
|
||||
باز نقاشی را عوض کردم.
|
||||
آن را هم مثل قبلی ها رد کرد:
|
||||
-این یکی خیلی پیر است... من یک بره میخواهم که مدت ها عمر کند...
|
||||
|
||||
باری چون عجله داشتم که موتورم را پیاده کنم رو بی حوصلگی جعبهای کشیدم که دیوارهاش سه تا سوراخ داشت، و از دهنم پرید که:جعبه
|
||||
-این یک جعبه است. برهای که میخواهی این تو است.
|
||||
|
||||
و چه قدر تعجب کردم از این که دیدم داور کوچولوی من قیافهاش از هم باز شد و گفت:
|
||||
-آها... این درست همان چیزی است که میخواستم! فکر میکنی این بره خیلی علف بخواهد؟
|
||||
-چطور مگر؟
|
||||
-آخر جای من خیلی تنگ است...
|
||||
-هر چه باشد حتماً بسش است. برهیی که بت دادهام خیلی کوچولوست.
|
||||
-آن قدرهاهم کوچولو نیست... اِه! گرفته خوابیده...
|
||||
|
||||
و این جوری بود که من با شهریار کوچولو آشنا شدم.
|
||||
|
||||
۳
|
||||
خیلی طول کشید تا توانستم بفهمم از کجا آمده. شهریار کوچولو که مدام مرا سوال پیچ میکرد خودش انگار هیچ وقت سوالهای مرا نمیشنید. فقط چیزهایی که جسته گریخته از دهنش میپرید کم کم همه چیز را به من آشکار کرد. مثلا اول بار که هواپیمای مرا دید (راستی من هواپیما نقاشی نمیکنم، سختم است.) ازم پرسید:
|
||||
-این چیز چیه؟
|
||||
-این «چیز» نیست: این پرواز میکند. هواپیماست. هواپیمای من است.
|
||||
|
||||
و از این که بهاش میفهماندم من کسیام که پرواز میکنم به خود میبالیدم.
|
||||
حیرت زده گفت: -چی؟ تو از آسمان افتادهای؟
|
||||
با فروتنی گفتم: -آره.
|
||||
گفت: -اوه، این دیگر خیلی عجیب است!
|
||||
و چنان قهقههی ملوسی سر داد که مرا حسابی از جا در برد. راستش من دلم میخواهد دیگران گرفتاریهایم را جدی بگیرند.
|
||||
خندههایش را که کرد گفت: -خب، پس تو هم از آسمان میآیی! اهل کدام سیارهای؟...
|
||||
|
||||
بفهمی نفهمی نور مبهمی به معمای حضورش تابید. یکهو پرسیدم:
|
||||
-پس تو از یک سیارهی دیگر آمدهای؟
|
||||
آرام سرش را تکان داد بی این که چشم از هواپیما بردارد.
|
||||
|
||||
اما جوابم را نداد، تو نخ هواپیما رفته بود و آرام آرام سر تکان میداد.
|
||||
گفت: -هر چه باشد با این نباید از جای خیلی دوری آمده باشی...
|
||||
|
||||
مدت درازی تو خیال فرو رفت، بعد برهاش را از جیب در آورد و محو تماشای آن گنج گرانبها شد.تصویری از شهریار کوچولو بر روی زمین
|
||||
فکر میکنید از این نیمچه اعتراف «سیارهی دیگر»ِ او چه هیجانی به من دست داد؟ زیر پاش نشستم که حرف بیشتری از زبانش بکشم:
|
||||
-تو از کجا میآیی آقا کوچولوی من؟ خانهات کجاست؟ برهی مرا میخواهی کجا ببری؟
|
||||
مدتی در سکوت به فکر فرورفت و بعد در جوابم گفت:
|
||||
-حسن جعبهای که بم دادهای این است که شبها میتواند خانهاش بشود.
|
||||
-معلوم است... اما اگر بچهی خوبی باشی یک ریسمان هم بِت میدهم که روزها ببندیش. یک ریسمان با یک میخ طویله...
|
||||
انگار از پیشنهادم جا خورد، چون که گفت:
|
||||
-ببندمش؟ چه فکر ها!
|
||||
-آخر اگر نبندیش راه میافتد میرود گم میشود.
|
||||
|
||||
دوست کوچولوی من دوباره غش غش خنده را سر داد:
|
||||
-مگر کجا میتواند برود؟
|
||||
-خدا میداند. راستِ شکمش را میگیرد و میرود...
|
||||
-بگذار برود...اوه، خانهی من آنقدر کوچک است!
|
||||
و شاید با یک خرده اندوه در آمد که:
|
||||
-یکراست هم که بگیرد برود جای دوری نمیرود...
|
||||
|
||||
۴
|
||||
به این ترتیب از یک موضوع خیلی مهم دیگر هم سر در آوردم: این که سیارهی او کمی از یک خانهی معمولی بزرگتر بود.این نکته آنقدرها به حیرتم نینداخت. میدانستم گذشته از سیارههای بزرگی مثل زمین و کیوان و تیر و ناهید که هرکدام برای خودشان اسمی دارند، صدها سیارهی دیگر هم هست که بعضیشان از بس کوچکند با دوربین نجومی هم به هزار زحمت دیده میشوند و هرگاه اخترشناسی یکیشان را کشف کند به جای اسم شمارهای بهاش میدهد. مثلا اسمش را میگذارد «اخترک ۳۲۵۱».
|
||||
|
||||
دلایل قاطعی دارم که ثابت میکند شهریار کوچولو از اخترک ب۶۱۲ آمدهبود.
|
||||
|
||||
شهریار کوچولو بر اخترکِ ب۶۱۲
|
||||
این اخترک را فقط یک بار به سال ۱۹۰۹ یک اخترشناس ترک توانسته بود ببیند اخترشناسِ ترک در حالِ دیدنِ اخترکِ ب۶۱۲که تو یک کنگرهی بینالمللی نجوم هم با کشفش هیاهوی زیادی به راه انداخت اما واسه خاطر لباسی که تنش بود هیچ کس حرفش را باور نکرد. اخترشناسِ ترک در کنگرهی بینالمللیِ نجوم، با لباس قدیمیآدم بزرگها این جوریاند!
|
||||
|
||||
بختِ اخترک ب۶۱۲ زد و، ترک مستبدی ملتش را به ضرب دگنک وادار به پوشیدن لباس اروپاییها کرد. اخترشناس به سال ۱۹۲۰ دوباره، و این بار با سر و وضع آراسته برای کشفش ارائهی دلیل کرد و این بار همه جانب او را گرفتند.اخترشناسِ ترک در کنگرهی بینالمللیِ نجوم، با لباس جدید
|
||||
به خاطر آدم بزرگهاست که من این جزئیات را در باب اخترکِ ب۶۱۲ برایتان نقل میکنم یا شمارهاش را میگویم چون که آنها عاشق عدد و رقماند. وقتی با آنها از یک دوست تازهتان حرف بزنید هیچ وقت ازتان دربارهی چیزهای اساسیاش سوال نمیکنند که هیج وقت نمیپرسند «آهنگ صداش چهطور است؟ چه بازیهایی را بیشتر دوست دارد؟ پروانه جمع میکند یا نه؟» -میپرسند: «چند سالش است؟ چند تا برادر دارد؟ وزنش چهقدر است؟ پدرش چهقدر حقوق میگیرد؟» و تازه بعد از این سوالها است که خیال میکنند طرف را شناختهاند.
|
||||
|
||||
اگر به آدم بزرگها بگویید یک خانهی قشنگ دیدم از آجر قرمز که جلو پنجرههاش غرقِ شمعدانی و بامش پر از کبوتر بود محال است بتوانند مجسمش کنند. باید حتماً بهشان گفت یک خانهی صد میلیون تومنی دیدم تا صداشان بلند بشود که: -وای چه قشنگ!
|
||||
|
||||
یا مثلا اگر بهشان بگویید «دلیل وجودِ شهریارِ کوچولو این که تودلبرو بود و میخندید و دلش یک بره میخواست و بره خواستن، خودش بهترین دلیل وجود داشتن هر کسی است» شانه بالا میاندازند و باتان مثل بچهها رفتار میکنند! اما اگر بهشان بگویید «سیارهای که ازش آمدهبود اخترک ب۶۱۲ است» بیمعطلی قبول میکنند و دیگر هزار جور چیز ازتان نمیپرسند. این جوریاند دیگر. نباید ازشان دلخور شد. بچهها باید نسبت به آدم بزرگها گذشت داشته باشند.
|
||||
|
||||
اما البته ماها که مفهوم حقیقی زندگی را درک میکنیم میخندیم به ریش هرچه عدد و رقم است! چیزی که من دلم میخواست این بود که این ماجرا را مثل قصهی پریا نقل کنم. دلم میخواست بگویم: «یکی بود یکی نبود. روزی روزگاری یه شهریار کوچولو بود که تو اخترکی زندگی میکرد همهاش یه خورده از خودش بزرگتر و واسه خودش پیِ دوستِ همزبونی میگشت...»، آن هایی که مفهوم حقیقی زندگی را درک کردهاند واقعیت قضیه را با این لحن بیشتر حس میکنند. آخر من دوست ندارم کسی کتابم را سرسری بخواند. خدا میداند با نقل این خاطرات چه بار غمی روی دلم مینشیند. شش سالی میشود که دوستم با بَرّهاش رفته. این که این جا میکوشم او را وصف کنم برای آن است که از خاطرم نرود. فراموش کردن یک دوست خیلی غمانگیز است. همه کس که دوستی ندارد. من هم میتوانم مثل آدم بزرگها بشوم که فقط اعداد و ارقام چشمشان را میگیرد. و باز به همین دلیل است که رفتهام یک جعبه رنگ و چند تا مداد خریدهام. تو سن و سال من واسه کسی که جز کشیدنِ یک بوآی باز یا یک بوآی بسته هیچ کار دیگری نکرده -و تازه آن هم در شش سالگی- دوباره به نقاشی رو کردن از آن حرفهاست! البته تا آنجا که بتوانم سعی میکنم چیزهایی که میکشم تا حد ممکن شبیه باشد. گیرم به موفقیت خودم اطمینان چندانی ندارم. یکیش شبیه از آب در میآید یکیش نه. سرِ قدّ و قوارهاش هم حرف است. یک جا زیادی بلند درش آوردهام یک جا زیادی کوتاه. از رنگ لباسش هم مطمئن نیستم. خب، رو حدس و گمان پیش رفتهام؛ کاچی به زِ هیچی. و دست آخر گفته باشم که تو بعضِ جزئیات مهمترش هم دچار اشتباه شدهام. اما در این مورد دیگر باید ببخشید: دوستم زیر بار هیچ جور شرح و توصیفی نمیرفت. شاید مرا هم مثل خودش میپنداشت. اما از بختِ بد، دیدن برهها از پشتِ جعبه از من بر نمیآید. نکند من هم یک خرده به آدم بزرگها رفتهام؟ «باید پیر شده باشم».
|
||||
|
||||
۵
|
||||
هر روزی که میگذشت از اخترک و از فکرِ عزیمت و از سفر و این حرفها چیزهای تازهای دستگیرم میشد که همهاش معلولِ بازتابهایِ اتفاقی بود. و از همین راه بود که روز سوم از ماجرایِ تلخِ بائوباب ها سردرآوردم.
|
||||
|
||||
این بار هم بَرّه باعثش شد، چون شهریار کوچولو که انگار سخت دودل ماندهبود ناگهان ازم پرسید:
|
||||
-بَرّهها بتهها را هم میخورند دیگر، مگر نه؟
|
||||
-آره. همین جور است.
|
||||
-آخ! چه خوشحال شدم!
|
||||
|
||||
نتوانستم بفهمم این موضوع که بَرّهها بوتهها را هم میخورند اهمیتش کجاست اما شهریار کوچولو درآمد که:
|
||||
-پس لابد بائوباب ها را هم میخورند دیگر؟
|
||||
|
||||
یک گله فیل که در اخترکِ ب۶۱۲ روی هم چیده شدهاندمن برایش توضیح دادم که بائوباب بُتّه نیست. درخت است و از ساختمان یک معبد هم گندهتر، و اگر یک گَلّه فیل هم با خودش ببرد حتا یک درخت بائوباب را هم نمیتوانند بخورند.
|
||||
از فکر یک گَلّه فیل به خنده افتاد و گفت: -باید چیدشان روی هم.
|
||||
اما با فرزانگی تمام متذکر شد که: -بائوباب هم از بُتِّگی شروع میکند به بزرگ شدن.
|
||||
-درست است. اما نگفتی چرا دلت میخواهد برههایت نهالهای بائوباب را بخورند؟
|
||||
گفت: -دِ! معلوم است!
|
||||
|
||||
و این را چنان گفت که انگار موضوع از آفتاب هم روشنتر است؛ منتها من برای این که به تنهایی از این راز سر در آرم ناچار شدم حسابی کَلّه را به کار بیندازم.
|
||||
|
||||
راستش این که تو اخترکِ شهریار کوچولو هم مثل سیارات دیگر هم گیاهِ خوب به هم میرسید هم گیاهِ بد. یعنی هم تخمِ خوب گیاههای خوب به هم میرسید، هم تخمِ بدِ گیاههایِ بد. اما تخم گیاهها نامرییاند. آنها تو حرمِ تاریک خاک به خواب میروند تا یکیشان هوس بیدار شدن به سرش بزند. آن وقت کش و قوسی میآید و اول با کم رویی شاخکِ باریکِ خوشگل و بیآزاری به طرف خورشید میدواند. اگر این شاخک شاخکِ تربچهای گلِ سرخی چیزی باشد میشود گذاشت برای خودش رشد کند اما اگر گیاهِ بدی باشد آدم باید به مجردی که دستش را خواند ریشهکنش کند.
|
||||
|
||||
باری، تو سیارهی شهریار کوچولو گیاه تخمههای وحشتناکی به هم میرسید. یعنی تخم درختِ بائوباب که خاکِ سیاره حسابی ازشان لطمه خورده بود. بائوباب هم اگر دیر بهاش برسند دیگر هیچ جور نمیشود حریفش شد: تمام سیاره را میگیرد و با ریشههایش سوراخ سوراخش میکند و اگر سیاره خیلی کوچولو باشد و بائوبابها خیلی زیاد باشند پاک از هم متلاشیش میکنند.
|
||||
|
||||
شهریار کوچولو در حال نظافت ِ اخترکششهریار کوچولو بعدها یک روز به من گفت: «این، یک امر انضباطی است. صبح به صبح بعد از نظافتِ خود باید با دفت تمام به نظافتِ اخترک پرداخت. آدم باید خودش را مجبور کند که به مجردِ تشخیص دادن بائوبابها از بتههای گلِ سرخ که تا کوچولواَند عین هماَند با دقت ریشهکنشان بکند. کار کسلکنندهای هست اما هیچ مشکل نیست.»
|
||||
|
||||
یک روز هم بم توصیه کرد سعی کنم هر جور شده یک نقاشی حسابی از کار درآرم که بتواند قضیه را به بچههای سیارهی من هم حالی کند. گفت اگر یک روز بروند سفر ممکن است به دردشان بخورد. پارهای وقتها پشت گوش انداختن کار ایرادی ندارد اما اگر پای بائوباب در میان باشد گاوِ آدم میزاید. اخترکی را سراغ دارم که یک تنبلباشی ساکنش بود و برای کندن سه تا نهال بائوباب امروز و فردا کرد...».
|
||||
|
||||
آن وقت من با استفاده از چیزهایی که گفت شکل آن اخترک را کشیدم.
|
||||
|
||||
اخترکِ تنبلباشی با سه درختِ بائوباب
|
||||
هیچ دوست ندارم اندرزگویی کنم. اما خطر بائوبابها آنقدر کم شناخته شده و سر راهِ کسی که تو چنان اخترکی سرگیدان بشود آن قدر خطر به کمین نشسته که این مرتبه را از رویهی همیشگی خودم دست بر میدارم و میگویم: «بچهها! هوای بائوبابها را داشته باشید!»
|
||||
|
||||
اگر من سرِ این نقاشی این همه به خودم فشار آوردهام فقط برای آن بوده که دوستانم را متوجه خطری کنم که از مدتها پیش بیخ گوششان بوده و مثلِ خودِ من ازش غافل بودهاند. درسی که با این نقاشی دادهام به زحمتش میارزد. حالا ممکن است شما از خودتان بپرسید: «پس چرا هیچ کدام از بقیهی نقاشیهای این کتاب هیبتِ تصویرِ بائوبابها را ندارد؟» -خب، جوابش خیلی ساده است: من زور خودم را زدهام اما نتوانستهام از کار درشان بیاورم. اما عکس بائوبابها را که میکشیدم احساس میکردم قضیه خیلی فوریت دارد و به این دلیل شور بَرَم داشته بود.
|
||||
|
||||
۶
|
||||
آخ، شهریار کوچولو! این جوری بود که من کَم کَمَک از زندگیِ محدود و دلگیر تو سر درآوردم. تا مدتها تنها سرگرمیِ تو تماشای زیباییِ غروب آفتاب بوده. به این نکتهی تازه صبح روز چهارم بود که پی بردم؛ یعنی وقتی که به من گفتی:
|
||||
-غروب آفتاب را خیلی دوست دارم. برویم فرورفتن آفتاب را تماشا کنیم...شهریار کوچولو در اخترکش مشغولِ تماشای غروبِ آفتاب
|
||||
-هوم، حالاها باید صبر کنی...
|
||||
-واسه چی صبر کنم؟
|
||||
-صبر کنی که آفتاب غروب کند.
|
||||
|
||||
اول سخت حیرت کردی بعد از خودت خندهات گرفت و برگشتی به من گفتی:
|
||||
-همهاش خیال میکنم تو اخترکِ خودمم!
|
||||
-راستش موقعی که تو آمریکا ظهر باشد همه میدانند تو فرانسه تازه آفتاب دارد غروب میکند. کافی است آدم بتواند در یک دقیقه خودش را برساند به فرانسه تا بتواند غروب آفتاب را تماشا کند. متاسفانه فرانسه کجا اینجا کجا! اما رو اخترک تو که به آن کوچکی است همینقدر که چند قدمی صندلیت را جلو بکشی میتوانی هرقدر دلت خواست غروب تماشا کنی.
|
||||
-یک روز چهل و سه بار غروب آفتاب را تماشا کردم!
|
||||
و کمی بعد گفت:
|
||||
-خودت که میدانی... وقتی آدم خیلی دلش گرفته باشد از تماشای غروب لذت میبرد.
|
||||
-پس خدا میداند آن روز چهل و سه غروبه چهقدر دلت گرفته بوده.
|
||||
|
||||
اما مسافر کوچولو جوابم را نداد.
|
||||
|
||||
۷
|
||||
روز پنجم باز سرِ گوسفند از یک راز دیگر زندگی شهریار کوچولو سر در آوردم. مثل چیزی که مدتها تو دلش بهاش فکر کرده باشد یکهو بی مقدمه از من پرسید:
|
||||
-گوسفندی که بُتّه ها را بخورد گل ها را هم میخورد؟
|
||||
-گوسفند هرچه گیرش بیاید میخورد.
|
||||
-حتا گلهایی را هم که خار دارند؟
|
||||
-آره، حتا گلهایی را هم که خار دارند.
|
||||
-پس خارها فایدهشان چیست؟
|
||||
|
||||
من چه میدانستم؟ یکی از آن: سخت گرفتار باز کردن یک مهرهی سفتِ موتور بودم. از این که یواش یواش بو میبردم خرابیِ کار به آن سادگیها هم که خیال میکردم نیست برج زهرمار شدهبودم و ذخیرهی آبم هم که داشت ته میکشید بیشتر به وحشتم میانداخت.
|
||||
-پس خارها فایدهشان چسیت؟
|
||||
|
||||
شهریار کوچولو وقتی سوالی را میکشید وسط دیگر به این مفتیها دست بر نمیداشت. مهره پاک کلافهام کرده بود. همین جور سرسری پراندم که:
|
||||
-خارها به درد هیچ کوفتی نمیخورند. آنها فقط نشانهی بدجنسی گلها هستند.
|
||||
-دِ!
|
||||
و پس از لحظهیی سکوت با یک جور کینه درآمد که:
|
||||
-حرفت را باور نمیکنم! گلها ضعیفند. بی شیلهپیلهاند. سعی میکنند یک جوری تهِ دل خودشان را قرص کنند. این است که خیال میکنند با آن خارها چیزِ ترسناکِ وحشتآوری میشوند...
|
||||
|
||||
لام تا کام بهاش جواب ندادم. در آن لحظه داشتم تو دلم میگفتم: «اگر این مهرهی لعنتی همین جور بخواهد لج کند با یک ضربهی چکش حسابش را میرسم.» اما شهریار کوچولو دوباره افکارم را به هم ریخت:
|
||||
-تو فکر میکنی گلها...
|
||||
من باز همان جور بیتوجه گفتم:
|
||||
-ای داد بیداد! ای داد بیداد! نه، من هیچ کوفتی فکر نمیکنم! آخر من گرفتار هزار مسالهی مهمتر از آنم!
|
||||
هاج و واج نگاهم کرد و گفت:
|
||||
-مسالهی مهم!
|
||||
|
||||
مرا میدید که چکش به دست با دست و بالِ سیاه روی چیزی که خیلی هم به نظرش زشت میآمد خم شدهام.
|
||||
-مثل آدم بزرگها حرف میزنی!
|
||||
از شنیدنِ این حرف خجل شدم اما او همین جور بیرحمانه میگفت:
|
||||
-تو همه چیز را به هم میریزی... همه چیز را قاتی میکنی!
|
||||
حسابی از کوره در رفتهبود.
|
||||
|
||||
موهای طلایی طلائیش تو باد میجنبید.
|
||||
-اخترکی را سراغ دارم که یک آقا سرخ روئه توش زندگی میکند. او هیچ وقت یک گل را بو نکرده، هیچ وقت یک ستارهرا تماشا نکرده هیچ وقت کسی را دوست نداشته هیچ وقت جز جمع زدن عددها کاری نکرده. او هم مثل تو صبح تا شب کارش همین است که بگوید: «من یک آدم مهمم! یک آدم مهمم!» این را بگوید و از غرور به خودش باد کند. اما خیال کرده: او آدم نیست، یک قارچ است!
|
||||
-یک چی؟
|
||||
-یک قارچ!گلِ سرخ
|
||||
حالا دیگر رنگش از فرط خشم مثل گچ سفید شدهبود:
|
||||
-کرورها سال است که گلها خار میسازند و با وجود این کرورها سال است که برّهها گلها را میخورند. آن وقت هیچ مهم نیست آدم بداند پس چرا گلها واسه ساختنِ خارهایی که هیچ وقتِ خدا به هیچ دردی نمیخورند این قدر به خودشان زحمت میدهند؟ جنگ میان برّهها و گلها هیچ مهم نیست؟ این موضوع از آن جمع زدنهای آقا سرخروئهیِ شکمگنده مهمتر و جدیتر نیست؟ اگر من گلی را بشناسم که تو همهی دنیا تک است و جز رو اخترک خودم هیچ جای دیگر پیدا نمیشه و ممکن است یک روز صبح یک برّه کوچولو، مفت و مسلم، بی این که بفهمد چهکار دارد میکند به یک ضرب پاک از میان ببردش چی؟ یعنی این هم هیچ اهمیتی ندارد؟ اگر کسی گلی را دوست داشته باشد که تو کرورها و کرورها ستاره فقط یک دانه ازش هست واسه احساس وشبختی همین قدر بس است که نگاهی به آن همه ستاره بیندازد و با خودش بگوید: «گل من یک جایی میان آن ستارههاست»، اما اگر برّه گل را بخورد برایش مثل این است که یکهو تمام آن ستارهها پِتّی کنند و خاموش بشوند. یعنی این هم هیچ اهمیتی ندارد؟
|
||||
دیگر نتوانست چیزی بگوید و ناگهان هِق هِق کنان زد زیر گریه.
|
||||
|
||||
حالا دیگر شب شدهبود. اسباب و ابزارم را کنار انداختهبودم. دیگر چکش و مهره و تشنگی و مرگ به نظرم مضحک میآمد. رو ستارهای، رو سیارهای، رو سیارهی من، زمین، شهریارِ کوچولویی بود که احتیاج به دلداری داشت! به آغوشش گرفتم مثل گهواره تابش دادم بهاش گفتم: «گلی که تو دوست داری تو خطر نیست. خودم واسه گوسفندت یک پوزهبند میکشم... خودم واسه گفت یک تجیر میکشم... خودم...» بیش از این نمیدانستم چه بگویم. خودم را سخت چُلمَن و بی دست و پا حس میکردم. نمیدانستم چهطور باید خودم را بهاش برسانم یا بهاش بپیوندم...p چه دیار اسرارآمیزی است دیار اشک!
|
||||
|
||||
۸
|
||||
راه شناختن آن گل را خیلی زود پیدا کردم:
|
||||
تو اخترکِ شهریار کوچولو همیشه یک مشت گلهای خیلی ساده در میآمده. گلهایی با یک ردیف گلبرگ که جای چندانی نمیگرفته، دست و پاگیرِ کسی نمیشده. صبحی سر و کلهشان میان علفها پیدا میشده شب از میان میرفتهاند. اما این یکی یک روز از دانهای جوانه زده بود که خدا میدانست از کجا آمده رود و شهریار کوچولو با جان و دل از این شاخکِ نازکی که به هیچ کدام از شاخکهای دیگر نمیرفت مواظبت کردهبود. بعید بنود که این هم نوعِ تازهای از بائوباب باشد اما بته خیلی زود از رشد بازماند و دستبهکارِ آوردن گل شد. شهریار کوچولو که موقعِ نیش زدن آن غنچهی بزرگ حاضر و ناظر بود به دلش افتاد که باید چیز معجزهآسایی از آن بیرون بیاید. اما گل تو پناهِ خوابگاهِ سبزش سر فرصت دست اندکار خودآرایی بود تا هرچه زیباتر جلوهکند. رنگهایش را با وسواس تمام انتخاب میکرد سر صبر لباس میپوشید و گلبرگها را یکی یکی به خودش میبست. دلش نمیخواست مثل شقایقها با جامهی مچاله و پر چروک بیرون بیاید.
|
||||
|
||||
شهریار کوچولو و گلِ سرخنمیخواست جز در اوج درخشندگی زیبائیش رو نشان بدهد!...
|
||||
|
||||
هوه، بله عشوهگری تمام عیار بود! آرایشِ پر راز و رمزش روزها و روزها طول کشید تا آن که سرانجام یک روز صبح درست با بر آمدن آفتاب نقاب از چهره برداشت و با این که با آن همه دقت و ظرافت روی آرایش و پیرایش خودش کار کرده بود خمیازهکشان گفت:
|
||||
-اوه، تازه همین حالا از خواب پا شدهام... عذر میخواهم که موهام این جور آشفتهاست...
|
||||
|
||||
شهریار کوچولو نتوانست جلو خودش را بگیرد و از ستایش او خودداری کند:
|
||||
-وای چهقدر زیبائید!
|
||||
گل به نرمی گفت:
|
||||
-چرا که نه؟ من و آفتاب تو یک لحظه به دنیا آمدیم...
|
||||
شهریار کوچولو شستش خبردار شد که طرف آنقدرها هم اهل شکستهنفسی نیست اما راستی که چهقدر هیجان انگیز بود!
|
||||
-به نظرم وقت خوردن ناشتایی است. بی زحمت برایم فکری بکنید.
|
||||
و شهریار کوچولوی مشوش و در هم یک آبپاش آب خنک آورده به گل دادهبود.شهریار کوچولو در حالِ تماشای گلِ سرخ
|
||||
با این حساب، هنوزهیچی نشده با آن خودپسندیش که بفهمینفهمی از ضعفش آب میخورد دل او را شکسته بود. مثلا یک روز که داشت راجع به چهارتا خارش حرف میزد یکهو در آمده بود که:ببر و گلِ سرخ
|
||||
-نکند ببرها با آن چنگالهای تیزشان بیایند سراغم!
|
||||
شهریار کوچولو ازش ایراد گرفتهبود که:
|
||||
-تو اخترک من ببر به هم نمیرسد. تازه ببرها که علفخوار نیستند.
|
||||
گل به گلایه جواب داده بود:
|
||||
-من که علف نیستم.
|
||||
و شهریار کوچولو گفته بود:
|
||||
-عذر میخواهم...
|
||||
-من از ببرها هیچ ترسی ندارم اما از جریان هوا وحشت میکنم. تو دستگاهتان تجیر به هم نمیرسد؟شهریار کوچولو در حالِ پوشاندنِ گلِ سرخ
|
||||
شهریار کوچولو تو دلش گفت: «وحشت از جریان هوا... این که واسه یک گیاه تعریفی ندارد... چه مرموز است این گل!»
|
||||
-شب مرا بگذارید زیر یک سرپوش. این جا هواش خیلی سرد است. چه جای بدی افتادم! جایی که پیش از این بودم...شهریار کوچولو در حالِ گذاشتنِ سرپوش روی گلِ سرخ
|
||||
اما حرفش را خورده بود. آخر، آمدنا هنوز به شکل دانه بود. امکان نداشت توانستهباشد دنیاهای دیگری را بشناسد. شرمسار از این که گذاشته بود سر به هم بافتن دروغی به این آشکاری مچش گیربیفتد دو سه بار سرفه کرده بود تا اهمالِ شهریار کوچولو را بهاش یادآور شود:
|
||||
-تجیر کو پس؟
|
||||
-داشتم میرفتم اما شما داشتید صحبت میکردید!
|
||||
و با وجود این زورکی بنا کردهبود به سرفه کردن تا او احساس پشیمانی کند.
|
||||
|
||||
به این ترتیب شهریار کوچولو با همهی حسن نیّتی که از عشقش آب میخورد همان اول کار به او بد گمان شدهبود. حرفهای بی سر و تهش را جدی گرفتهبود و سخت احساس شوربختی میکرد.
|
||||
|
||||
یک روز دردِدل کنان به من گفت: -حقش بود به حرفهاش گوش نمیدادم. هیچ وقت نباید به حرف گلها گوش داد. گل را فقط باید بوئید و تماشا کرد. گلِ من تمامِ اخترکم را معطر میکرد گیرم من بلد نبودم چهجوری از آن لذت ببرم. قضیهی چنگالهای ببر که آن جور دَمَغم کردهبود میبایست دلم را نرم کرده باشد...»
|
||||
|
||||
یک روز دیگر هم به من گفت: «آن روزها نتوانستم چیزی بفهمم. من بایست روی کرد و کارِ او در بارهاش قضاوت میکردم نه روی گفتارش... عطرآگینم میکرد. دلم را روشن میکرد. نمیبایست ازش بگریزم. میبایست به مهر و محبتی که پشتِ آن کلکهای معصومانهاش پنهان بود پی میبردم. گلها پُرَند از این جور تضادها. اما خب دیگر، من خامتر از آن بودم که راهِ دوست داشتنش را بدانم!».
|
||||
|
||||
۹
|
||||
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرندههای وحشی استفاده کرد.
|
||||
|
||||
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرندههای وحشی استفاده کرد.
|
||||
صبح روز حرکت، اخترکش را آن جور که باید مرتب کرد، آتشفشانهای فعالش را با دقت پاک و دودهگیری کرد: شهریار کوچولو در حالِ پاک کردنِ آتشفشان.دو تا آتشفشان فعال داشت که برای گرم کردن ناشتایی خیلی خوب بود. یک آتشفشان خاموش هم داشت. منتها به قول خودش «آدم کف دستش را که بو نکرده!» این بود که آتشفشان خاموش را هم پاک کرد. آتشفشان که پاک باشد مرتب و یک هوا میسوزد و یکهو گُر نمیزند. آتشفشان هم عینهو بخاری یکهو اَلُو میزند. البته ما رو سیارهمان زمین کوچکتر از آن هستیم که آتشفشانهامان را پاک و دودهگیری کنیم و برای همین است که گاهی آن جور اسباب زحمتمان میشوند.
|
||||
|
||||
شهریار کوچولو با دلِگرفته آخرین نهالهای بائوباب را هم ریشهکن کرد. فکر میکرد دیگر هیچ وقت نباید برگردد. اما آن روز صبح گرچه از این کارهای معمولیِ هر روزه کُلّی لذت برد موقعی که آخرین آب را پای گل داد و خواست بگذاردش زیرِ سرپوش چیزی نماندهبود که اشکش سرازیر شود.
|
||||
به گل گفت: -خدا نگهدار!
|
||||
اما او جوابش را نداد.
|
||||
دوباره گفت: -خدا نگهدار!
|
||||
گل سرفهکرد، گیرم این سرفه اثر چائیدن نبود. بالاخره به زبان آمد و گفت:
|
||||
-من سبک مغز بودم. ازت عذر میخواهم. سعی کن خوشبخت باشی.
|
||||
از این که به سرکوفت و سرزنشهای همیشگی برنخورد حیرت کرد و سرپوش به دست هاجوواج ماند. از این محبتِ آرام سر در نمیآورد.
|
||||
گل بهاش گفت: -خب دیگر، دوستت دارم. اگر تو روحت هم از این موضوع خبردار نشد تقصیر من است. باشد، زیاد مهم نیست. اما تو هم مثل من بیعقل بودی... سعی کن خوشبخت بشوی... این سرپوش را هم بگذار کنار، دیگر به دردم نمیخورد.
|
||||
-آخر، باد...
|
||||
-آن قدرهاهم سَرمائو نیستم... هوای خنک شب برای سلامتیم خوب است. خدانکرده گُلم آخر.
|
||||
-آخر حیوانات...
|
||||
-اگر خواستهباشم با شبپرهها آشنا بشوم جز این که دو سه تا کرمِ حشره را تحمل کنم چارهای ندارم. شبپره باید خیلی قشنگ باشد. جز آن کی به دیدنم میآید؟ تو که میروی به آن دور دورها. از بابتِ درندهها هم هیچ کَکَم نمیگزد: «من هم برای خودم چنگ و پنجهای دارم».
|
||||
و با سادگی تمام چهارتا خارش را نشان داد. بعد گفت:
|
||||
-دستدست نکن دیگر! این کارت خلق آدم را تنگ میکند. حالا که تصمیم گرفتهای بروی برو!
|
||||
|
||||
و این را گفت، چون که نمیخواست شهریار کوچولو گریهاش را ببیند. گلی بود تا این حد خودپسند...
|
||||
|
||||
۱۰
|
||||
خودش را در منطقهی اخترکهای ۳۲۵، ۳۲۶، ۳۲۷، ۳۲۸، ۳۲۹ و ۳۳۰ دید. این بود که هم برای سرگرمی و هم برای چیزیادگرفتن بنا کرد یکییکیشان را سیاحت کردن.
|
||||
|
||||
اخترکِ اول مسکن پادشاهی بود که با شنلی از مخمل ارغوانی قاقم بر اورنگی بسیار ساده و در عین حال پرشکوه نشسته بود و همین که چشمش به شهریار کوچولو افتاد داد زد:
|
||||
-خب، این هم رعیت!
|
||||
شهریار کوچولو از خودش پرسید: -او که تا حالا هیچ وقت مرا ندیده چه جوری میتواند بشناسدم؟
|
||||
دیگر اینش را نخواندهبود که دنیابرای پادشاهان به نحو عجیبی ساده شده و تمام مردم فقط یک مشت رعیت به حساب میآیند.
|
||||
|
||||
پادشاه در سیارهاش
|
||||
پادشاه که میدید بالاخره شاهِ کسی شده و از این بابت کبکش خروس میخواند گفت: -بیا جلو بهتر ببینیمت. شهریار کوچولو با چشم پیِ جایی گشت که بنشیند اما شنلِ قاقمِ حضرتِ پادشاهی تمام اخترک را دربرگرفتهبود. ناچار همان طور سر پا ماند و چون سخت خسته بود به دهندره افتاد.
|
||||
شاه بهاش گفت: -خمیازه کشیدن در حضرتِ سلطان از نزاکت به دور است. این کار را برایت قدغن میکنم. شهریار کوچولو که سخت خجل شدهبود در آمد که:
|
||||
-نمیتوانم جلوِ خودم را بگیرم. راه درازی طیکردهام و هیچ هم نخوابیدهام...
|
||||
پادشاه گفت: -خب خب، پس بِت امر میکنم خمیازه بکشی. سالهاست خمیازهکشیدن کسی را ندیدهام برایم تازگی دارد. یاالله باز هم خمیازه بکش. این یک امر است.
|
||||
شهریار کوچولو گفت: -آخر این جوری من دست و پایم را گم میکنم... دیگر نمیتوانم.
|
||||
شاه گفت: -هوم! هوم! خب، پس من بهات امر میکنم که گاهی خمیازه بکشی گاهی نه.
|
||||
تند و نامفهوم حرف میزد و انگار خلقش حسابی تنگ بود.
|
||||
|
||||
پادشاه فقط دربند این بود که مطیع فرمانش باشند. در مورد نافرمانیها هم هیچ نرمشی از خودش نشان نمیداد. یک پادشاهِ تمام عیار بود گیرم چون زیادی خوب بود اوامری که صادر میکرد اوامری بود منطقی. مثلا خیلی راحت در آمد که: «اگر من به یکی از سردارانم امر کنم تبدیل به یکی از این مرغهای دریایی بشود و یارو اطاعت نکند تقسیر او نیست که، تقصیر خودم است».
|
||||
شهریار کوچولو در نهایت ادب پرسید: -اجازه میفرمایید بنشینم؟
|
||||
پادشاه که در نهایتِ شکوه و جلال چینی از شنل قاقمش را جمع میکرد گفت: -بهات امر میکنیم بنشینی.
|
||||
|
||||
منتها شهریار کوچولو ماندهبود حیران: آخر آن اخترک کوچکتر از آن بود که تصورش را بشود کرد. واقعا این پادشاه به چی سلطنت میکرد؟ گفت: -قربان عفو میفرمایید که ازتان سوال میکنم...
|
||||
پادشاه با عجله گفت: -بهات امر میکنیم از ما سوال کنی.
|
||||
-شما قربان به چی سلطنت میفرمایید؟
|
||||
پادشاه خیلی ساده گفت: -به همه چی.
|
||||
-به همهچی؟
|
||||
پادشاه با حرکتی قاطع به اخترک خودش و اخترکهای دیگر و باقی ستارهها اشاره کرد.
|
||||
شهریار کوچولو پرسید: -یعنی به همهی این ها؟
|
||||
شاه جواب داد: -به همهی این ها.
|
||||
آخر او فقط یک پادشاه معمولی نبود که، یک پادشاهِ جهانی بود.
|
||||
-آن وقت ستارهها هم سربهفرمانتانند؟
|
||||
پادشاه گفت: -البته که هستند. همهشان بیدرنگ هر فرمانی را اطاعت میکنند. ما نافرمانی را مطلقا تحمل نمیکنیم.
|
||||
|
||||
یک چنین قدرتی شهریار کوچولو را به شدت متعجب کرد. اگر خودش چنین قدرتی میداشت بی این که حتا صندلیش را یک ذره تکان بدهد روزی چهل و چهار بار که هیچ روزی هفتاد بار و حتا صدبار و دویستبار غروب آفتاب را تماشا میکرد! و چون بفهمی نفهمی از یادآوریِ اخترکش که به امان خدا ولکردهبود غصهاش شد جراتی به خودش داد که از پادشاه درخواست محبتی بکند:
|
||||
-دلم میخواست یک غروب آفتاب تماشا کنم... در حقم التفات بفرمایید امر کنید خورشید غروب کند.
|
||||
-اگر ما به یک سردار امر کنیم مثل شبپره از این گل به آن گل بپرد یا قصهی سوزناکی بنویسد یا به شکل مرغ دریایی در آید و او امریه را اجرا نکند کدام یکیمان مقصریم، ما یا او؟
|
||||
شهریار کوچولو نه گذاشت، نه برداشت، گفت: -شما.
|
||||
پادشاه گفت: -حرف ندارد. باید از هر کسی چیزی را توقع داشت که ازش ساخته باشد. قدرت باید پیش از هر چیز به عقل متکی باشد. اگر تو به ملتت فرمان بدهی که بروند خودشان را بیندازند تو دریا انقلاب میکنند. حق داریم توقع اطاعت داشته باشیم چون اوامرمان عاقلانه است.
|
||||
شهریار کوچولو که هیچ وقت چیزی را که پرسیده بود فراموش نمیکرد گفت: -غروب آفتاب من چی؟
|
||||
-تو هم به غروب آفتابت میرسی. امریهاش را صادر میکنیم. منتها با شَمِّ حکمرانیمان منتظریم زمینهاش فراهم بشود.
|
||||
شهریار کوچولو پرسید: -کِی فراهم میشود؟
|
||||
پادشاه بعد از آن که تقویم کَت و کلفتی را نگاه کرد جواب داد:
|
||||
-هوم! هوم! حدودِ... حدودِ... غروب. حدودِ ساعت هفت و چهل دقیقه... و آن وقت تو با چشمهای خودت میبینی که چهطور فرمان ما اجرا میشود!
|
||||
|
||||
شهریار کوچولو خمیازه کشید. از این که تماشای آفتاب غروب از کیسهاش رفتهبود تاسف میخورد. از آن گذشته دلش هم کمی گرفتهبود. این بود که به پادشاه گفت:
|
||||
-من دیگر اینجا کاری ندارم. میخواهم بروم.
|
||||
شاه که دلش برای داشتن یک رعیت غنج میزد گفت:
|
||||
-نرو! نرو! وزیرت میکنیم.
|
||||
-وزیرِ چی؟
|
||||
-وزیرِ دادگستری!
|
||||
-آخر این جا کسی نیست که محاکمه بشود.
|
||||
پادشاه گفت: -معلوم نیست. ما که هنوز گشتی دور قلمرومان نزدهایم. خیلی پیر شدهایم، برای کالسکه جا نداریم. پیادهروی هم خستهمان میکند.
|
||||
شهریار کوچولو که خم شدهبود تا نگاهی هم به آن طرف اخترک بیندازد گفت: -بَه! من نگاه کردهام، آن طرف هم دیارالبشری نیست.
|
||||
پادشاه بهاش جواب داد: -خب، پس خودت را محاکمه کن. این کار مشکلتر هم هست. محاکمه کردن خود از محاکمهکردن دیگران خیلی مشکل تر است. اگر توانستی در مورد خودت قضاوت درستی بکنی معلوم میشود یک فرزانهی تمام عیاری.
|
||||
شهریار کوچولو گفت: -من هر جا باشم میتوانم خودم را محاکمه کنم، چه احتیاجی است این جا بمانم؟ پادشاه گفت: -هوم! هوم! فکر میکنیم یک جایی تو اخترک ما یک موش پیر هست. صدایش را شب ها میشنویم. میتوانی او را به محاکمه بکشی و گاهگاهی هم به اعدام محکومش کنی. در این صورت زندگی او به عدالت تو بستگی پیدا میکند. گیرم تو هر دفعه عفوش میکنی تا همیشه زیر چاق داشته باشیش. آخر یکی بیشتر نیست که.
|
||||
شهریار کوچولو جواب داد: -من از حکم اعدام خوشم نمیآید. فکر میکنم دیگر باید بروم.
|
||||
پادشاه گفت: -نه!
|
||||
|
||||
اما شهریار کوچولو که آمادهی حرکت شده بود و ضمنا هم هیچ دلش نمیخواست اسباب ناراحتی سلطان پیر بشود گفت:
|
||||
-اگر اعلیحضرت مایلند اوامرشان دقیقا اجرا بشود میتوانند فرمان خردمندانهای در مورد بنده صادر بفرمایند. مثلا میتوانند به بنده امر کنند ظرف یک دقیقه راه بیفتم. تصور میکنم زمینهاش هم آماده باشد...
|
||||
چون پادشاه جوابی نداد شهریار کوچولو اول دو دل ماند اما بعد آهی کشید و به راه افتاد.
|
||||
آنوقت پادشاه با شتاب فریاد زد: -سفیر خودمان فرمودیمت!
|
||||
حالت بسیار شکوهمندی داشت.
|
||||
|
||||
شهریار کوچولو همان طور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۱
|
||||
اخترک دوم مسکن آدم خود پسندی بود.
|
||||
خود پسند چشمش که به شهریار کوچولو افتاد از همان دور داد زد: -بهبه! این هم یک ستایشگر که دارد میآید مرا ببیند!
|
||||
|
||||
خودپسند در سیارهاش
|
||||
آخر برای خودپسندها دیگران فقط یک مشت ستایشگرند.
|
||||
شهریار کوچولو گفت: -سلام! چه کلاه عجیب غریبی سرتان گذاشتهاید!
|
||||
خود پسند جواب داد: -مال اظهار تشکر است. منظورم موقعی است که هلهلهی ستایشگرهایم بلند میشود. گیرم متاسفانه تنابندهای گذارش به این طرفها نمیافتد.
|
||||
شهریار کوچولو که چیزی حالیش نشده بود گفت:
|
||||
-چی؟
|
||||
خودپسند گفت: -دستهایت را بزن به هم دیگر.
|
||||
شهریار کوچولو دست زد و خودپسند کلاهش را برداشت و متواضعانه از او تشکر کرد.
|
||||
شهریار کوچولو با خودش گفت: «دیدنِ این تفریحش خیلی بیشتر از دیدنِ پادشاهاست». و دوباره بنا کرد دستزدن و خودپسند با برداشتن کلاه بنا کرد تشکر کردن.
|
||||
|
||||
پس از پنج دقیقهای شهریار کوچولو که از این بازی یکنواخت خسته شده بود پرسید: -چه کار باید کرد که کلاه از سرت بیفتد؟
|
||||
اما خودپسند حرفش را نشنید. آخر آنها جز ستایش خودشان چیزی را نمیشنوند.
|
||||
از شهریار کوچولو پرسید: -تو راستی راستی به من با چشم ستایش و تحسین نگاه میکنی؟
|
||||
-ستایش و تحسین یعنی چه؟
|
||||
-یعنی قبول این که من خوشقیافهترین و خوشپوشترین و ثروتمندترین و باهوشترین مرد این اخترکم.
|
||||
-آخر روی این اخترک که فقط خودتی و کلاهت.
|
||||
-با وجود این ستایشم کن. این لطف را در حق من بکن.
|
||||
شهریار کوچولو نیمچه شانهای بالا انداخت و گفت: -خب، ستایشت کردم. اما آخر واقعا چیِ این برایت جالب است؟
|
||||
|
||||
شهریار کوچولو به راه افتاد و همان طور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۲
|
||||
تو اخترک بعدی میخوارهای مینشست. دیدار کوتاه بود اما شهریار کوچولو را به غم بزرگی فرو برد.
|
||||
|
||||
میخواره در سیارهاش
|
||||
|
||||
به میخواره که صُمبُکم پشت یک مشت بطری خالی و یک مشت بطری پر نشسته بود گفت: -چه کار داری میکنی؟
|
||||
میخواره با لحن غمزدهای جواب داد: -مِی میزنم.
|
||||
شهریار کوچولو پرسید: -مِی میزنی که چی؟
|
||||
میخواره جواب داد: -که فراموش کنم.
|
||||
شهریار کوچولو که حالا دیگر دلش برای او میسوخت پرسید: -چی را فراموش کنی؟
|
||||
میخواره همان طور که سرش را میانداخت پایین گفت: -سر شکستگیم را.
|
||||
شهریار کوچولو که دلش میخواست دردی از او دوا کند پرسید: -سرشکستگی از چی؟
|
||||
میخواره جواب داد: -سرشکستگیِ میخواره بودنم را.
|
||||
این را گفت و قال را کند و به کلی خاموش شد. و شهریار کوچولو مات و مبهوت راهش را گرفت و رفت و همان جور که میرفت تو دلش میگفت: -این آدم بزرگها راستیراستی چهقدر عجیبند!
|
||||
|
||||
۱۳
|
||||
اخترک چهارم اخترک مرد تجارتپیشه بود. این بابا چنان مشغول و گرفتار بود که با ورود شهریار کوچولو حتا سرش را هم بلند نکرد.
|
||||
|
||||
مردِ تجارتپیشه در سیارهاش
|
||||
شهریار کوچولو گفت: -سلام. آتشسیگارتان خاموش شده.
|
||||
-سه و دو میکند پنج. پنج و هفت دوازده و سه پانزده. سلام. پانزده و هفت بیست و دو. بیست و دو و شش بیست و هشت. وقت ندارم روشنش کنم. بیست و شش و پنج سی و یک. اوف! پس جمعش میکند پانصدویک میلیون و ششصد و بیست و دو هزار هفتصد و سی و یک.
|
||||
-پانصد میلیون چی؟
|
||||
-ها؟ هنوز این جایی تو؟ پانصد و یک میلیون چیز. چه میدانم، آن قدر کار سرم ریخته که!... من یک مرد جدی هستم و با حرفهای هشتمننهشاهی سر و کار ندارم!... دو و پنج هفت...
|
||||
شهریار کوچولو که وقتی چیزی میپرسید دیگر تا جوابش را نمیگرفت دست بردار نبود دوباره پرسید:
|
||||
-پانصد و یک میلیون چی؟
|
||||
تاجر پیشه سرش را بلند کرد:
|
||||
-تو این پنجاه و چهار سالی که ساکن این اخترکم همهاش سه بار گرفتار مودماغ شدهام. اولیش بیست و دو سال پیش یک سوسک بود که خدا میداند از کدام جهنم پیدایش شد. صدای وحشتناکی از خودش در میآورد که باعث شد تو یک جمع چهار جا اشتباه کنم. دفعهی دوم یازده سال پیش بود که استخوان درد بیچارهام کرد. من ورزش نمیکنم. وقت یللیتللی هم ندارم. آدمی هستم جدی... این هم بار سومش!... کجا بودم؟ پانصد و یک میلیون و...
|
||||
-این همه میلیون چی؟
|
||||
تاجرپیشه فهمید که نباید امید خلاصی داشته باشد. گفت: -میلیونها از این چیزهای کوچولویی که پارهای وقتها تو هوا دیده میشود.
|
||||
-مگس؟
|
||||
-نه بابا. این چیزهای کوچولوی براق.
|
||||
-زنبور عسل؟
|
||||
-نه بابا! همین چیزهای کوچولوی طلایی که وِلِنگارها را به عالم هپروت میبرد. گیرم من شخصا آدمی هستم جدی که وقتم را صرف خیالبافی نمیکنم.
|
||||
-آها، ستاره؟
|
||||
-خودش است: ستاره.
|
||||
-خب پانصد میلیون ستاره به چه دردت میخورد؟
|
||||
-پانصد و یک میلیون و ششصد و بیست و دو هزار و هفتصد و سی و یکی. من جدیّم و دقیق.
|
||||
-خب، به چه دردت میخورند؟
|
||||
-به چه دردم میخورند؟
|
||||
-ها.
|
||||
-هیچی تصاحبشان میکنم.
|
||||
-ستارهها را؟
|
||||
-آره خب.
|
||||
-آخر من به یک پادشاهی برخوردم که...
|
||||
-پادشاهها تصاحب نمیکنند بلکه بهاش «سلطنت» میکنند. این دو تا با هم خیلی فرق دارد.
|
||||
-خب، حالا تو آنها را تصاحب میکنی که چی بشود؟
|
||||
-که دارا بشوم.
|
||||
-خب دارا شدن به چه کارت میخورد؟
|
||||
-به این کار که، اگر کسی ستارهای پیدا کرد من ازش بخرم.
|
||||
شهریار کوچولو با خودش گفت: «این بابا هم منطقش یک خرده به منطق آن دائمالخمره میبَرَد.» با وجود این باز ازش پرسید:
|
||||
-چه جوری میشود یک ستاره را صاحب شد؟
|
||||
تاجرپیشه بی درنگ با اَخم و تَخم پرسید: -این ستارهها مال کیاند؟
|
||||
-چه میدانم؟ مال هیچ کس.
|
||||
-پس مال منند، چون من اول به این فکر افتادم.
|
||||
-همین کافی است؟
|
||||
-البته که کافی است. اگر تو یک جواهر پیدا کنی که مال هیچ کس نباشد میشود مال تو. اگر جزیرهای کشف کنی که مال هیچ کس نباشد میشود مال تو. اگر فکری به کلهات بزند که تا آن موقع به سر کسی نزده به اسم خودت ثبتش میکنی و میشود مال تو. من هم ستارهها را برای این صاحب شدهام که پیش از من هیچ کس به فکر نیفتاده بود آنها را مالک بشود.
|
||||
شهریار کوچولو گفت: -این ها همهاش درست. منتها چه کارشان میکنی؟
|
||||
تاجر پیشه گفت: -ادارهشان میکنم، همین جور میشمارمشان و میشمارمشان. البته کار مشکلی است ولی خب دیگر، من آدمی هستم بسیار جدی.
|
||||
شهریار کوچولو که هنوز این حرف تو کَتَش نرفتهبود گفت:
|
||||
-اگر من یک شال گردن ابریشمی داشته باشم میتوانم بپیچم دور گردنم با خودم ببرمش. اگر یک گل داشته باشم میتوانم بچینم با خودم ببرمش. اما تو که نمیتوانی ستارهها را بچینی!
|
||||
-نه. اما میتوانم بگذارمشان تو بانک.
|
||||
-اینی که گفتی یعنی چه؟
|
||||
-یعنی این که تعداد ستارههایم را رو یک تکه کاغذ مینویسم میگذارم تو کشو درش را قفل میکنم.
|
||||
-همهاش همین؟
|
||||
-آره همین کافی است.
|
||||
|
||||
شهریار کوچولو فکر کرد «جالب است. یک خرده هم شاعرانه است. اما کاری نیست که آن قدرها جدیش بشود گرفت». آخر تعبیر او از چیزهای جدی با تعبیر آدمهای بزرگ فرق میکرد.
|
||||
باز گفت: -من یک گل دارم که هر روز آبش میدهم. سه تا هم آتشفشان دارم که هفتهای یک بار پاک و دودهگیریشان میکنم. آخر آتشفشان خاموشه را هم پاک میکنم. آدم کفِ دستش را که بو نکرده! رو این حساب، هم برای آتشفشانها و هم برای گل این که من صاحبشان باشم فایده دارد. تو چه فایدهای به حال ستارهها داری؟
|
||||
|
||||
تاجرپیشه دهن باز کرد که جوابی بدهد اما چیزی پیدا نکرد. و شهریار کوچولو راهش را گرفت و رفت و همان جور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۴
|
||||
اخترکِ پنجم چیز غریبی بود. از همهی اخترکهای دیگر کوچکتر بود، یعنی فقط به اندازهی یک فانوس پایهدار و یک فانوسبان جا داشت.
|
||||
|
||||
فانوسبان در حالِ روشن کردنِ فانوس در سیارهاش
|
||||
شهریار کوچولو از این راز سر در نیاورد که یک جا میان آسمان خدا تو اخترکی که نه خانهای روش هست نه آدمی، حکمت وجودی یک فانوس و یک فانوسبان چه میتواند باشد. با وجود این تو دلش گفت:
|
||||
-خیلی احتمال دارد که این بابا عقلش پارهسنگ ببرد. اما به هر حال از پادشاه و خودپسند و تاجرپیشه و مسته کم عقلتر نیست. دست کم کاری که میکند یک معنایی دارد. فانوسش را که روشن میکند عینهو مثل این است که یک ستارهی دیگر یا یک گل به دنیا میآورد و خاموشش که میکند پنداری گل یا ستارهای را میخواباند. سرگرمی زیبایی است و چیزی که زیبا باشد بی گفتوگو مفید هم هست.
|
||||
|
||||
وقتی رو اخترک پایین آمد با ادب فراوان به فانوسبان سلام کرد:
|
||||
-سلام. واسه چی فانوس را خاموش کردی؟
|
||||
-دستور است. صبح به خیر!
|
||||
-دستور چیه؟
|
||||
-این است که فانوسم را خاموش کنم. شب خوش!
|
||||
و دوباره فانوس را روشن کرد.
|
||||
-پس چرا روشنش کردی باز؟
|
||||
فانوسبان جواب داد: -خب دستور است دیگر.
|
||||
شهریار کوچولو گفت: -اصلا سر در نمیارم.
|
||||
فانوسبان گفت: -چیز سر در آوردنییی توش نیست که. دستور دستور است. روز بخیر!
|
||||
و باز فانوس را خاموش کرد.
|
||||
بعد با دستمال شطرنجی قرمزی عرق پیشانیش را خشکاند و گفت:
|
||||
-کار جانفرسایی دارم. پیشتر ها معقول بود: صبح خاموشش میکردم و شب که میشد روشنش میکردم. باقی روز را فرصت داشتم که استراحت کنم و باقی شب را هم میتوانستم بگیرم بخوابم...
|
||||
-بعدش دستور عوض شد؟
|
||||
فانوسبان گفت: -دستور عوض نشد و بدبختی من هم از همین جاست: سیاره سال به سال گردشش تندتر و تندتر شده اما دستور همان جور به قوت خودش باقی مانده است.
|
||||
-خب؟
|
||||
-حالا که سیاره دقیقهای یک بار دور خودش میگردد دیگر من یک ثانیه هم فرصت استراحت ندارم: دقیقهای یک بار فانوس را روشن میکنم یک بار خاموش.
|
||||
-چه عجیب است! تو اخترک تو شبانه روز همهاش یک دقیقه طول میکشد!
|
||||
فانوسبان گفت: -هیچ هم عجیب نیست. الان یک ماه تمام است که ما داریم با هم اختلاط میکنیم.
|
||||
-یک ماه؟
|
||||
-آره. سی دقیقه. سی روز! شب خوش!
|
||||
و دوباره فانوس را روشن کرد.
|
||||
|
||||
شهریار کوچولو به فانوسبان نگاه کرد و حس کرد این مرد را که تا این حد به دستور وفادار است دوست میدارد. یادِ آفتابغروبهایی افتاد که آن وقتها خودش با جابهجا کردن صندلیش دنبال میکرد. برای این که دستی زیر بال دوستش کرده باشد گفت:
|
||||
-میدانی؟ یک راهی بلدم که میتوانی هر وقت دلت بخواهد استراحت کنی.
|
||||
فانوسبان گفت: -آرزوش را دارم.
|
||||
آخر آدم میتواند هم به دستور وفادار بماند هم تنبلی کند.
|
||||
شهریار کوچولو دنبال حرفش را گرفت و گفت:
|
||||
-تو، اخترکت آنقدر کوچولوست که با سه تا شلنگ برداشتن میتوانی یک بار دور بزنیش. اگر آن اندازه که لازم است یواش راه بروی میتوانی کاری کنی که مدام تو آفتاب بمانی. پس هر وقت خواستی استراحت کنی شروع میکنی به راهرفتن... به این ترتیب روز هرقدر که بخواهی برایت کِش میآید.
|
||||
فانوسبان گفت: -این کار گرهی از بدبختی من وا نمیکند. تنها چیزی که تو زندگی آرزویش را دارم یک چرت خواب است.
|
||||
شهریار کوچولو گفت: -این یکی را دیگر باید بگذاری در کوزه.
|
||||
فانوسبان گفت: -آره. باید بگذارمش در کوزه... صبح بخیر!
|
||||
و فانوس را خاموش کرد.
|
||||
|
||||
شهریار کوچولو میان راه با خودش گفت: گرچه آنهای دیگر، یعنی خودپسنده و تاجره اگر این را میدیدند دستش میانداختند و تحقیرش میکردند، هر چه نباشد کار این یکی به نظر من کمتر از کار آنها بیمعنی و مضحک است. شاید به خاطر این که دست کم این یکی به چیزی جز خودش مشغول است.
|
||||
|
||||
از حسرت آهی کشید و همان طور با خودش گفت:
|
||||
-این تنها کسی بود که من میتوانستم باش دوست بشوم. گیرم اخترکش راستی راستی خیلی کوچولو است و دو نفر روش جا نمیگیرند.
|
||||
|
||||
چیزی که جرات اعترافش را نداشت حسرت او بود به این اخترک کوچولویی که، بخصوص، به هزار و چهارصد و چهل بار غروب آفتاب در هر بیست و چهار ساعت برکت پیدا کرده بود.
|
||||
|
||||
۱۵
|
||||
اخترک ششم اخترکی بود ده بار فراختر، و آقاپیرهای توش بود که کتابهای کَتوکلفت مینوشت.
|
||||
|
||||
جغرافیدان در سیارهاش
|
||||
همین که چشمش به شهریار کوچولو افتاد با خودش گفت:
|
||||
-خب، این هم یک کاشف!
|
||||
شهریار کوچولو لب میز نشست و نفس نفس زد. نه این که راه زیادی طی کرده بود؟
|
||||
آقا پیره بهاش گفت: -از کجا میآیی؟
|
||||
شهریار کوچولو گفت: -این کتاب به این کلفتی چی است؟ شما اینجا چهکار میکنید؟
|
||||
آقا پیره گفت: -من جغرافیدانم.
|
||||
-جغرافیدان چه باشد؟
|
||||
-جغرافیدان به دانشمندی میگویند که جای دریاها و رودخانهها و شهرها و کوهها و بیابانها را میداند.
|
||||
شهریار کوچولو گفت: -محشر است. یک کار درست و حسابی است.
|
||||
و به اخترک جغرافیدان، این سو و آنسو نگاهی انداخت. تا آن وقت اخترکی به این عظمت ندیدهبود.
|
||||
-اخترکتان خیلی قشنگ است. اقیانوس هم دارد؟
|
||||
جغرافیدان گفت: -از کجا بدانم؟
|
||||
شهریار کوچولو گفت: -عجب! (بد جوری جا خورده بود) کوه چهطور؟
|
||||
جغرافیدان گفت: -از کجا بدانم؟
|
||||
-شهر، رودخانه، بیابان؟
|
||||
جغرافیدان گفت: از اینها هم خبری ندارم.
|
||||
-آخر شما جغرافیدانید؟
|
||||
جغرافیدان گفت: -درست است ولی کاشف که نیستم. من حتا یک نفر کاشف هم ندارم. کار جغرافیدان نیست که دورهبیفتد برود شهرها و رودخانهها و کوهها و دریاها و اقیانوسها و بیابانها را بشمرد. مقام جغرافیدان برتر از آن است که دوره بیفتد و ولبگردد. اصلا از اتاق کارش پا بیرون نمیگذارد بلکه کاشفها را آن تو میپذیرد ازشان سوالات میکند و از خاطراتشان یادداشت بر میدارد و اگر خاطرات یکی از آنها به نظرش جالب آمد دستور میدهد روی خُلقیات آن کاشف تحقیقاتی صورت بگیرد.
|
||||
-برای چه؟
|
||||
-برای این که اگر کاشفی گندهگو باشد کار کتابهای جغرافیا را به فاجعه میکشاند. هکذا کاشفی که اهل پیاله باشد.
|
||||
-آن دیگر چرا؟
|
||||
b-چون آدمهای دائمالخمر همه چیز را دوتا میبینند. آن وقت جغرافیدان برمیدارد جایی که یک کوه
|
||||
بیشتر نیست مینویسد دو کوه.
|
||||
شهریار کوچولو گفت: -پس من یک بابایی را میشناسم که کاشف هجوی از آب در میآید.
|
||||
-بعید نیست. بنابراین، بعد از آن که کاملا ثابت شد پالان کاشف کج نیست تحقیقاتی هم روی کشفی که کرده انجام میگیرد.
|
||||
-یعنی میروند میبینند؟
|
||||
-نه، این کار گرفتاریش زیاد است. از خود کاشف میخواهند دلیل بیاورد. مثلا اگر پای کشف یک کوه بزرگ در میان بود ازش میخواهند سنگهای گندهای از آن کوه رو کند.
|
||||
جغرافیدان ناگهان به هیجان در آمد و گفت: -راستی تو داری از راه دوری میآیی! تو کاشفی! باید چند و چون اخترکت را برای من بگویی.
|
||||
و با این حرف دفتر و دستکش را باز کرد و مدادش را تراشید. معمولا خاطرات کاشفها را اول بامداد یادداشت میکنند و دست نگه میدارند تا دلیل اقامه کند، آن وقت با جوهر مینویسند.
|
||||
گفت: -خب؟
|
||||
شهریار کوچولو گفت: -اخترک من چیز چندان جالبی ندارد. آخر خیلی کوچک است. سه تا آتشفشان دارم که دوتاش فعال است یکیش خاموش. اما، خب دیگر، آدم کف دستش را که بو نکرده.
|
||||
جغرافیدان هم گفت: -آدم چه میداند چه پیش میآید.
|
||||
-یک گل هم دارم.
|
||||
-نه، نه، ما دیگر گل ها را یادداشت نمیکنیم.
|
||||
-چرا؟ گل که زیباتر است.
|
||||
-برای این که گلها فانیاند.
|
||||
-فانی یعنی چی؟
|
||||
جغرافیدان گفت: -کتابهای جغرافیا از کتابهای دیگر گرانبهاترست و هیچ وقت هم از اعتبار نمیافتد. بسیار به ندرت ممکن است یک کوه جا عوض کند. بسیار به ندرت ممکن است آب یک اقیانوس خالی شود. ما فقط چیزهای پایدار را مینویسیم.
|
||||
شهریار کوچولو تو حرف او دوید و گفت: -اما آتشفشانهای خاموش میتوانند از نو بیدار بشوند. فانی را نگفتید یعنی چه؟
|
||||
جغرافیدان گفت: -آتشفشان چه روشن باشد چه خاموش برای ما فرقی نمیکند. آنچه به حساب میآید خود کوه است که تغییر پیدا نمیکند.
|
||||
شهریار کوچولو که تو تمام عمرش وقتی چیزی از کسی میپرسید دیگر دست بردار نبود دوباره سوال کرد: -فانی یعنی چه؟
|
||||
-یعنی چیزی که در آینده تهدید به نابودی شود.
|
||||
-گل من هم در آینده نابود میشود؟
|
||||
-البته که میشود.
|
||||
شهریار کوچولو در دل گفت: «گل من فانی است و جلو دنیا برای دفاع از خودش جز چهارتا خار هیچی ندارد، و آن وقت مرا بگو که او را توی اخترکم تک و تنها رها کردهام!»
|
||||
این اولین باری بود که دچار پریشانی و اندوه میشد اما توانست به خودش مسلط بشود. پرسید: -شما به من دیدن کجا را توصیه میکنید؟
|
||||
جغرافیدان بهاش جواب داد: -سیارهی زمین. شهرت خوبی دارد...
|
||||
|
||||
و شهریار کوچولو هم چنان که به گلش فکر میکرد به راه افتاد.
|
||||
|
||||
۱۶
|
||||
لاجرم، زمین، سیارهی هفتم شد.
|
||||
|
||||
زمین، فلان و بهمان سیاره نیست. رو پهنهی زمین یکصد و یازده پادشاه (البته بامحاسبهی پادشاهان سیاهپوست)، هفت هزار جغرافیدان، نهصد هزار تاجرپیشه، پانزده کرور میخواره و ششصد و بیست و دو کرور خودپسند و به عبارت دیگر حدود دو میلیارد آدم بزرگ زندگی میکند. برای آنکه از حجم زمین مقیاسی به دستتان بدهم بگذارید بهتان بگویم که پیش از اختراع برق مجبور بودند در مجموع شش قارهی زمین وسایل زندگیِ لشکری جانانه شامل یکصد و شصت و دو هزار و پانصد و یازده نفر فانوسبان را تامین کنند.
|
||||
|
||||
روشن شدن فانوسها از دور خیلی باشکوه بود. حرکات این لشکر مثل حرکات یک بالهی تو اپرا مرتب و منظم بود. اول از همه نوبت فانوسبانهای زلاندنو و استرالیا بود. اینها که فانوسهاشان را روشن میکردند، میرفتند میگرفتند میخوابیدند آن وقت نوبت فانوسبانهای چین و سیبری میرسید که به رقص درآیند. بعد، اینها با تردستی تمام به پشت صحنه میخزیدند و جا را برای فانوسبانهای ترکیه و هفت پَرکَنِهی هند خالی می کردند. بعد نوبت به فانوسبانهای آمریکایجنوبی میشد. و آخر سر هم نوبت فانوسبانهای افریقا و اروپا میرسد و بعد نوبت فانوسبانهای آمریکای شمالی بود. و هیچ وقتِ خدا هم هیچکدام اینها در ترتیب ورودشان به صحنه دچار اشتباه نمیشدند. چه شکوهی داشت! میان این جمع عظیم فقط نگهبانِ تنها فانوسِ قطب شمال و همکارش نگهبانِ تنها فانوسِ قطب جنوب بودند که عمری به بطالت و بیهودگی میگذراندند: آخر آنها سالی به سالی همهاش دو بار کار میکردند.
|
||||
|
||||
۱۷
|
||||
آدمی که اهل اظهار لحیه باشد بفهمی نفهمی میافتد به چاخان کردن. من هم تو تعریف قضیهی فانوسبانها برای شما آنقدرهاروراست نبودم. میترسم به آنهایی که زمین ما را نمیسناسند تصور نادرستی داده باشم. انسانها رو پهنهی زمین جای خیلی کمی را اشغال میکنند. اگر همهی دو میلیارد نفری که رو کرهی زمین زندگی میکنند بلند بشوند و مثل موقعی که به تظاهرات میروند یک خورده جمع و جور بایستند راحت و بیدرپسر تو میدانی به مساحت بیست میل در بیست میل جا میگیرند. همهی جامعهی بشری را میشود یکجا روی کوچکترین جزیرهی اقیانوس آرام کُپه کرد.
|
||||
|
||||
البته گفتوگو ندارد که آدم بزرگها حرفتان را باور نمیکنند. آخر تصور آنها این است که کلی جا اشغال کردهاند، نه اینکه مثل بائوبابها خودشان را خیلی مهم میبینند؟ بنابراین بهشان پیشنهاد میکنید که بنشینند حساب کنند. آنها هم که عاشق اعداد و ارقامند، پس این پیشنهاد حسابی کیفورشان میکند. اما شما را به خدا بیخودی وقت خودتان را سر این جریمهی مدرسه به هدر ندهید. این کار دو قاز هم نمیارزد. به من که اطمینان دارید. شهریار کوچولو پاش که به زمین رسید از این که دیارالبشری دیده نمیشد سخت هاج و واج ماند.
|
||||
|
||||
شهریار کوچولو وسطِ کویر
|
||||
تازه داشت از این فکر که شاید سیاره را عوضی گرفته ترسش بر میداشت که چنبرهی مهتابی رنگی رو ماسهها جابهجا شد.شهریار کوچولو و مار
|
||||
شهریار کوچولو همینجوری سلام کرد.
|
||||
مار گفت: -سلام.
|
||||
شهریار کوچولو پرسید: -رو چه سیارهای پایین آمدهام؟
|
||||
مار جواب داد: -رو زمین تو قارهی آفریقا.
|
||||
-عجب! پس رو زمین انسان به هم نمیرسد؟
|
||||
مار گفت: -اینجا کویر است. تو کویر کسی زندگی نمیکند. زمین بسیار وسیع است.
|
||||
شهریار کوچولو رو سنگی نشست و به آسمان نگاه کرد. گفت: -به خودم میگویم ستارهها واسه این روشنند که هرکسی بتواند یک روز مال خودش را پیدا کند!... اخترک مرا نگاه! درست بالا سرمان است... اما چهقدر دور است!
|
||||
مار گفت: -قشنگ است. اینجا آمدهای چه کار؟
|
||||
شهریار کوچولو گفت: -با یک گل بگومگویم شده.
|
||||
مار گفت: -عجب!
|
||||
و هر دوشان خاموش ماندند.
|
||||
دست آخر شهریار کوچولو درآمد که: -آدمها کجاند؟ آدم تو کویر یک خرده احساس تنهایی میکند.
|
||||
مار گفت: -پیش آدمها هم احساس تنهایی میکنی.
|
||||
شهریار کوچولو مدت درازی تو نخ او رفت و آخر سر بهاش گفت: -تو چه جانور بامزهای هستی! مثل یک انگشت، باریکی.
|
||||
مار گفت: -عوضش از انگشت هر پادشاهی مقتدرترم.
|
||||
شهریار کوچولو لبخندی زد و گفت: -نه چندان... پا هم که نداری. حتا راه هم نمیتونی بری...
|
||||
-من میتونم تو را به چنان جای دوری ببرم که با هیچ کشتییی هم نتونی بری.
|
||||
مار این را گفت و دور قوزک پای شهریار کوچولو پیچید. عین یک خلخال طلا. و باز درآمد که: -هر کسی را لمس کنم به خاکی که ازش درآمده بر میگردانم اما تو پاکی و از یک سیّارهی دیگر آمدهای...
|
||||
شهریار کوچولو جوابی بش نداد.
|
||||
-تو رو این زمین خارایی آنقدر ضعیفی که به حالت رحمم میآید. روزیروزگاری اگر دلت خیلی هوای اخترکت را کرد بیا من کمکت کنم... من میتوانم...
|
||||
شهریار کوچولو گفت: -آره تا تهش را خواندم. اما راستی تو چرا همهی حرفهایت را به صورت معما درمیآری؟
|
||||
|
||||
مار گفت: -حلّال همهی معماهام من.
|
||||
و هر دوشان خاموش شدند.
|
||||
|
||||
۱۸
|
||||
شهریار کوچولو کویر را از پاشنه درکرد و جز یک گل به هیچی برنخورد: یک گل سه گلبرگه. یک گلِ ناچیز.
|
||||
|
||||
یک گُل وسطِ کویر
|
||||
|
||||
شهریار کوچولو گفت: -سلام.
|
||||
گل گفت: -سلام.
|
||||
شهریار کوچولو با ادب پرسید: -آدمها کجاند؟
|
||||
گل روزی روزگاری عبور کاروانی را دیدهبود. این بود که گفت: -آدمها؟ گمان کنم ازشان شش هفت تایی باشد. سالها پیش دیدمشان. منتها خدا میداند کجا میشود پیداشان کرد. باد اینور و آنور میبَرَدشان؛ نه این که ریشه ندارند؟ بیریشگی هم حسابی اسباب دردسرشان شده.
|
||||
شهریار کوچولو گفت: -خداحافظ.
|
||||
گل گفت: -خداحافظ.
|
||||
|
||||
۱۹
|
||||
از کوه بلندی بالا رفت.
|
||||
|
||||
شهریار کوچولو بر قلهی کوهِ بلند
|
||||
تنها کوههایی که به عمرش دیده بود سه تا آتشفشانهای اخترک خودش بود که تا سر زانویش میرسید و از آن یکی که خاموش بود جای چارپایه استفاده میکرد. این بود که با خودش گفت: «از سر یک کوه به این بلندی میتوانم به یک نظر همهی سیاره و همهی آدمها را ببینم...» اما جز نوکِ تیزِ صخرههای نوکتیز چیزی ندید.
|
||||
همین جوری گفت: -سلام.
|
||||
طنین بهاش جواب داد: -سلام... سلام... سلام...
|
||||
شهریار کوچولو گفت: -کی هستید شما؟
|
||||
طنین بهاش جواب داد: -کی هستید شما... کی هستید شما... کی هستید شما...
|
||||
گفت: -با من دوست بشوید. من تک و تنهام.
|
||||
طنین بهاش جواب داد: -من تک و تنهام... من تک و تنهام... من تک و تنهام...
|
||||
آنوقت با خودش فکر کرد: «چه سیارهی عجیبی! خشکِخشک و تیزِتیز و شورِشور. این آدمهاش که یک ذره قوهی تخیل ندارند و هر چه را بشنوند عینا تکرار میکنند... تو اخترک خودم گلی داشتم که همیشه اول او حرف میزد...»
|
||||
|
||||
۲۰
|
||||
اما سرانجام، بعد از مدتها راه رفتن از میان ریگها و صخرهها و برفها به جادهای برخورد. و هر جادهای یکراست میرود سراغ آدمها.
|
||||
گفت: -سلام.
|
||||
و مخاطبش گلستان پرگلی بود.
|
||||
|
||||
شهریار کوچولو در گلستانِ پرگل
|
||||
|
||||
گلها گفتند: -سلام.
|
||||
شهریار کوچولو رفت تو بحرشان. همهشان عین گل خودش بودند. حیرتزده ازشان پرسید: -شماها کی هستید؟
|
||||
گفتند: -ما گل سرخیم.
|
||||
|
||||
آهی کشید و سخت احساس شوربختی کرد. گلش به او گفته بود که از نوع او تو تمام عالم فقط همان یکی هست و حالا پنجهزارتا گل، همه مثل هم، فقط تو یک گلستان! فکر کرد: «اگر گل من این را میدید بدجور از رو میرفت. پشت سر هم بنا میکرد سرفهکردن و، برای اینکه از هُوشدن نجات پیدا کند خودش را به مردن میزد و من هم مجبور میشدم وانمود کنم به پرستاریش، وگرنه برای سرشکسته کردنِ من هم شده بود راستی راستی میمرد...» و باز تو دلش گفت: «مرا باش که فقط بایک دانه گل خودم را دولتمندِ عالم خیال میکردم در صورتیکه آنچه دارم فقط یک گل معمولی است. با آن گل و آن سه تا آتشفشان که تا سرِ زانومَند و شاید هم یکیشان تا ابد خاموش بماند شهریارِ چندان پُرشوکتی به حساب نمیآیم.»
|
||||
|
||||
شهریار کوچولو در حالِ احساسِ شوربختی
|
||||
رو سبزهها دراز شد و حالا گریه نکن کی گریهکن.
|
||||
|
||||
۲۱
|
||||
آن وقت بود که سر و کلهی روباه پیدا شد.
|
||||
|
||||
شهریار کوچولو و روباه
|
||||
|
||||
روباه گفت: -سلام.
|
||||
شهریار کوچولو برگشت اما کسی را ندید. با وجود این با ادب تمام گفت: -سلام.
|
||||
صداگفت: -من اینجام، زیر درخت سیب...
|
||||
شهریار کوچولو گفت: -کی هستی تو؟ عجب خوشگلی!
|
||||
روباه گفت: -یک روباهم من.
|
||||
شهریار کوچولو گفت: -بیا با من بازی کن. نمیدانی چه قدر دلم گرفته...
|
||||
روباه گفت: -نمیتوانم بات بازی کنم. هنوز اهلیم نکردهاند آخر.
|
||||
شهریار کوچولو آهی کشید و گفت: -معذرت میخواهم.
|
||||
اما فکری کرد و پرسید: -اهلی کردن یعنی چه؟
|
||||
روباه گفت: -تو اهل اینجا نیستی. پی چی میگردی؟
|
||||
شهریار کوچولو گفت: -پی آدمها میگردم. نگفتی اهلی کردن یعنی چه؟
|
||||
روباه گفت: -آدمها تفنگ دارند و شکار میکنند. اینش اسباب دلخوری است! اما مرغ و ماکیان هم پرورش میدهند و خیرشان فقط همین است. تو پی مرغ میکردی؟
|
||||
شهریار کوچولو گفت: -نَه، پیِ دوست میگردم. اهلی کردن یعنی چی؟
|
||||
روباه گفت: -یک چیزی است که پاک فراموش شده. معنیش ایجاد علاقه کردن است.
|
||||
-ایجاد علاقه کردن؟
|
||||
روباه گفت: -معلوم است. تو الان واسه من یک پسر بچهای مثل صد هزار پسر بچهی دیگر. نه من هیچ احتیاجی به تو دارم نه تو هیچ احتیاجی به من. من هم واسه تو یک روباهم مثل صد هزار روباه دیگر. اما اگر منو اهلی کردی هر دوتامان به هم احتیاج پیدا میکنیم. تو واسه من میان همهی عالم موجود یگانهای میشوی من واسه تو.
|
||||
شهریار کوچولو گفت: -کمکم دارد دستگیرم میشود. یک گلی هست که گمانم مرا اهلی کرده باشد.
|
||||
روباه گفت: -بعید نیست. رو این کرهی زمین هزار جور چیز میشود دید.
|
||||
شهریار کوچولو گفت: -اوه نه! آن رو کرهی زمین نیست.
|
||||
روباه که انگار حسابی حیرت کرده بود گفت: -رو یک سیارهی دیگر است؟
|
||||
-آره.
|
||||
شکارچی-تو آن سیاره شکارچی هم هست؟
|
||||
-نه.
|
||||
-محشر است! مرغ و ماکیان چهطور؟
|
||||
-نه.
|
||||
روباه آهکشان گفت: -همیشهی خدا یک پای بساط لنگ است!
|
||||
اما پی حرفش را گرفت و گفت: -زندگی یکنواختی دارم. من مرغها را شکار میکنم آدمها مرا. همهی مرغها عین همند همهی آدمها هم عین همند. این وضع یک خرده خلقم را تنگ میکند. اما اگر تو منو اهلی کنی انگار که زندگیم را چراغان کرده باشی. آن وقت صدای پایی را میشناسم که باهر صدای پای دیگر فرق میکند: صدای پای دیگران مرا وادار میکند تو هفت تا سوراخ قایم بشوم اما صدای پای تو مثل نغمهای مرا از سوراخم میکشد بیرون. تازه، نگاه کن آنجا آن گندمزار را میبینی؟ برای من که نان بخور نیستم گندم چیز بیفایدهای است. پس گندمزار هم مرا به یاد چیزی نمیاندازد. اسباب تاسف است. اما تو موهات رنگ طلا است. پس وقتی اهلیم کردی محشر میشود! گندم که طلایی رنگ است مرا به یاد تو میاندازد و صدای باد را هم که تو گندمزار میپیچد دوست خواهم داشت...
|
||||
خاموش شد و مدت درازی شهریار کوچولو را نگاه کرد. آن وقت گفت: -اگر دلت میخواهد منو اهلی کن!
|
||||
شهریار کوچولو جواب داد: -دلم که خیلی میخواهد، اما وقتِ چندانی ندارم. باید بروم دوستانی پیدا کنم و از کلی چیزها سر در آرم.
|
||||
روباه گفت: -آدم فقط از چیزهایی که اهلی کند میتواند سر در آرد. انسانها دیگر برای سر در آوردن از چیزها وقت ندارند. همه چیز را همین جور حاضر آماده از دکانها میخرند. اما چون دکانی نیست که دوست معامله کند آدمها ماندهاند بیدوست... تو اگر دوست میخواهی خب منو اهلی کن!
|
||||
شهریار کوچولو پرسید: -راهش چیست؟
|
||||
روباه جواب داد: -باید خیلی خیلی حوصله کنی. اولش یک خرده دورتر از من میگیری این جوری میان علفها مینشینی. من زیر چشمی نگاهت میکنم و تو لامتاکام هیچی نمیگویی، چون تقصیر همهی سؤِتفاهمها زیر سر زبان است. عوضش میتوانی هر روز یک خرده نزدیکتر بنشینی.
|
||||
|
||||
روباه در حالِ انتظارفردای آن روز دوباره شهریار کوچولو آمد.
|
||||
روباه گفت: -کاش سر همان ساعت دیروز آمده بودی. اگر مثلا سر ساعت چهار بعد از ظهر بیایی من از ساعت سه تو دلم قند آب میشود و هر چه ساعت جلوتر برود بیشتر احساس شادی و خوشبختی میکنم. ساعت چهار که شد دلم بنا میکند شور زدن و نگران شدن. آن وقت است که قدرِ خوشبختی را میفهمم! اما اگر تو وقت و بی وقت بیایی من از کجا بدانم چه ساعتی باید دلم را برای دیدارت آماده کنم؟... هر چیزی برای خودش قاعدهای دارد.
|
||||
شهریار کوچولو گفت: -قاعده یعنی چه؟
|
||||
روباه گفت: -این هم از آن چیزهایی است که پاک از خاطرها رفته. این همان چیزی است که باعث میشود فلان روز با باقی روزها و فلان ساعت با باقی ساعتها فرق کند. مثلا شکارچیهای ما میان خودشان رسمی دارند و آن این است که پنجشنبهها را با دخترهای ده میروند رقص. پس پنجشنبهها بَرّهکشانِ من است: برای خودم گردشکنان میروم تا دم مُوِستان. حالا اگر شکارچیها وقت و بی وقت میرقصیدند همهی روزها شبیه هم میشد و منِ بیچاره دیگر فرصت و فراغتی نداشتم.
|
||||
|
||||
به این ترتیب شهریار کوچولو روباه را اهلی کرد.
|
||||
لحظهی جدایی که نزدیک شد روباه گفت: -آخ! نمیتوانم جلو اشکم را بگیرم.
|
||||
شهریار کوچولو گفت: -تقصیر خودت است. من که بدت را نمیخواستم، خودت خواستی اهلیت کنم.
|
||||
روباه گفت: -همین طور است.
|
||||
شهریار کوچولو گفت: -آخر اشکت دارد سرازیر میشود!
|
||||
روباه گفت: -همین طور است.
|
||||
-پس این ماجرا فایدهای به حال تو نداشته.
|
||||
روباه گفت: -چرا، واسه خاطرِ رنگ گندم.
|
||||
بعد گفت: -برو یک بار دیگر گلها را ببین تا بفهمی که گلِ خودت تو عالم تک است. برگشتنا با هم وداع میکنیم و من به عنوان هدیه رازی را بهات میگویم.
|
||||
شهریار کوچولو بار دیگر به تماشای گلها رفت و به آنها گفت: -شما سرِ سوزنی به گل من نمیمانید و هنوز هیچی نیستید. نه کسی شما را اهلی کرده نه شما کسی را. درست همان جوری هستید که روباه من بود: روباهی بود مثل صدهزار روباه دیگر. او را دوست خودم کردم و حالا تو همهی عالم تک است.
|
||||
گلها حسابی از رو رفتند.
|
||||
شهریار کوچولو دوباره درآمد که: -خوشگلید اما خالی هستید. برایتان نمیشود مُرد. گفتوگو ندارد که گلِ مرا هم فلان رهگذر میبیند مثل شما. اما او به تنهایی از همهی شما سر است چون فقط اوست که آبش دادهام، چون فقط اوست که زیر حبابش گذاشتهام، چون فقط اوست که با تجیر برایش حفاظ درست کردهام، چون فقط اوست که حشراتش را کشتهام (جز دو سهتایی که میبایست شبپره بشوند)، چون فقط اوست که پای گِلِهگزاریها یا خودنماییها و حتا گاهی پای بُغ کردن و هیچی نگفتنهاش نشستهام، چون او گلِ من است.
|
||||
و برگشت پیش روباه.
|
||||
گفت: -خدانگهدار!
|
||||
روباه گفت: -خدانگهدار!... و اما رازی که گفتم خیلی ساده است:
|
||||
جز با دل هیچی را چنان که باید نمیشود دید. نهاد و گوهر را چشمِ سَر نمیبیند.
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -نهاد و گوهر را چشمِ سَر نمیبیند.
|
||||
-ارزش گل تو به قدرِ عمری است که به پاش صرف کردهای.
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -به قدر عمری است که به پاش صرف کردهام.
|
||||
روباه گفت: -انسانها این حقیقت را فراموش کردهاند اما تو نباید فراموشش کنی. تو تا زندهای نسبت به چیزی که اهلی کردهای مسئولی. تو مسئول گُلِتی...
|
||||
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -من مسئول گُلمَم.
|
||||
|
||||
۲۲
|
||||
شهریار کوچولو گفت: -سلام.
|
||||
سوزنبان گفت: -سلام.
|
||||
شهریار کوچولو گفت: -تو چه کار میکنی اینجا؟
|
||||
سوزنبان گفت: -مسافرها را به دستههای هزارتایی تقسیم میکنم و قطارهایی را که میبَرَدشان گاهی به سمت راست میفرستم گاهی به سمت چپ. و همان دم سریعالسیری با چراغهای روشن و غرّشی رعدوار اتاقک سوزنبانی را به لرزه انداخت.
|
||||
-عجب عجلهای دارند! پیِ چی میروند؟
|
||||
سوزنبان گفت: -از خودِ آتشکارِ لکوموتیف هم بپرسی نمیداند!
|
||||
سریعالسیر دیگری با چراغهای روشن غرّید و در جهت مخالف گذشت .
|
||||
شهریار کوچولو پرسید: -برگشتند که؟
|
||||
سوزنبان گفت: -اینها اولیها نیستند. آنها رفتند اینها برمیگردند.
|
||||
-جایی را که بودند خوش نداشتند؟
|
||||
سوزنبان گفت: -آدمیزاد هیچ وقت جایی را که هست خوش ندارد.
|
||||
و رعدِ سریعالسیرِ نورانیِ ثالثی غرّید.
|
||||
شهریار کوچولو پرسید: -اینها دارند مسافرهای اولی را دنبال میکنند؟
|
||||
سوزنبان گفت: -اینها هیچ چیزی را دنبال نمیکنند. آن تو یا خوابشان میبَرَد یا دهندره میکنند. فقط بچههاند که دماغشان را فشار میدهند به شیشهها.
|
||||
شهریار کوچولو گفت: -فقط بچههاند که میدانند پیِ چی میگردند. بچههاند که کُلّی وقت صرف یک عروسک پارچهای میکنند و عروسک برایشان آن قدر اهمیت به هم میرساند که اگر یکی آن را ازشان کِش برود میزنند زیر گریه...
|
||||
سوزنبان گفت: -بخت، یارِ بچههاست.
|
||||
|
||||
۲۳
|
||||
شهریار کوچولو گفت: -سلام!
|
||||
پیلهور گفت: -سلام.
|
||||
این بابا فروشندهی حَبهای ضد تشنگی بود. خریدار هفتهای یک حب میانداخت بالا و دیگر تشنگی بی تشنگی.
|
||||
شهریار کوچولو پرسید: -اینها را میفروشی که چی؟
|
||||
پیلهور گفت: -باعث صرفهجویی کُلّی وقت است. کارشناسهای خبره نشستهاند دقیقا حساب کردهاند که با خوردن این حبها هفتهای پنجاه و سه دقیقه وقت صرفهجویی میشود.
|
||||
-خب، آن وقت آن پنجاه و سه دقیقه را چه کار میکنند؟
|
||||
ـ هر چی دلشان خواست...
|
||||
|
||||
چشمه
|
||||
شهریار کوچولو تو دلش گفت: «من اگر پنجاه و سه دقیقه وقتِ زیادی داشته باشم خوشخوشک به طرفِ یک چشمه میروم...»
|
||||
|
||||
۲۴
|
||||
هشتمین روزِ خرابی هواپیمام تو کویر بود که، در حال نوشیدنِ آخرین چکّهی ذخیرهی آبم به قضیهی پیلهوره گوش داده بودم. به شهریار کوچولو گفتم:
|
||||
-خاطرات تو راستی راستی زیباند اما من هنوز از پسِ تعمیر هواپیما برنیامدهام، یک چکه آب هم ندارم. و راستی که من هم اگر میتوانستم خوشخوشک به طرف چشمهای بروم سعادتی احساس میکردم که نگو!
|
||||
درآمد که: -دوستم روباه...
|
||||
گفتم: -آقا کوچولو، دورِ روباه را قلم بگیر!
|
||||
-واسه چی؟
|
||||
-واسه این که تشنگی کارمان را می سازد. واسه این!
|
||||
از استدلال من چیزی حالیش نشد و در جوابم گفت:
|
||||
-حتا اگر آدم دَمِ مرگ باشد هم داشتن یک دوست عالی است. من که از داشتن یک دوستِ روباه خیلی خوشحالم...
|
||||
به خودم گفتم نمیتواند میزان خطر را تخمین بزند: آخر او هیچ وقت نه تشنهاش میشود نه گشنهاش. یه ذره آفتاب بسش است...
|
||||
اما او به من نگاه کرد و در جواب فکرم گفت: -من هم تشنهم است... بگردیم یک چاه پیدا کنیم...
|
||||
از سرِ خستگی حرکتی کردم: -این جوری تو کویرِ برهوت رو هوا پیِ چاه گشتن احمقانه است.
|
||||
و با وجود این به راه افتادیم.
|
||||
|
||||
پس از ساعتها که در سکوت راه رفتیم شب شد و ستارهها یکی یکی درآمدند. من که از زور تشنگی تب کرده بودم انگار آنها را خواب میدیدم. حرفهای شهریار کوچولو تو ذهنم میرقصید.
|
||||
ازش پرسیدم: -پس تو هم تشنهات هست، ها؟
|
||||
اما او به سوآلِ من جواب نداد فقط در نهایت سادگی گفت: -آب ممکن است برای دلِ من هم خوب باشد...
|
||||
از حرفش چیزی دستگیرم نشد اما ساکت ماندم. میدانستم از او نباید حرف کشید.
|
||||
خسته شده بود. گرفت نشست. من هم کنارش نشستم. پس از مدتی سکوت گفت:
|
||||
-قشنگیِ ستارهها واسه خاطرِ گلی است که ما نمیبینیمش...
|
||||
گفتم: -همین طور است
|
||||
و بدون حرف در مهتاب غرق تماشای چین و شکنهای شن شدم.
|
||||
باز گفت: -کویر زیباست.
|
||||
|
||||
و حق با او بود. من همیشه عاشق کویر بودهام. آدم بالای تودهای شن لغزان مینشیند، هیچی نمیبیند و هیچی نمیشنود اما با وجود این چیزی توی سکوت برقبرق میزند.
|
||||
شهریار کوچولو گفت: -چیزی که کویر را زیبا میکند این است که یک جایی یک چاه قایم کرده...
|
||||
از اینکه ناگهان به راز آن درخشش اسرارآمیزِ شن پی بردم حیرتزده شدم. بچگیهام تو خانهی کهنهسازی مینشستیم که معروف بود تو آن گنجی چال کردهاند. البته نگفته پیداست که هیچ وقت کسی آن را پیدا نکرد و شاید حتا اصلا کسی دنبالش نگشت اما فکرش همهی اهل خانه را تردماغ میکرد: «خانهی ما تهِ دلش رازی پنهان کرده بود...»
|
||||
گفتم: -آره. چه خانه باشد چه ستاره، چه کویر، چیزی که اسباب زیباییاش میشود نامریی است!
|
||||
گفت: -خوشحالم که با روباه من توافق داری.
|
||||
|
||||
چون خوابش برده بود بغلش کردم و راه افتادم. دست و دلم میلرزید.انگار چیز شکستنیِ بسیار گرانبهایی را روی دست میبردم. حتا به نظرم میآمد که تو تمام عالم چیزی شکستنیتر از آن هم به نظر نمیرسد. تو روشنی مهتاب به آن پیشانی رنگپریده و آن چشمهای بسته و آن طُرّههای مو که باد میجنباند نگاه کردم و تو دلم گفتم: «آن چه میبینم صورت ظاهری بیشتر نیست. مهمترش را با چشم نمیشود دید...»
|
||||
باز، چون دهان نیمهبازش طرح کمرنگِ نیمهلبخندی را داشت به خود گفتم: «چیزی که تو شهریار کوچولوی خوابیده مرا به این شدت متاثر میکند وفاداری اوست به یک گل: او تصویرِ گل سرخی است که مثل شعلهی چراغی حتا در خوابِ ناز هم که هست تو وجودش میدرخشد...» و آن وقت او را باز هم شکنندهتر دیدم. حس کردم باید خیلی مواظبش باشم: به شعلهی چراغی میمانست که یک وزش باد هم میتوانست خاموشش کند.
|
||||
و همان طور در حال راه رفتن بود که دمدمهی سحر چاه را پیداکردم.
|
||||
|
||||
۲۵
|
||||
شهریار کوچولو درآمد که: -آدمها!... میچپند تو قطارهای تندرو اما نمیدانند دنبال چی میگردند. این است که بنامیکنند دور خودشان چرخکزدن.
|
||||
و بعد گفت: -این هم کار نشد...
|
||||
چاهی که بهاش رسیدهبودیم اصلا به چاههای کویری نمیمانست. چاه کویری یک چالهی ساده است وسط شنها. این یکی به چاههای واحهای میمانست اما آن دوروبر واحهای نبود و من فکر کردم دارم خواب میبینم.
|
||||
گفتم: -عجیب است! قرقره و سطل و تناب، همهچیز روبهراه است.
|
||||
خندید تناب را گرفت و قرقره را به کار انداخت
|
||||
|
||||
شهریار کوچولو در حالِ کشیدنِ آب از چاه
|
||||
و قرقره مثل بادنمای کهنهای که تا مدتها پس از خوابیدنِ باد مینالد به نالهدرآمد.
|
||||
گفت: -میشنوی؟ ما داریم این چاه را از خواب بیدار میکنیم و او دارد برایمان آواز میخواند...
|
||||
دلم نمیخواست او تلاش و تقلا کند. بش گفتم: -بدهش به من. برای تو زیادی سنگین است.
|
||||
سطل را آرام تا طوقهی چاه آوردم بالا و آنجا کاملا در تعادل نگهش داشتم. از حاصل کار شاد بودم. خسته و شاد. آواز قرقره را همانطور تو گوشم داشتم و تو آب که هنوز میلرزید لرزش خورشید را میدیدم.
|
||||
گفت: -بده من، که تشنهی این آبم.
|
||||
ومن تازه توانستم بفهمم پی چه چیز میگشته!
|
||||
|
||||
سطل را تا لبهایش بالا بردم. با چشمهای بسته نوشید. آبی بود به شیرینیِ عیدی. این آب به کُلّی چیزی بود سوایِ هرگونه خوردنی. زاییدهی راه رفتنِ زیر ستارهها و سرود قرقره و تقلای بازوهای من بود. مثل یک چشم روشنی برای دل خوب بود. پسر بچه که بودم هم، چراغ درخت عید و موسیقیِ نماز نیمهشب عید کریسمس و لطف لبخندهها عیدیی را که بم میدادند درست به همین شکل آن همه جلا و جلوه میبخشید.
|
||||
گفت: -مردم سیارهی تو ور میدارند پنج هزار تا گل را تو یک گلستان میکارند، و آن یک دانهای را که پِیَش میگردند آن وسط پیدا نمیکنند...
|
||||
گفتم: -پیدایش نمیکنند.
|
||||
-با وجود این، چیزی که پیَش میگردند ممکن است فقط تو یک گل یا تو یک جرعه آب پیدا بشود...
|
||||
جواب دادم: -گفتوگو ندارد.
|
||||
باز گفت: -گیرم چشمِ سَر کور است، باید با چشم دل پیاش گشت.
|
||||
من هم سیراب شده بودم. راحت نفس میکشیدم. وقتی آفتاب درمیآید شن به رنگ عسل است. من هم از این رنگ عسلی لذت میبردم. چرا میبایست در زحمت باشم...
|
||||
شهریار کوچولو که باز گرفته بود کنار من نشسته بود با لطف بم گفت: -هِی! قولت قول باشد ها!
|
||||
-کدام قول؟
|
||||
-یادت است؟ یک پوزهبند برای بَرّهام... آخر من مسئول گلمَم!
|
||||
طرحهای اولیهام را از جیب درآوردم. نگاهشان کرد و خندانخندان گفت: -بائوبابهات یک خرده شبیه کلم شده.
|
||||
ای وای! مرا بگو که آنقدر به بائوبابهام مینازیدم.
|
||||
-روباهت... گوشهاش بیشتر به شاخ میماند... زیادی درازند!
|
||||
و باز زد زیر خنده.
|
||||
-آقا کوچولو داری بیانصافی میکنی. من جز بوآهای بسته و بوآهای باز چیزی بلد نبودم بکشم که.
|
||||
گفت: -خب، مهم نیست. عوضش بچهها سرشان تو حساب است.
|
||||
با مداد یک پوزهبند کشیدم دادم دستش و با دلِ فشرده گفتم:
|
||||
-تو خیالاتی به سر داری که من ازشان بیخبرم...
|
||||
اما جواب مرا نداد. بم گفت: -میدانی؟ فردا سالِ به زمین آمدنِ من است.
|
||||
بعد پس از لحظهای سکوت دوباره گفت: -همین نزدیکیها پایین آمدم.
|
||||
و سرخ شد.
|
||||
|
||||
و من از نو بی این که بدانم چرا غم عجیبی احساس کردم. با وجود این سوآلی به ذهنم رسید: -پس هشت روز پیش، آن روز صبح که تو تک و تنها هزار میل دورتر از هر آبادی وسطِ کویر به من برخوردی اتفاقی نبود: داشتی برمیگشتی به همان جایی که پایینآمدی...
|
||||
دوباره سرخ شد
|
||||
و من با دودلی به دنبال حرفم گفتم:
|
||||
-شاید به مناسبت همین سالگرد؟...
|
||||
باز سرخ شد. او هیچ وقت به سوآلهایی که ازش میشد جواب نمیداد اما وقتی کسی سرخ میشود معنیش این است که «بله»، مگر نه؟
|
||||
بهاش گفتم: -آخر، من ترسم برداشته...
|
||||
اما او حرفم را برید:
|
||||
-دیگر تو باید بروی به کارت برسی. باید بروی سراغ موتورت. من همینجا منتظرت میمانم. فردا عصر برگرد...
|
||||
|
||||
منتها من خاطر جمع نبودم. به یاد روباه افتادم: اگر آدم گذاشت اهلیش کنند بفهمینفهمی خودش را به این خطر انداخته که کارش به گریهکردن بکشد.
|
||||
|
||||
۲۶
|
||||
کنار چاه دیوارِ سنگی مخروبهای بود. فردا عصر که از سرِ کار برگشتم از دور دیدم که آن بالا نشسته پاها را آویزان کرده،
|
||||
|
||||
شهریار کوچولو نشسته بر دیوارِ سنگی و مار در پایینِ آن
|
||||
و شنیدم که میگوید:
|
||||
-پس یادت نمیآید؟ درست این نقطه نبود ها!
|
||||
لابد صدای دیگری بهاش جوابی داد، چون شهریار کوچولو در رَدِّ حرفش گفت:
|
||||
-چرا چرا! روزش که درست همین امروز است گیرم محلش این جا نیست...
|
||||
راهم را به طرف دیوار ادامه دادم. هنوز نه کسی به چشم خورده بود نه صدای کسی را شنیده بودم اما شهریار کوچولو باز در جواب درآمد که:
|
||||
-... آره، معلوم است. خودت میتوانی ببینی رَدِّ پاهایم روی شن از کجا شروع میشود.
|
||||
همان جا منتظرم باش، تاریک که شد میآیم.
|
||||
بیست متری دیوار بودم و هنوز چیزی نمیدیدم. پس از مختصر مکثی دوباره گفت:
|
||||
-زهرت خوب هست؟ مطمئنی درد و زجرم را کِش نمیدهد؟
|
||||
با دل فشرده از راه ماندم اما هنوز از موضوع سر در نیاورده بودم.
|
||||
گفت: -خب، حالا دیگر برو. دِ برو. میخواهم بیایم پایین!
|
||||
|
||||
آن وقت من نگاهم را به پایین به پای دیوار انداختم و از جا جستم! یکی از آن مارهای زردی که تو سی ثانیه کَلَکِ آدم را میکنند، به طرف شهریار کوچولو قد راست کرده بود. من همان طور که به دنبال تپانچه دست به جیبم میبردم پا گذاشتم به دو، اما ماره از سر و صدای من مثل فوارهای که بنشیند آرام روی شن جاری شد و بی آن که چندان عجلهای از خودش نشان دهد باصدای خفیف فلزی لای سنگها خزید.
|
||||
من درست به موقع به دیوار رسیدم و طفلکی شهریار کوچولو را که رنگش مثل برف پریده بود تو هوا بغل کردم.
|
||||
-این دیگر چه حکایتی است! حالا دیگر با مارها حرف میزنی؟
|
||||
شال زردش را که مدام به گردن داشت باز کردم به شقیقههایش آب زدم و جرعهای بهاش نوشاندم. اما حالا دیگر اصلا جرات نمی کردم ازش چیزی بپرسم. با وقار به من نگاه کرد و دستش را دور گردنم انداخت. حس کردم قلبش مثل قلب پرندهای میزند که تیر خوردهاست و دارد میمیرد.
|
||||
گفت: -از این که کم و کسرِ لوازم ماشینت را پیدا کردی خوشحالم. حالا میتوانی برگردی خانهات...
|
||||
-تو از کجا فهمیدی؟
|
||||
درست همان دم لبواکردهبودم بش خبر بدهم که علیرغم همهی نومیدیها تو کارم موفق شدهام!
|
||||
به سوآلهای من هیچ جوابی نداد اما گفت: -آخر من هم امروز بر میگردم خانهام...
|
||||
و بعد غمزده درآمد که: -گیرم راه من خیلی دورتر است... خیلی سختتر است...
|
||||
|
||||
حس میکردم اتفاق فوقالعادهای دارد میافتد. گرفتمش تو بغلم. عین یک بچهی کوچولو. با وجود این به نظرم میآمد که او دارد به گردابی فرو میرود و برای نگه داشتنش از من کاری ساخته نیست... نگاه متینش به دوردستهای دور راه کشیده بود.
|
||||
گفت: بَرِّهات را دارم. جعبههه را هم واسه برههه دارم. پوزهبنده را هم دارم.
|
||||
و با دلِ گرفته لبخندی زد.
|
||||
مدت درازی صبر کردم. حس کردم کمکمَک تنش دوباره دارد گرم میشود.
|
||||
-عزیز کوچولوی من، وحشت کردی...
|
||||
-امشب وحشت خیلی بیشتری چشم بهراهم است.
|
||||
|
||||
دوباره از احساسِ واقعهای جبران ناپذیر یخ زدم. این فکر که دیگر هیچ وقت غشغش خندهی او را نخواهم شنید برایم سخت تحملناپذیر بود. خندهی او برای من به چشمهای در دلِ کویر میمانست.
|
||||
-کوچولوئَکِ من، دلم میخواهد باز هم غشغشِ خندهات را بشنوم.
|
||||
اما بهام گفت: -امشب درست میشود یک سال و اخترَکَم درست بالای همان نقطهای میرسد که پارسال به زمین آمدم.
|
||||
-کوچولوئک، این قضیهی مار و میعاد و ستاره یک خواب آشفته بیشتر نیست. مگر نه؟
|
||||
به سوال من جوابی نداد اما گفت: -چیزی که مهم است با چشمِ سَر دیده نمیشود.
|
||||
-مسلم است.
|
||||
-در مورد گل هم همینطور است: اگر گلی را دوست داشته باشی که تو یک ستارهی دیگر است، شب تماشای آسمان چه لطفی پیدا میکند: همهی ستارهها غرق گل میشوند!
|
||||
-مسلم است...
|
||||
-در مورد آب هم همینطور است. آبی که تو به من دادی به خاطر قرقره و ریسمان درست به یک موسیقی میمانست... یادت که هست... چه خوب بود.
|
||||
-مسلم است...
|
||||
-شببهشب ستارهها را نگاه میکنی. اخترک من کوچولوتر از آن است که بتوانم جایش را نشانت بدهم. اما چه بهتر! آن هم برای تو میشود یکی از ستارهها؛ و آن وقت تو دوست داری همهی ستارهها را تماشا کنی... همهشان میشوند دوستهای تو... راستی میخواهم هدیهای بت بدهم...
|
||||
و غش غش خندید.
|
||||
-آخ، کوچولوئک، کوچولوئک! من عاشقِ شنیدنِ این خندهام!
|
||||
-هدیهی من هم درست همین است... درست مثل مورد آب.
|
||||
-چی میخواهی بگویی؟
|
||||
-همهی مردم ستاره دارند اما همهی ستارهها یکجور نیست: واسه آنهایی که به سفر میروند حکم راهنما را دارند واسه بعضی دیگر فقط یک مشت روشناییِ سوسوزناند. برای بعضی که اهل دانشند هر ستاره یک معما است واسه آن بابای تاجر طلا بود. اما این ستارهها همهشان زبان به کام کشیده و خاموشند. فقط تو یکی ستارههایی خواهی داشت که تنابندهای مِثلش را ندارد.
|
||||
-چی میخواهی بگویی؟
|
||||
-نه این که من تو یکی از ستارههام؟ نه این که من تو یکی از آنها میخندم؟... خب، پس هر شب که به آسمان نگاه میکنی برایت مثل این خواهد بود که همهی ستارهها میخندند. پس تو ستارههایی خواهی داشت که بلدند بخندند!
|
||||
و باز خندید.
|
||||
-و خاطرت که تسلا پیدا کرد (خب بالاخره آدمیزاد یک جوری تسلا پیدا میکند دیگر) از آشنایی با من خوشحال میشوی. دوست همیشگی من باقی میمانی و دلت میخواهد با من بخندی و پارهای وقتهام واسه تفریح پنجرهی اتاقت را وا میکنی... دوستانت از اینکه میبینند تو به آسمان نگاه میکنی و میخندی حسابی تعجب میکنند آن وقت تو بهشان میگویی: «آره، ستارهها همیشه مرا خنده میاندازند!» و آنوقت آنها یقینشان میشود که تو پاک عقلت را از دست دادهای. جان! میبینی چه کَلَکی بهات زدهام...
|
||||
و باز زد زیر خنده.
|
||||
-به آن میماند که عوضِ ستاره یک مشت زنگوله بت داده باشم که بلدند بخندند...
|
||||
دوباره خندید و بعد حالتی جدی به خودش گرفت:
|
||||
-نه، من تنهات نمیگذارم.
|
||||
|
||||
شهریار کوچولو تنها
|
||||
|
||||
-ظاهر آدمی را پیدا میکنم که دارد درد میکشد... یک خرده هم مثل آدمی میشوم که دارد جان میکند. رو هم رفته این جوریها است. نیا که این را نبینی. چه زحمتی است بیخود؟
|
||||
-تنهات نمیگذارم.
|
||||
اندوهزده بود.
|
||||
-این را بیشتر از بابت ماره میگویم که، نکند یکهو تو را هم بگزد. مارها خیلی خبیثند. حتا واسه خنده هم ممکن است آدم را نیش بزنند.
|
||||
-تنهات نمیگذارم.
|
||||
منتها یک چیز باعث خاطر جمعیش شد:
|
||||
-گر چه، بار دوم که بخواهند بگزند دیگر زهر ندارند.
|
||||
شب متوجه راه افتادنش نشدم. بی سر و صدا گریخت.
|
||||
وقتی خودم را بهاش رساندم با قیافهی مصمم و قدمهای محکم پیش میرفت. همین قدر گفت: -اِ! اینجایی؟
|
||||
و دستم را گرفت.
|
||||
اما باز بیقرار شد وگفت: -اشتباه کردی آمدی. رنج میبری. گرچه حقیقت این نیست، اما ظاهرِ یک مرده را پیدا میکنم.
|
||||
من ساکت ماندم.
|
||||
-خودت درک میکنی. راه خیلی دور است. نمیتوانم این جسم را با خودم ببرم. خیلی سنگین است.
|
||||
من ساکت ماندم.
|
||||
-گیرم عینِ پوستِ کهنهای میشود که دورش انداخته باشند؛ پوست کهنه که غصه ندارد، ها؟
|
||||
من ساکت ماندم.
|
||||
کمی دلسرد شد اما باز هم سعی کرد:
|
||||
-خیلی با مزه میشود، نه؟ من هم به ستارهها نگاه میکنم. همشان به صورت چاههایی در میآیند با قرقرههای زنگ زده. همهی ستارهها بم آب میدهند بخورم...
|
||||
من ساکت ماندم.
|
||||
-خیلی با مزه میشود. نه؟ تو صاحب هزار کرور زنگوله میشوی من صاحب هزار کرور فواره...
|
||||
او هم ساکت شد، چرا که داشت گریه میکرد...
|
||||
-خب، همین جاست. بگذار چند قدم خودم تنهایی بروم.
|
||||
و گرفت نشست، چرا که میترسید.
|
||||
|
||||
شهریار کوچولو نشسته
|
||||
|
||||
میدانی؟... گلم را میگویم... آخر من مسئولشم. تازه چه قدر هم لطیف است و چه قدر هم ساده و بیشیلهپیله. برای آن که جلو همهی عالم از خودش دفاع کند همهاش چی دارد مگر؟ چهارتا خار پِرپِرَک!
|
||||
|
||||
من هم گرفتم نشستم. دیگر نمیتوانستم سر پا بند بشوم.
|
||||
گفت: -همین... همهاش همین و بس...
|
||||
باز هم کمی دودلی نشان داد اما بالاخره پا شد و قدمی به جلو رفت. من قادر به حرکت نبودم.
|
||||
|
||||
کنار قوزکِ پایش جرقهی زردی جست و... فقط همین! یک دم بیحرکت ماند. فریادی نزد. مثل درختی که بیفتد آرامآرام به زمین افتاد که به وجود شن از آن هم صدایی بلند نشد.
|
||||
|
||||
شهریار کوچولو در حالی که آرامآرام به زمین میافتد
|
||||
۲۷
|
||||
شش سال گذشته است و من هنوز بابت این قضیه جایی لبترنکردهام. دوستانم از این که مرا دوباره زنده میدیدند سخت شاد شدند. من غمزده بودم اما به آنها میگفتم اثر خستگی است.
|
||||
حالا کمی تسلای خاطر پیدا کردهام. یعنی نه کاملا... اما این را خوب میدانم که او به اخترکش برگشته. چون آفتاب که زد پیکرش را پیدا نکردم. پیکری هم نبود که چندان وزنی داشته باشد... و شبها دوست دارم به ستارهها گوش بدهم. عین هزار زنگولهاند.
|
||||
اما موضوع خیلی مهمی که هست، من پاک یادم رفت به پوزهبندی که برای شهریار کوچولو کشیدم تسمهی چرمی اضافه کنم و او ممکن نیست بتواند آن را به پوزهی بَرّه ببندد. این است که از خودم میپرسم: «یعنی تو اخترکش چه اتفاقی افتاده؟ نکند برههه گل را چریده باشد؟...»
|
||||
گاه به خودم میگویم: «حتما نه، شهریار کوچولو هر شب گلش را زیر حباب شیشهای میگذارد و هوای برهاش را هم دارد...» آن وقت است که خیالم راحت میشود و ستارهها همه به شیرینی میخندند.
|
||||
گاه به خودم میگویم: «همین کافی است که آدم یک بار حواسش نباشد... آمدیم و یک شب حباب یادش رفت یا بَرّه شب نصفشبی بیسروصدا از جعبه زد بیرون...» آن وقت است که زنگولهها همه تبدیل به اشک میشوند!...
|
||||
|
||||
یک راز خیلی خیلی بزرگ این جا هست: برای شما هم که او را دوست دارید، مثل من هیچ چیزِ عالم مهمتر از دانستن این نیست که تو فلان نقطهای که نمیدانیم، فلان برهای که نمیشماسیم گل سرخی را چریده یا نچریده...
|
||||
|
||||
خب. آسمان را نگاه کنید و بپرسید: «بَرّه گل را چریده یا نچریده؟» و آن وقت با چشمهای خودتان تفاوتش را ببینید...
|
||||
|
||||
و محال است آدم بزرگها روحشان خبردار بشود که این موضوع چه قدر مهم است!
|
||||
|
||||
بدونِ شهریار کوچولو
|
||||
در نظر من این زیباترین و حزنانگیزترین منظرهی عالم است. این همان منظرهی دو صفحه پیش است گیرم آن را دوباره کشیدهام که بهتر نشانتان بدهم: «ظهور شهریار کوچولو بر زمین در این جا بود؛ و بعد در همین جا هم بود که ناپدید شد».
|
||||
|
||||
آن قدر به دقت این منظره را نگاه کنید که مطمئن بشوید اگر روزی تو آفریقا گذرتان به کویر صحرا افتاد حتما آن را خواهید شناخت. و اگر پاداد و گذارتان به آن جا افتاد به التماس ازتان میخواهم که عجله به خرج ندهید و درست زیر ستاره چند لحظهای توقف کنید. آن وقت اگر بچهای به طرفتان آمد، اگر خندید، اگر موهایش طلایی بود، اگر وقتی ازش سوالی کردید جوابی نداد، لابد حدس میزنید که کیست. در آن صورت لطف کنید و نگذارید من این جور افسرده خاطر بمانم:
|
||||
بی درنگ بردارید به من بنویسید که او برگشته.
|
||||
|
10000
perf/texts/fa-words.txt
10000
perf/texts/fa-words.txt
File diff suppressed because it is too large
Load Diff
10000
perf/texts/hi-words.txt
10000
perf/texts/hi-words.txt
File diff suppressed because it is too large
Load Diff
|
@ -1,250 +0,0 @@
|
|||
#
|
||||
# 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
|
|
@ -1,295 +0,0 @@
|
|||
#
|
||||
# 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
|
485
src/Makefile.am
485
src/Makefile.am
|
@ -1,6 +1,5 @@
|
|||
# Process this file with automake to produce Makefile.in
|
||||
|
||||
NULL =
|
||||
SUBDIRS =
|
||||
DIST_SUBDIRS =
|
||||
BUILT_SOURCES =
|
||||
|
@ -9,20 +8,13 @@ CLEANFILES =
|
|||
DISTCLEANFILES =
|
||||
MAINTAINERCLEANFILES =
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
|
||||
TESTS =
|
||||
check_PROGRAMS =
|
||||
|
||||
EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
|
||||
EXTRA_DIST += meson.build
|
||||
EXTRA_DIST += fix_get_types.py
|
||||
# The following warning options are useful for debugging: -Wpadded
|
||||
#AM_CXXFLAGS =
|
||||
|
||||
# Convenience targets:
|
||||
lib: $(BUILT_SOURCES) libharfbuzz.la
|
||||
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
|
||||
tiny:
|
||||
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Os -DHB_TINY $(CPPFLAGS)" libs
|
||||
tinyz:
|
||||
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Oz -DHB_TINY $(CPPFLAGS)" libs
|
||||
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
|
||||
|
||||
lib_LTLIBRARIES = libharfbuzz.la
|
||||
|
||||
|
@ -35,6 +27,17 @@ HBDEPS =
|
|||
HBSOURCES = $(HB_BASE_sources)
|
||||
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
|
||||
HBHEADERS = $(HB_BASE_headers)
|
||||
HBNODISTHEADERS = $(HB_NODIST_headers)
|
||||
|
||||
if HAVE_OT
|
||||
HBSOURCES += $(HB_OT_sources)
|
||||
HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources)
|
||||
HBHEADERS += $(HB_OT_headers)
|
||||
endif
|
||||
|
||||
if HAVE_FALLBACK
|
||||
HBSOURCES += $(HB_FALLBACK_sources)
|
||||
endif
|
||||
|
||||
if HAVE_PTHREAD
|
||||
HBCFLAGS += $(PTHREAD_CFLAGS)
|
||||
|
@ -47,20 +50,19 @@ 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)
|
||||
HBDEPS += $(FREETYPE_DEPS)
|
||||
# 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)
|
||||
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
|
||||
|
@ -69,9 +71,6 @@ 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
|
||||
|
@ -79,9 +78,6 @@ 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
|
||||
|
@ -89,19 +85,6 @@ 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
|
||||
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
|
||||
|
@ -109,22 +92,19 @@ 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
|
||||
|
||||
if HAVE_UCDN
|
||||
SUBDIRS += hb-ucdn
|
||||
HBCFLAGS += -I$(srcdir)/hb-ucdn
|
||||
HBLIBS += hb-ucdn/libhb-ucdn.la
|
||||
HBSOURCES += $(HB_UCDN_sources)
|
||||
hb-ucdn/libhb-ucdn.la: ucdn
|
||||
ucdn:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn
|
||||
endif
|
||||
DIST_SUBDIRS += hb-ucdn
|
||||
|
||||
BUILT_SOURCES += \
|
||||
hb-version.h
|
||||
|
||||
$(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac
|
||||
$(AM_V_GEN) $(SED) \
|
||||
-e 's/[@]HB_VERSION_MAJOR@/$(HB_VERSION_MAJOR)/' \
|
||||
-e 's/[@]HB_VERSION_MINOR@/$(HB_VERSION_MINOR)/' \
|
||||
-e 's/[@]HB_VERSION_MICRO@/$(HB_VERSION_MICRO)/' \
|
||||
-e 's/[@]HB_VERSION@/$(HB_VERSION)/' \
|
||||
"$<" > "$@" || ($(RM) "$@"; false)
|
||||
|
||||
# Put the library together
|
||||
|
||||
|
@ -133,78 +113,46 @@ HBLIBS += $(HBNONPCLIBS)
|
|||
if OS_WIN32
|
||||
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
|
||||
harfbuzz_gobject_def_dependency = harfbuzz-gobject.def
|
||||
chosen_linker = $(CXXLINK)
|
||||
libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
|
||||
else
|
||||
if WITH_LIBSTDCXX
|
||||
chosen_linker = $(CXXLINK)
|
||||
else
|
||||
if HAVE_GCC
|
||||
# Use a C linker for GCC, not C++; Don't link to libstdc++
|
||||
chosen_linker = $(LINK)
|
||||
if HAVE_GCC
|
||||
libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
|
||||
else
|
||||
chosen_linker = $(CXXLINK)
|
||||
endif
|
||||
libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
|
||||
endif
|
||||
endif
|
||||
|
||||
@CODE_COVERAGE_RULES@
|
||||
|
||||
base_link_flags = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
|
||||
libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS)
|
||||
libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
|
||||
libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) $(CODE_COVERAGE_LDFLAGS)
|
||||
libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS)
|
||||
libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
|
||||
libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
|
||||
libharfbuzz_la_LIBADD = $(HBLIBS)
|
||||
EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
|
||||
pkginclude_HEADERS = $(HBHEADERS)
|
||||
nodist_pkginclude_HEADERS =
|
||||
nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = harfbuzz.pc
|
||||
cmakedir = $(libdir)/cmake/harfbuzz
|
||||
cmake_DATA = harfbuzz-config.cmake
|
||||
EXTRA_DIST += hb-version.h.in hb-features.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
|
||||
EXTRA_DIST += harfbuzz.pc.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)
|
||||
libharfbuzz_subset_la_LIBADD = libharfbuzz.la
|
||||
EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency)
|
||||
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
|
||||
FUZZING_CPPFLAGS = \
|
||||
-DHB_NDEBUG \
|
||||
-DHB_MAX_NESTING_LEVEL=3 \
|
||||
-DHB_SANITIZE_MAX_EDITS=3 \
|
||||
-DHB_BUFFER_MAX_LEN_FACTOR=3 \
|
||||
-DHB_BUFFER_MAX_LEN_MIN=8 \
|
||||
-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
|
||||
-DHB_BUFFER_MAX_OPS_FACTOR=8 \
|
||||
-DHB_BUFFER_MAX_OPS_MIN=64 \
|
||||
-DHB_BUFFER_MAX_OPS_DEFAULT=1024 \
|
||||
$(NULL)
|
||||
EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
|
||||
libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
|
||||
libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
|
||||
libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
|
||||
libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
|
||||
libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
|
||||
EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
|
||||
CLEANFILES += libharfbuzz-fuzzing.la
|
||||
|
||||
if HAVE_ICU
|
||||
if HAVE_ICU_BUILTIN
|
||||
|
@ -212,32 +160,27 @@ 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)
|
||||
libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu) $(CODE_COVERAGE_LDFLAGS)
|
||||
libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
|
||||
libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
|
||||
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
|
||||
|
||||
if HAVE_GOBJECT
|
||||
lib_LTLIBRARIES += libharfbuzz-gobject.la
|
||||
libharfbuzz_gobject_la_LINK = $(chosen_linker) $(libharfbuzz_gobject_la_LDFLAGS)
|
||||
libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_DIST_sources)
|
||||
nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_NODIST_sources)
|
||||
libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(GOBJECT_CFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags) $(CODE_COVERAGE_LDFLAGS)
|
||||
libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_sources)
|
||||
nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_ENUM_sources)
|
||||
libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
|
||||
libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
|
||||
libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
|
||||
EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency)
|
||||
pkginclude_HEADERS += $(HB_GOBJECT_DIST_headers)
|
||||
nodist_pkginclude_HEADERS += $(HB_GOBJECT_NODIST_headers)
|
||||
pkginclude_HEADERS += $(HB_GOBJECT_headers)
|
||||
nodist_pkginclude_HEADERS += $(HB_GOBJECT_ENUM_headers)
|
||||
pkgconfig_DATA += harfbuzz-gobject.pc
|
||||
|
||||
BUILT_SOURCES += \
|
||||
|
@ -249,14 +192,11 @@ DISTCLEANFILES += \
|
|||
$(HB_GOBJECT_ENUM_headers) \
|
||||
$(NULL)
|
||||
hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
|
||||
$(AM_V_GEN) PYTHONIOENCODING=UTF-8 $(GLIB_MKENUMS) \
|
||||
$(AM_V_GEN) $(GLIB_MKENUMS) \
|
||||
--identifier-prefix hb_ --symbol-prefix hb_gobject \
|
||||
--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 \
|
||||
|
@ -265,27 +205,6 @@ 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' \
|
||||
|
@ -301,90 +220,64 @@ hb-features.h: hb-features.h.in $(top_builddir)/config.status
|
|||
CLEANFILES += $(pkgconfig_DATA)
|
||||
|
||||
|
||||
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated-symbols.txt
|
||||
if HAVE_GOBJECT
|
||||
DEF_FILES += harfbuzz-gobject.def
|
||||
endif
|
||||
check: $(DEF_FILES) # For check-symbols.sh
|
||||
CLEANFILES += $(DEF_FILES)
|
||||
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)
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h
|
||||
$(AM_V_GEN) PLAIN_LIST=1 $(srcdir)/gen-def.py "$@" $^
|
||||
CLEANFILES += harfbuzz.def
|
||||
harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
|
||||
$(AM_V_GEN) (echo EXPORTS; \
|
||||
(cat $^ || echo 'hb_ERROR ()' ) | \
|
||||
$(EGREP) '^hb_.* \(' | \
|
||||
sed -e 's/ (.*//' | \
|
||||
LC_ALL=C sort; \
|
||||
echo LIBRARY libharfbuzz-0.dll; \
|
||||
) >"$@"
|
||||
@ ! grep -q hb_ERROR "$@" \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
|
||||
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 \
|
||||
gen-vowel-constraints.py \
|
||||
$(NULL)
|
||||
EXTRA_DIST += $(GENERATORS)
|
||||
|
||||
unicode-tables: arabic-table indic-table use-table
|
||||
|
||||
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-arabic-table.hh \
|
||||
|| ($(RM) hb-ot-shape-complex-arabic-table.hh; false)
|
||||
|
||||
indic-table: gen-indic-table.py IndicSyllabicCategory-7.0.0.txt IndicMatraCategory-7.0.0.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-indic-table.cc \
|
||||
|| ($(RM) hb-ot-shape-complex-indic-table.cc; false)
|
||||
|
||||
use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > hb-ot-shape-complex-use-table.cc \
|
||||
|| ($(RM) hb-ot-shape-complex-use-table.cc; false)
|
||||
|
||||
built-sources: $(BUILT_SOURCES)
|
||||
|
||||
.PHONY: built-sources
|
||||
.PHONY: unicode-tables arabic-table indic-table use-table built-sources
|
||||
|
||||
RAGEL_GENERATED = \
|
||||
$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
|
||||
$(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \
|
||||
$(NULL)
|
||||
BUILT_SOURCES += $(RAGEL_GENERATED)
|
||||
EXTRA_DIST += \
|
||||
$(HB_BASE_RAGEL_sources) \
|
||||
$(HB_OT_RAGEL_sources) \
|
||||
$(NULL)
|
||||
# We decided to add ragel-generated files to git...
|
||||
#MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
|
||||
MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
|
||||
$(srcdir)/%.hh: $(srcdir)/%.rl
|
||||
$(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
harfbuzz.cc: Makefile.sources
|
||||
$(AM_V_GEN) \
|
||||
LANG=C; \
|
||||
for f in \
|
||||
$(HB_BASE_sources) \
|
||||
$(HB_GLIB_sources) \
|
||||
$(HB_FT_sources) \
|
||||
$(HB_GRAPHITE2_sources) \
|
||||
$(HB_UNISCRIBE_sources) \
|
||||
$(HB_GDI_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
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
main \
|
||||
test \
|
||||
test-buffer-serialize \
|
||||
test-ot-meta \
|
||||
test-ot-name \
|
||||
test-ot-glyphname \
|
||||
test-gpos-size-params \
|
||||
test-gsub-get-alternates \
|
||||
test-gsub-would-substitute \
|
||||
test-use-table \
|
||||
test-size-params \
|
||||
test-would-substitute \
|
||||
$(NULL)
|
||||
bin_PROGRAMS =
|
||||
|
||||
|
@ -396,178 +289,65 @@ test_SOURCES = test.cc
|
|||
test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
test_would_substitute_SOURCES = test-would-substitute.cc
|
||||
test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
test_size_params_SOURCES = test-size-params.cc
|
||||
test_size_params_CPPFLAGS = $(HBCFLAGS)
|
||||
test_size_params_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_buffer_serialize_SOURCES = test-buffer-serialize.cc
|
||||
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
|
||||
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_meta_SOURCES = test-ot-meta.cc
|
||||
test_ot_meta_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_meta_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_name_SOURCES = test-ot-name.cc
|
||||
test_ot_name_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_name_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_glyphname_SOURCES = test-ot-glyphname.cc
|
||||
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_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)
|
||||
|
||||
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)
|
||||
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
|
||||
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
check_PROGRAMS += $(COMPILED_TESTS)
|
||||
TESTS += $(COMPILED_TESTS)
|
||||
|
||||
test_algs_SOURCES = test-algs.cc hb-static.cc
|
||||
test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_algs_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_array_SOURCES = test-array.cc
|
||||
test_array_CPPFLAGS = $(HBCFLAGS)
|
||||
test_array_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_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 hb-static.cc
|
||||
test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_iter_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
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
|
||||
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
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)
|
||||
check: harfbuzz.def # For check-defs.sh
|
||||
|
||||
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 \
|
||||
check-c-linkage-decls.sh \
|
||||
check-defs.sh \
|
||||
check-externs.sh \
|
||||
check-header-guards.sh \
|
||||
check-includes.sh \
|
||||
check-libstdc++.sh \
|
||||
check-static-inits.sh \
|
||||
check-symbols.sh \
|
||||
$(NULL)
|
||||
TESTS += $(dist_check_SCRIPTS)
|
||||
|
||||
if !WITH_LIBSTDCXX
|
||||
dist_check_SCRIPTS += \
|
||||
check-libstdc++.py \
|
||||
check_PROGRAMS = \
|
||||
test-ot-tag \
|
||||
$(NULL)
|
||||
endif
|
||||
test_ot_tag_SOURCES = hb-ot-tag.cc
|
||||
test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
|
||||
test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
|
||||
TESTS_ENVIRONMENT = \
|
||||
srcdir="$(srcdir)" \
|
||||
base_srcdir="$(srcdir)" \
|
||||
builddir="$(builddir)" \
|
||||
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
|
||||
HBSOURCES="$(HBSOURCES)" \
|
||||
HBHEADERS="$(HBHEADERS)" \
|
||||
LDD="$(LDD)" \
|
||||
NM="$(NM)" \
|
||||
OBJDUMP="$(OBJDUMP)" \
|
||||
OTOOL="$(OTOOL)" \
|
||||
HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?!
|
||||
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_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
|
||||
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 freetype2-2.0
|
||||
HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
|
||||
HarfBuzz_0_0_gir_CFLAGS = \
|
||||
$(INCLUDES) \
|
||||
$(HBCFLAGS) \
|
||||
-DHB_NO_SINGLE_HEADER_ERROR \
|
||||
-DHAVE_GOBJECT \
|
||||
-DHB_H \
|
||||
-DHB_H_IN \
|
||||
-DHB_OT_H \
|
||||
-DHB_OT_H_IN \
|
||||
-DHB_GOBJECT_H \
|
||||
-DHB_GOBJECT_H_IN \
|
||||
-DHB_EXTERN= \
|
||||
$(NULL)
|
||||
HarfBuzz_0_0_gir_LIBS = \
|
||||
|
@ -576,9 +356,12 @@ HarfBuzz_0_0_gir_LIBS = \
|
|||
$(NULL)
|
||||
HarfBuzz_0_0_gir_FILES = \
|
||||
$(HBHEADERS) \
|
||||
$(HBNODISTHEADERS) \
|
||||
$(HBSOURCES) \
|
||||
$(HB_GOBJECT_ENUM_sources) \
|
||||
$(HB_GOBJECT_ENUM_headers) \
|
||||
$(HB_GOBJECT_sources) \
|
||||
$(HB_GOBJECT_headers) \
|
||||
$(HB_GOBJECT_STRUCTS_headers) \
|
||||
$(NULL)
|
||||
|
||||
girdir = $(datadir)/gir-1.0
|
||||
|
|
|
@ -1,321 +1,162 @@
|
|||
NULL =
|
||||
|
||||
# Base and default-included sources and headers
|
||||
|
||||
HB_BASE_sources = \
|
||||
hb-aat-layout-ankr-table.hh \
|
||||
hb-aat-layout-bsln-table.hh \
|
||||
hb-aat-layout-common.hh \
|
||||
hb-aat-layout-feat-table.hh \
|
||||
hb-aat-layout-just-table.hh \
|
||||
hb-aat-layout-kerx-table.hh \
|
||||
hb-aat-layout-morx-table.hh \
|
||||
hb-aat-layout-opbd-table.hh \
|
||||
hb-aat-layout-trak-table.hh \
|
||||
hb-aat-layout.cc \
|
||||
hb-aat-layout.hh \
|
||||
hb-aat-ltag-table.hh \
|
||||
hb-aat-map.cc \
|
||||
hb-aat-map.hh \
|
||||
hb-algs.hh \
|
||||
hb-array.hh \
|
||||
hb-atomic.hh \
|
||||
hb-bimap.hh \
|
||||
hb-bit-page.hh \
|
||||
hb-bit-set.hh \
|
||||
hb-bit-set-invertible.hh \
|
||||
hb-atomic-private.hh \
|
||||
hb-blob.cc \
|
||||
hb-blob.hh \
|
||||
hb-buffer-private.hh \
|
||||
hb-buffer-serialize.cc \
|
||||
hb-buffer-verify.cc \
|
||||
hb-buffer.cc \
|
||||
hb-buffer.hh \
|
||||
hb-cache.hh \
|
||||
hb-cff-interp-common.hh \
|
||||
hb-cff-interp-cs-common.hh \
|
||||
hb-cff-interp-dict-common.hh \
|
||||
hb-cff1-interp-cs.hh \
|
||||
hb-cff2-interp-cs.hh \
|
||||
hb-common.cc \
|
||||
hb-config.hh \
|
||||
hb-debug.hh \
|
||||
hb-dispatch.hh \
|
||||
hb-draw.cc \
|
||||
hb-draw.hh \
|
||||
hb-dsalgs.hh \
|
||||
hb-face-private.hh \
|
||||
hb-face.cc \
|
||||
hb-face.hh \
|
||||
hb-face-builder.cc \
|
||||
hb-fallback-shape.cc \
|
||||
hb-font-private.hh \
|
||||
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-meta.hh \
|
||||
hb-ms-feature-ranges.hh \
|
||||
hb-multimap.hh \
|
||||
hb-mutex.hh \
|
||||
hb-null.hh \
|
||||
hb-number.cc \
|
||||
hb-number.hh \
|
||||
hb-object.hh \
|
||||
hb-open-file.hh \
|
||||
hb-open-type.hh \
|
||||
hb-ot-cff-common.hh \
|
||||
hb-ot-cff1-std-str.hh \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-ot-cff1-table.hh \
|
||||
hb-ot-cff2-table.cc \
|
||||
hb-ot-cff2-table.hh \
|
||||
hb-mutex-private.hh \
|
||||
hb-object-private.hh \
|
||||
hb-open-file-private.hh \
|
||||
hb-open-type-private.hh \
|
||||
hb-ot-cbdt-table.hh \
|
||||
hb-ot-cmap-table.hh \
|
||||
hb-ot-color.cc \
|
||||
hb-ot-face-table-list.hh \
|
||||
hb-ot-face.cc \
|
||||
hb-ot-face.hh \
|
||||
hb-ot-font.cc \
|
||||
hb-ot-gasp-table.hh \
|
||||
hb-ot-glyf-table.hh \
|
||||
hb-ot-hdmx-table.hh \
|
||||
hb-ot-head-table.hh \
|
||||
hb-ot-hhea-table.hh \
|
||||
hb-ot-hmtx-table.hh \
|
||||
hb-ot-kern-table.hh \
|
||||
hb-ot-layout-base-table.hh \
|
||||
hb-ot-layout-common.hh \
|
||||
hb-ot-layout-gdef-table.hh \
|
||||
hb-ot-layout-gpos-table.hh \
|
||||
hb-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 \
|
||||
hb-ot-layout.hh \
|
||||
hb-ot-map.cc \
|
||||
hb-ot-map.hh \
|
||||
hb-ot-math-table.hh \
|
||||
hb-ot-math.cc \
|
||||
hb-ot-maxp-table.hh \
|
||||
hb-ot-meta-table.hh \
|
||||
hb-ot-meta.cc \
|
||||
hb-ot-metrics.cc \
|
||||
hb-ot-metrics.hh \
|
||||
hb-ot-name-language-static.hh \
|
||||
hb-ot-name-language.hh \
|
||||
hb-ot-name-table.hh \
|
||||
hb-ot-name.cc \
|
||||
hb-ot-os2-table.hh \
|
||||
hb-ot-os2-unicode-ranges.hh \
|
||||
hb-ot-post-macroman.hh \
|
||||
hb-ot-post-table.hh \
|
||||
hb-ot-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 \
|
||||
hb-ot-shape-normalize.hh \
|
||||
hb-ot-shape.cc \
|
||||
hb-ot-shape.hh \
|
||||
hb-ot-stat-table.hh \
|
||||
hb-ot-tag-table.hh \
|
||||
hb-ot-tag.cc \
|
||||
hb-ot-var-avar-table.hh \
|
||||
hb-ot-var-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 \
|
||||
hb-ot-var-mvar-table.hh \
|
||||
hb-ot-var.cc \
|
||||
hb-ot-vorg-table.hh \
|
||||
hb-pool.hh \
|
||||
hb-sanitize.hh \
|
||||
hb-serialize.hh \
|
||||
hb-set-digest.hh \
|
||||
hb-private.hh \
|
||||
hb-set-digest-private.hh \
|
||||
hb-set-private.hh \
|
||||
hb-set.cc \
|
||||
hb-set.hh \
|
||||
hb-shape-plan.cc \
|
||||
hb-shape-plan.hh \
|
||||
hb-shape.cc \
|
||||
hb-shaper-impl.hh \
|
||||
hb-shape-plan-private.hh \
|
||||
hb-shape-plan.cc \
|
||||
hb-shaper-list.hh \
|
||||
hb-shaper-impl-private.hh \
|
||||
hb-shaper-private.hh \
|
||||
hb-shaper.cc \
|
||||
hb-shaper.hh \
|
||||
hb-static.cc \
|
||||
hb-string-array.hh \
|
||||
hb-style.cc \
|
||||
hb-ucd-table.hh \
|
||||
hb-ucd.cc \
|
||||
hb-unicode-emoji-table.hh \
|
||||
hb-unicode-private.hh \
|
||||
hb-unicode.cc \
|
||||
hb-unicode.hh \
|
||||
hb-utf.hh \
|
||||
hb-vector.hh \
|
||||
hb-priority-queue.hh \
|
||||
hb.hh \
|
||||
hb-utf-private.hh \
|
||||
hb-warning.cc \
|
||||
$(NULL)
|
||||
|
||||
HB_BASE_RAGEL_GENERATED_sources = \
|
||||
hb-buffer-deserialize-json.hh \
|
||||
hb-buffer-deserialize-text-glyphs.hh \
|
||||
hb-buffer-deserialize-text-unicode.hh \
|
||||
hb-number-parser.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 \
|
||||
hb-buffer-deserialize-text.hh \
|
||||
$(NULL)
|
||||
HB_BASE_RAGEL_sources = \
|
||||
hb-buffer-deserialize-json.rl \
|
||||
hb-buffer-deserialize-text-glyphs.rl \
|
||||
hb-buffer-deserialize-text-unicode.rl \
|
||||
hb-number-parser.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 \
|
||||
hb-buffer-deserialize-text.rl \
|
||||
$(NULL)
|
||||
|
||||
HB_BASE_headers = \
|
||||
hb-aat-layout.h \
|
||||
hb-aat.h \
|
||||
hb.h \
|
||||
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 \
|
||||
hb-ot-color.h \
|
||||
hb-ot-deprecated.h \
|
||||
hb-set.h \
|
||||
hb-shape.h \
|
||||
hb-shape-plan.h \
|
||||
hb-unicode.h \
|
||||
$(NULL)
|
||||
|
||||
HB_NODIST_headers = \
|
||||
hb-version.h \
|
||||
$(NULL)
|
||||
|
||||
HB_FALLBACK_sources = \
|
||||
hb-fallback-shape.cc \
|
||||
$(NULL)
|
||||
|
||||
HB_OT_sources = \
|
||||
hb-aat-layout.cc \
|
||||
hb-aat-layout-common-private.hh \
|
||||
hb-aat-layout-morx-table.hh \
|
||||
hb-aat-layout-private.hh \
|
||||
hb-ot-font.cc \
|
||||
hb-ot-layout.cc \
|
||||
hb-ot-layout-common-private.hh \
|
||||
hb-ot-layout-gdef-table.hh \
|
||||
hb-ot-layout-gpos-table.hh \
|
||||
hb-ot-layout-gsubgpos-private.hh \
|
||||
hb-ot-layout-gsub-table.hh \
|
||||
hb-ot-layout-jstf-table.hh \
|
||||
hb-ot-layout-private.hh \
|
||||
hb-ot-map.cc \
|
||||
hb-ot-map-private.hh \
|
||||
hb-ot-math.cc \
|
||||
hb-ot-math-table.hh \
|
||||
hb-ot-shape.cc \
|
||||
hb-ot-shape-complex-arabic.cc \
|
||||
hb-ot-shape-complex-arabic-fallback.hh \
|
||||
hb-ot-shape-complex-arabic-private.hh \
|
||||
hb-ot-shape-complex-arabic-table.hh \
|
||||
hb-ot-shape-complex-arabic-win1256.hh \
|
||||
hb-ot-shape-complex-default.cc \
|
||||
hb-ot-shape-complex-hangul.cc \
|
||||
hb-ot-shape-complex-hebrew.cc \
|
||||
hb-ot-shape-complex-indic.cc \
|
||||
hb-ot-shape-complex-indic-private.hh \
|
||||
hb-ot-shape-complex-indic-table.cc \
|
||||
hb-ot-shape-complex-khmer.cc \
|
||||
hb-ot-shape-complex-myanmar.cc \
|
||||
hb-ot-shape-complex-thai.cc \
|
||||
hb-ot-shape-complex-tibetan.cc \
|
||||
hb-ot-shape-complex-use.cc \
|
||||
hb-ot-shape-complex-use-private.hh \
|
||||
hb-ot-shape-complex-use-table.cc \
|
||||
hb-ot-shape-complex-private.hh \
|
||||
hb-ot-shape-normalize-private.hh \
|
||||
hb-ot-shape-normalize.cc \
|
||||
hb-ot-shape-fallback-private.hh \
|
||||
hb-ot-shape-fallback.cc \
|
||||
hb-ot-shape-private.hh \
|
||||
hb-ot-var.cc \
|
||||
hb-ot-var-avar-table.hh \
|
||||
hb-ot-var-fvar-table.hh \
|
||||
hb-ot-var-hvar-table.hh \
|
||||
hb-ot-var-mvar-table.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_OT_RAGEL_GENERATED_sources = \
|
||||
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 \
|
||||
$(NULL)
|
||||
HB_OT_RAGEL_sources = \
|
||||
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 \
|
||||
$(NULL)
|
||||
|
||||
HB_OT_headers = \
|
||||
hb-ot.h \
|
||||
hb-ot-font.h \
|
||||
hb-ot-layout.h \
|
||||
hb-ot-math.h \
|
||||
hb-ot-meta.h \
|
||||
hb-ot-metrics.h \
|
||||
hb-ot-name.h \
|
||||
hb-ot-shape.h \
|
||||
hb-ot-tag.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 \
|
||||
$(NULL)
|
||||
|
||||
# Optional Sources and Headers with external deps
|
||||
|
||||
HB_FT_sources = hb-ft.cc hb-ft-colr.hh
|
||||
HB_FT_sources = hb-ft.cc
|
||||
HB_FT_headers = hb-ft.h
|
||||
|
||||
HB_GLIB_sources = hb-glib.cc
|
||||
|
@ -332,73 +173,18 @@ HB_CORETEXT_headers = hb-coretext.h
|
|||
HB_DIRECTWRITE_sources = hb-directwrite.cc
|
||||
HB_DIRECTWRITE_headers = hb-directwrite.h
|
||||
|
||||
HB_GDI_sources = hb-gdi.cc
|
||||
HB_GDI_headers = hb-gdi.h
|
||||
|
||||
HB_UNISCRIBE_sources = hb-uniscribe.cc
|
||||
HB_UNISCRIBE_headers = hb-uniscribe.h
|
||||
|
||||
# Additional supplemental sources
|
||||
HB_UCDN_sources = hb-ucdn.cc
|
||||
|
||||
# Sources for libharfbuzz-gobject and libharfbuzz-icu
|
||||
HB_ICU_sources = hb-icu.cc
|
||||
HB_ICU_headers = hb-icu.h
|
||||
|
||||
# Sources for libharfbuzz-subset
|
||||
HB_SUBSET_sources = \
|
||||
hb-number.cc \
|
||||
hb-number.hh \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-ot-cff2-table.cc \
|
||||
hb-ot-post-table-v2subset.hh \
|
||||
hb-static.cc \
|
||||
hb-subset-cff-common.cc \
|
||||
hb-subset-cff-common.hh \
|
||||
hb-subset-cff1.cc \
|
||||
hb-subset-cff1.hh \
|
||||
hb-subset-cff2.cc \
|
||||
hb-subset-cff2.hh \
|
||||
hb-subset-input.cc \
|
||||
hb-subset-input.hh \
|
||||
hb-subset-instancer-solver.cc \
|
||||
hb-subset-accelerator.hh \
|
||||
hb-subset-plan.cc \
|
||||
hb-subset-plan.hh \
|
||||
hb-subset-repacker.cc \
|
||||
hb-subset.cc \
|
||||
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
|
||||
HB_GOBJECT_DIST_headers = hb-gobject.h hb-gobject-structs.h
|
||||
HB_GOBJECT_sources = hb-gobject-structs.cc
|
||||
HB_GOBJECT_STRUCTS_headers = hb-gobject-structs.h
|
||||
HB_GOBJECT_headers = hb-gobject.h $(HB_GOBJECT_STRUCTS_headers)
|
||||
HB_GOBJECT_ENUM_sources = hb-gobject-enums.cc
|
||||
HB_GOBJECT_ENUM_headers = hb-gobject-enums.h
|
||||
HB_GOBJECT_NODIST_sources = $(HB_GOBJECT_ENUM_sources)
|
||||
HB_GOBJECT_NODIST_headers = $(HB_GOBJECT_ENUM_headers)
|
||||
HB_GOBJECT_sources = $(HB_GOBJECT_DIST_sources) $(HB_GOBJECT_NODIST_sources)
|
||||
HB_GOBJECT_headers = $(HB_GOBJECT_DIST_headers) $(HB_GOBJECT_NODIST_headers)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* 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 */
|
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* 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 palette’s 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 */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue