This commit is contained in:
Nathan Willis 2019-04-14 15:42:42 +01:00
commit ad12603664
1058 changed files with 42406 additions and 15760 deletions

17
.ci/build-freetype.sh Normal file
View File

@ -0,0 +1,17 @@
#!/bin/bash
set -x
set -o errexit -o nounset
# 22.0.16 is the libtool version of 2.9.0
if pkg-config --atleast-version 22.0.16 freetype2; then exit; fi
pushd $HOME
wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2
tar xf freetype-2.9.tar.bz2
pushd freetype-2.9
./autogen.sh
./configure --prefix=$HOME/.local
make -j4 install
popd
popd

View File

@ -2,40 +2,45 @@ version: 2
jobs:
macos-llvm-gcc-4.2:
macos-10.12.6-aat-fonts:
macos:
xcode: "8.3.3"
xcode: "9.2.0"
steps:
- checkout
- run: brew update-reset
- run: brew install wget pkg-config libtool ragel freetype glib cairo
- run: wget https://packages.macports.org/llvm-gcc42/llvm-gcc42-2336.11_3+universal.darwin_15.i386-x86_64.tbz2 && tar zxvf llvm-gcc42-2336.11_3+universal.darwin_15.i386-x86_64.tbz2
- run: CC=$PWD/opt/local/bin/llvm-gcc-4.2 CXX=$PWD/opt/local/bin/llvm-g++-4.2 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
# Ignoring assembler complains, https://stackoverflow.com/a/39867021
- run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
- run: make -j4
- run: make check || .ci/fail.sh
macos-notest-apple-gcc-i686-4.2:
macos-10.13.6-aat-fonts:
macos:
xcode: "8.3.3"
xcode: "10.1.0"
steps:
- checkout
- run: brew update-reset
- run: brew install wget pkg-config libtool ragel
- run: wget https://packages.macports.org/apple-gcc42/apple-gcc42-5666.3_15+universal.darwin_15.i386-x86_64.tbz2 && tar zxvf apple-gcc42-5666.3_15+universal.darwin_15.i386-x86_64.tbz2
- run: CPP=$PWD/opt/local/bin/i686-apple-darwin15-cpp-apple-4.2.1 CC=$PWD/opt/local/bin/i686-apple-darwin15-gcc-apple-4.2.1 CXX=$PWD/opt/local/bin/i686-apple-darwin15-g++-apple-4.2.1 ./autogen.sh
# Ignoring assembler complains, https://stackoverflow.com/a/39867021
- run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
- run: make -j4
- run: make check || .ci/fail.sh
macos-10.14.3-aat-fonts:
macos:
xcode: "10.2.0"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2
- run: export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig" && ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-coretext --with-graphite2
- run: make -j4
- run: make check || .ci/fail.sh
distcheck:
docker:
- image: ubuntu:17.10
steps:
- checkout
- run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: ./autogen.sh
- run: make
- run: make -j32
- run: make distcheck || .ci/fail.sh
- run: rm -rf harfbuzz-*
- run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
@ -45,40 +50,66 @@ jobs:
- image: alpine
steps:
- checkout
- run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev
- run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev python
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
- run: make
- run: make -j32
- run: make check || .ci/fail.sh
archlinux-debug-O0-py3:
archlinux-py3-all:
docker:
- image: base/devel
- image: archlinux/base
steps:
- checkout
- run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip
- run: pip install fonttools
- run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip make which base-devel
- run: pip install flake8 fonttools
- run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: make
- run: make check || .ci/fail.sh
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: make -j32 CPPFLAGS="-Werror"
- run: make check CPPFLAGS="-Werror" || .ci/fail.sh
## Doesn't play well with CircleCI apparently
#void-notest:
# docker:
# - image: voidlinux/voidlinux
# steps:
# - checkout
# - run: xbps-install -Suy freetype gettext gcc glib graphite pkg-config ragel libtool autoconf automake make
# - run: ./autogen.sh && make -j32 && make check
clang-O3-O0:
docker:
- image: multiarch/crossbuild
- image: ubuntu:18.10
steps:
- checkout
- run: apt update || true
- run: apt install -y ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: apt install -y clang wget autoconf automake libtool pkg-config ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd ..
- run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
- run: make -j32
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
- run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
- run: make -j32
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
gcc-valgrind:
docker:
- image: ubuntu:18.10
steps:
- checkout
- run: apt update || true
- run: apt install -y gcc binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip valgrind
- run: pip install fonttools
- run: ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
- run: make -j32
# run-shape-fuzzer-tests.py automatically runs valgrind if see available
# but test/api runs it by request, we probably should normalize the approaches
- run: RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
# informational for now
- run: make -Ctest/api check-symbols || true
clang-everything:
docker:
- image: ubuntu:18.10
@ -89,11 +120,11 @@ jobs:
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
- run: apt update || true
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: CFLAGS="-Weverything -Wno-padded -Wno-cast-qual -Wno-sign-conversion -Wno-conversion" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-conversion -Wno-sign-conversion -Wno-c++98-compat -Wno-extra-semi -Wno-c++98-compat-pedantic -Wno-documentation-unknown-command -Wno-padded -Wno-shift-sign-overflow -Wno-missing-field-initializers -Wno-double-promotion -Wno-reserved-id-macro -Wno-cast-qual -Wno-unused-parameter -Wno-comma -Wno-shadow -Wno-used-but-marked-unused -Wno-format-pedantic -Wno-zero-as-null-pointer-constant -Wno-disabled-macro-expansion -Wno-covered-switch-default -Wno-conditional-uninitialized -Wno-unreachable-code -Wno-unused-macros -Wno-float-equal -Wno-missing-prototypes" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: make check || .ci/fail.sh
- run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
- run: make -j32 CPPFLAGS="-Werror"
- run: make check CPPFLAGS="-Werror" || .ci/fail.sh
clang-asan:
docker:
@ -108,7 +139,7 @@ jobs:
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: CPPFLAGS="-fsanitize=address" LDFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: make -j32
- run: make check || .ci/fail.sh | asan_symbolize | c++filt
clang-msan:
@ -121,11 +152,13 @@ jobs:
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
- run: apt update || true
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: apt install -y clang lld binutils libtool autoconf automake gtk-doc-tools gettext make pkg-config ragel libcairo2-dev libicu-dev libmount-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt
- run: update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 10
- run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
- run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu
- run: make -j32 && MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt
clang-tsan:
docker:
@ -139,10 +172,9 @@ jobs:
- run: apt update || true
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh && ./configure && make -j4 && cd ..
- run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh | asan_symbolize | c++filt
- run: make -j32
- run: make check || .ci/fail.sh | asan_symbolize | c++filt
clang-ubsan:
docker:
@ -157,16 +189,16 @@ jobs:
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: make -j32
- run: make check || .ci/fail.sh | asan_symbolize | c++filt
fedora-outoftreebuild:
fedora-O0-debug-outoftreebuild:
docker:
- image: fedora
steps:
- checkout
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python || true
- run: NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: mkdir build && cd build && ../configure && make && (make check || ../.ci/fail.sh)
cmake-gcc:
@ -189,18 +221,19 @@ jobs:
- run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
- run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
- run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
- run: make -Cbuild
- run: make -Cbuild -j32
- run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
- run: make -Cbuild install
crosscompile-notest-djgpp:
docker:
# https://gist.github.com/ebraminio/8551fc74f27951e668102baa2f6b1175
- image: quay.io/ebraminio/djgpp
steps:
- checkout
- run: apt update && apt install -y ragel pkg-config libtool autoconf
- run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp
- run: make
- run: make -j32
crosscompile-notest-freebsd9:
docker:
@ -209,24 +242,23 @@ jobs:
- checkout
- run: apt update && apt install -y pkg-config ragel
- run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9
- run: make
- run: make -j32
crosscompile-notest-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: echo "#""!""/bin/true" > /usr/bin/ragel && chmod +x /usr/bin/ragel
- run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
- run: make
- run: make -j32
crosscompile-cmake-notest-android-arm:
docker:
- image: dockcross/android-arm
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
@ -235,7 +267,6 @@ jobs:
- image: dockcross/browser-asmjs
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
@ -244,7 +275,6 @@ jobs:
- image: dockcross/linux-arm64
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
@ -253,44 +283,45 @@ jobs:
- image: dockcross/linux-mips
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
crosscompile-cmake-notest-windows-x64:
docker:
- image: dockcross/windows-x64
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
#crosscompile-cmake-notest-windows-x64:
# docker:
# - image: dockcross/windows-x64
# steps:
# - checkout
# - run: cmake -Bbuild -H. -GNinja
# - run: ninja -Cbuild
workflows:
version: 2
build:
jobs:
# macOS
- macos-llvm-gcc-4.2
- macos-notest-apple-gcc-i686-4.2
- macos-10.12.6-aat-fonts
- macos-10.13.6-aat-fonts
- macos-10.14.3-aat-fonts
# both autotools and cmake
- distcheck
# autotools based builds
- alpine-O3-NOMMAP
- archlinux-debug-O0-py3
- archlinux-py3-all
#- void-notest
- gcc-valgrind
- clang-O3-O0
- clang-everything
- clang-asan
#- clang-msan # https://github.com/harfbuzz/harfbuzz/issues/1175
- clang-msan
- clang-tsan
- clang-ubsan
- fedora-outoftreebuild
- fedora-O0-debug-outoftreebuild
# cmake based builds
- cmake-gcc
- cmake-oracledeveloperstudio
#- cmake-oracledeveloperstudio
# crosscompiles
# they can't be test thus are without tests
@ -304,4 +335,4 @@ workflows:
- crosscompile-cmake-notest-browser-asmjs
- crosscompile-cmake-notest-linux-arm64
- crosscompile-cmake-notest-linux-mips
- crosscompile-cmake-notest-windows-x64
#- crosscompile-cmake-notest-windows-x64

38
.clang-format Normal file
View File

@ -0,0 +1,38 @@
# 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

7
.codecov.yml Normal file
View File

@ -0,0 +1,7 @@
comment: off
coverage:
status:
project:
default:
threshold: 1%

View File

@ -7,9 +7,9 @@ end_of_line = lf
insert_final_newline = true
[*.{c,cc,h,hh}]
tab_width = 8
indent_size = 2
indent_style = space
tab_width = 8
[*.{py,sh}]
indent_style = tab

View File

@ -6,21 +6,20 @@ language: cpp
env:
global:
- CPPFLAGS=""
- CFLAGS="-Werror -Werror=unused -Werror=unused-function"
- CXXFLAGS="-Werror -Werror=unused -Werror=unused-function -Wno-deprecated-register" # glib uses register and clang raises a warning
- CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
- NOCONFIGURE=1
# COVERITY_SCAN_TOKEN
- secure: "MRJtVu/fQoWNwMAamvIJBCX/1SMvEuEUk/ljAif/y2/3syyWgxFGp17UGnDILdoZYyCqTM+jQciY2P0nVqbjjOAUlML4QOAalqw8kPp8iTsnHUe+KOMVrOVP6p6qAQxk1im1O41cCMkmVKvk+NXe/on5euz6LGF2laHZaOAMoes="
- secure: "k6l/18dpsoPAf0E5RQWCr+rgjbHns0H3k0WzSYovCoVg0B7RVlV8x8OjyEOBzEvXI4aaHRdH6MHCPDFnX4fa7ysImlT6LxxIG8YhDdLkJWyS0hHbcJiGxko9AhAGzOZcDl8fZi13d697wagMqqXpjN5v2T/AQm8t4X9z2otJosY="
matrix:
include:
- os: linux
compiler: gcc
script:
# Remove these two lines when Travis updated its distro
- wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
# Remove the following three lines when Travis updates its distro
- export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
- export LD_LIBRARY_PATH="$HOME/.local/lib"
- bash .ci/build-freetype.sh
- ./autogen.sh
- ./configure $CONFIGURE_OPTS --enable-gtk-doc --enable-code-coverage
@ -28,42 +27,32 @@ matrix:
- make check || .ci/fail.sh
- rm -rf freetype-2.9
after_success:
- bash .ci/run-coveralls.sh # for coveralls.io code coverage tracking
- bash .ci/run-coveralls.sh # coveralls.io code coverage
- bash <(curl -s https://codecov.io/bash) # codecov.io code coverage
- bash .ci/deploy-docs.sh
- bash .ci/trigger-coverity.sh
- os: linux
compiler: clang
script:
# Remove these two lines when Travis updated its distro
- wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
# Remove the following three lines when Travis updates its distro
- export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
- export LD_LIBRARY_PATH="$HOME/.local/lib"
- bash .ci/build-freetype.sh
- ./autogen.sh
- ./configure $CONFIGURE_OPTS
- make
- make check || .ci/fail.sh
- 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 || true
- brew link --force icu4c # icu4c is keg-only
script:
- ./autogen.sh
- ./configure $CONFIGURE_OPTS --with-coretext
- make
- make check || .ci/fail.sh
notifications:
irc: "irc.freenode.org#harfbuzz"
email: harfbuzz-bots-chatter@googlegroups.com
cache:
directories:
- /home/travis/.local
addons:
apt:
packages:

16
AUTHORS
View File

@ -1,9 +1,11 @@
Behdad Esfahbod
Simon Hausmann
Martin Hosken
Jonathan Kew
Lars Knoll
Werner Lemberg
Roozbeh Pournader
Owen Taylor
David Turner
Ebrahim Byagowi
Jonathan Kew
Khaled Hosny
Lars Knoll
Martin Hosken
Owen Taylor
Roozbeh Pournader
Simon Hausmann
Werner Lemberg

View File

@ -26,7 +26,7 @@ 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/`.
If you are bootstraping from git, you need a few more tools before you can
If you are bootstrapping from git, you need a few more tools before you can
run `autogen.sh` for the first time. Namely, `pkg-config` and `ragel`.
Again, on Ubuntu / Debian:

View File

@ -52,6 +52,9 @@ if (HB_BUILD_UTILS)
set (HB_HAVE_FREETYPE ON)
endif ()
option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON)
option(HB_BUILD_TESTS "Build harfbuzz tests" ON)
option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
if (HB_HAVE_GOBJECT)
set (HB_HAVE_GLIB ON)
@ -87,7 +90,6 @@ include_directories(AFTER
${PROJECT_BINARY_DIR}/src
)
add_definitions(-DHAVE_OT)
add_definitions(-DHAVE_FALLBACK)
# We need PYTHON_EXECUTABLE to be set for running the tests...
@ -98,10 +100,10 @@ include (CheckFunctionExists)
include (CheckIncludeFile)
macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
foreach (func_name ${ARGN})
string(TOUPPER ${func_name} definiton_to_add)
check_function_exists(${func_name} HAVE_${definiton_to_add})
if (${HAVE_${definiton_to_add}})
add_definitions(-DHAVE_${definiton_to_add})
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})
endif ()
endforeach ()
endmacro ()
@ -166,10 +168,6 @@ extract_make_variable(HB_BASE_headers ${SRCSOURCES})
add_prefix_to_list(HB_BASE_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_SUBSET_sources ${SRCSOURCES})
add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
@ -178,13 +176,10 @@ extract_make_variable(HB_SUBSET_headers ${SRCSOURCES})
add_prefix_to_list(HB_SUBSET_headers "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES})
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/")
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})
@ -210,7 +205,7 @@ set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
## Define ragel tasks
# if (NOT IN_HB_DIST)
# foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_RAGEL_GENERATED_sources})
# foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources})
# string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
# set (target_name ${CMAKE_MATCH_1})
# add_custom_command(OUTPUT ${ragel_output}
@ -244,8 +239,6 @@ set (project_sources
${HB_BASE_RAGEL_GENERATED_sources}
${HB_FALLBACK_sources}
${HB_OT_sources}
${HB_OT_RAGEL_GENERATED_sources}
)
set (subset_project_sources
@ -258,7 +251,6 @@ set (project_headers
#${HB_VERSION_H}
${HB_BASE_headers}
${HB_OT_headers}
)
set (subset_project_headers
@ -359,12 +351,32 @@ if (APPLE AND HB_HAVE_CORETEXT)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
if (APPLICATION_SERVICES_FRAMEWORK)
list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
endif (APPLICATION_SERVICES_FRAMEWORK)
if (HB_IOS)
find_library(COREFOUNDATION CoreFoundation)
if (COREFOUNDATION)
list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
endif ()
mark_as_advanced(COREFOUNDATION)
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
find_library(CORETEXT CoreText)
if (CORETEXT)
list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
endif ()
mark_as_advanced(CORETEXT)
find_library(COREGRAPHICS CoreGraphics)
if (COREGRAPHICS)
list(APPEND THIRD_PARTY_LIBS ${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})
endif ()
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
endif ()
endif ()
if (WIN32 AND HB_HAVE_UNISCRIBE)
@ -527,18 +539,20 @@ add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_heade
target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
## Define harfbuzz-subset library
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
add_dependencies(harfbuzz-subset harfbuzz)
target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
if (HB_BUILD_SUBSET)
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
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)
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)
CHECK_CXX_COMPILER_FLAG(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
if (CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
link_libraries(-Bsymbolic-functions)
endif ()
@ -549,13 +563,23 @@ if (UNIX OR MINGW)
set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm
set (CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set_target_properties(harfbuzz PROPERTIES LINKER_LANGUAGE C)
set_target_properties(harfbuzz-subset 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
if (HB_HAVE_GOBJECT)
add_library(harfbuzz-gobject
@ -574,7 +598,7 @@ if (HB_HAVE_GOBJECT)
endif ()
if (BUILD_SHARED_LIBS AND WIN32 AND NOT MINGW)
add_definitions("-DHB_EXTERN=__declspec(dllexport) extern")
add_definitions("-DHB_DLL_EXPORT")
endif ()
# On Windows, g-ir-scanner requires a DLL build in order for it to work
@ -680,6 +704,8 @@ 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=
@ -772,6 +798,11 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
)
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}
)
@ -811,63 +842,53 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
endif ()
endif ()
if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color")
endif ()
endif ()
if (HB_BUILD_TESTS)
## src/ executables
foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
set (prog_name ${prog})
if (${prog_name} STREQUAL "test")
# test can not be used as a valid executable name on cmake, lets special case it
set (prog_name test-test)
endif ()
add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
endforeach ()
set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
## Tests
if (UNIX OR MINGW)
if (BUILD_SHARED_LIBS)
# generate harfbuzz.def after build completion
add_custom_command(TARGET harfbuzz POST_BUILD
COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
## src/ executables
foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
set (prog_name ${prog})
if (${prog_name} STREQUAL "test")
# test can not be used as a valid executable name on cmake, lets special case it
set (prog_name test-test)
endif ()
add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
endforeach ()
set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
add_test(NAME check-static-inits.sh
COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
)
add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
## Tests
if (UNIX OR MINGW)
if (BUILD_SHARED_LIBS)
# generate harfbuzz.def after build completion
add_custom_command(TARGET harfbuzz POST_BUILD
COMMAND "${PYTHON_EXECUTABLE}" ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def ${project_headers}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
add_test(NAME check-static-inits.sh
COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
)
add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
set_tests_properties(
check-static-inits.sh check-libstdc++.sh check-symbols.sh
PROPERTIES
ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
SKIP_RETURN_CODE 77)
endif ()
add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
set_tests_properties(
check-static-inits.sh check-libstdc++.sh check-symbols.sh
check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
PROPERTIES
ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
SKIP_RETURN_CODE 77)
endif ()
add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
set_tests_properties(
check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
PROPERTIES
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
SKIP_RETURN_CODE 77)
# Needs to come last so that variables defined above are passed to
# subdirectories.
add_subdirectory(test)
endif ()
# Needs to come last so that variables defined above are passed to
# subdirectories.
add_subdirectory(test)

View File

@ -36,7 +36,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) | fmt --split-only > $@.tmp \
$(GIT) log $(CHANGELOG_RANGE) --stat) > $@.tmp \
&& mv -f $@.tmp "$(srcdir)/ChangeLog" \
|| ($(RM) $@.tmp; \
echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \

261
NEWS
View File

@ -1,3 +1,264 @@
Overview of changes leading to 2.4.0
Monday, March 25, 2019
====================================
- Unicode 12.
- Misc fixes.
- Subsetter improvements.
- New API:
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE
hb_directwrite_face_create()
Overview of changes leading to 2.3.1
Wednesday, January 30, 2019
====================================
- AAT bug fixes.
- Misc internal housekeeping cleanup.
Overview of changes leading to 2.3.0
Thursday, December 20, 2018
====================================
- Fix regression on big-endian architectures. Ouch!
- Misc bug and build fixes.
- Fix subsetting of simple GSUB/GDEF.
- Merge CFF / CFF2 support contributed by Adobe. This mostly involves
the subsetter, but also get_glyph_extents on CFF fonts.
New API in hb-aat.h:
+hb_aat_layout_has_substitution()
+hb_aat_layout_has_positioning()
+hb_aat_layout_has_tracking()
Overview of changes leading to 2.2.0
Thursday, November 29, 2018
====================================
- Misc shaping bug fixes.
- Add font variations named-instance API.
- Deprecate font variations axis enumeration API and add replacement.
- AAT shaping improvements:
o Fixed 'kern' table Format 2 implementation.
o Implement 'feat' table API for feature detection.
o Blacklist 'GSUB' table of fonts from 'MUTF' foundry that also have 'morx'.
New API:
+hb_aat_layout_feature_type_t
+hb_aat_layout_feature_selector_t
+hb_aat_layout_get_feature_types()
+hb_aat_layout_feature_type_get_name_id
+hb_aat_layout_feature_selector_info_t
+HB_AAT_LAYOUT_NO_SELECTOR_INDEX
+hb_aat_layout_feature_type_get_selector_infos()
+hb_ot_var_axis_flags_t
+hb_ot_var_axis_info_t
+hb_ot_var_get_axis_infos()
+hb_ot_var_find_axis_info()
+hb_ot_var_get_named_instance_count()
+hb_ot_var_named_instance_get_subfamily_name_id()
+hb_ot_var_named_instance_get_postscript_name_id()
+hb_ot_var_named_instance_get_design_coords()
Deprecated API:
+HB_OT_VAR_NO_AXIS_INDEX
+hb_ot_var_axis_t
+hb_ot_var_get_axes()
+hb_ot_var_find_axis()
Overview of changes leading to 2.1.3
Friday, November 16, 2018
====================================
- Fix AAT 'mort' shaping, which was broken in 2.1.2
Overview of changes leading to 2.1.2
Friday, November 16, 2018
====================================
- Various internal changes.
- AAT shaping improvements:
o Implement kern table Format 1 state-machine-based kerning.
o Implement cross-stream kerning (cursive positioning, etc).
o Ignore emptyish GSUB tables (zero scripts) if morx present.
o Don't apply GPOS if morx is being applied. Matches Apple.
-Overview of changes leading to 2.1.1
Monday, November 5, 2018
====================================
- AAT improvements:
o Implement 'mort' table.
o Implement 'kern' subtables Format 1 and Format 3.
Overview of changes leading to 2.1.0
Tuesday, October 30, 2018
====================================
- AAT shaping improvements:
o Allow user controlling AAT features, for whole buffer only currently.
o Several 'morx' fixes.
o Implement tuple-kerns in 'kerx'; Fixes kerning with Apple default
San Francisco fonts.
- Support for color fonts:
o COLR/CPAL API to fetch color layers.
o SVG table to fetch SVG documents.
o CBDT/sbix API to fetch PNG images.
- New 'name' table API.
- hb-ot-font now uses 'VORG' table to correctly position CFF glyphs
in vertical layout.
- Various fuzzer-found bug fixes.
Changed API:
A type and a macro added in 2.0.0 were renamed:
hb_name_id_t -> hb_ot_name_id_t
HB_NAME_ID_INVALID -> HB_OT_NAME_ID_INVALID
New API:
+hb_color_t
+HB_COLOR
+hb_color_get_alpha()
+hb_color_get_red()
+hb_color_get_green()
+hb_color_get_blue()
+hb_ot_color_has_palettes()
+hb_ot_color_palette_get_count()
+hb_ot_color_palette_get_name_id()
+hb_ot_color_palette_color_get_name_id()
+hb_ot_color_palette_flags_t
+hb_ot_color_palette_get_flags()
+hb_ot_color_palette_get_colors()
+hb_ot_color_has_layers()
+hb_ot_color_layer_t
+hb_ot_color_glyph_get_layers()
+hb_ot_color_has_svg()
+hb_ot_color_glyph_reference_svg()
+hb_ot_color_has_png()
+hb_ot_color_glyph_reference_png()
+hb_ot_name_id_t
+HB_OT_NAME_ID_INVALID
+HB_OT_NAME_ID_COPYRIGHT
+HB_OT_NAME_ID_FONT_FAMILY
+HB_OT_NAME_ID_FONT_SUBFAMILY
+HB_OT_NAME_ID_UNIQUE_ID
+HB_OT_NAME_ID_FULL_NAME
+HB_OT_NAME_ID_VERSION_STRING
+HB_OT_NAME_ID_POSTSCRIPT_NAME
+HB_OT_NAME_ID_TRADEMARK
+HB_OT_NAME_ID_MANUFACTURER
+HB_OT_NAME_ID_DESIGNER
+HB_OT_NAME_ID_DESCRIPTION
+HB_OT_NAME_ID_VENDOR_URL
+HB_OT_NAME_ID_DESIGNER_URL
+HB_OT_NAME_ID_LICENSE
+HB_OT_NAME_ID_LICENSE_URL
+HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY
+HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY
+HB_OT_NAME_ID_MAC_FULL_NAME
+HB_OT_NAME_ID_SAMPLE_TEXT
+HB_OT_NAME_ID_CID_FINDFONT_NAME
+HB_OT_NAME_ID_WWS_FAMILY
+HB_OT_NAME_ID_WWS_SUBFAMILY
+HB_OT_NAME_ID_LIGHT_BACKGROUND
+HB_OT_NAME_ID_DARK_BACKGROUND
+HB_OT_NAME_ID_VARIATIONS_PS_PREFIX
+hb_ot_name_entry_t
+hb_ot_name_list_names()
+hb_ot_name_get_utf8()
+hb_ot_name_get_utf16()
+hb_ot_name_get_utf32()
Overview of changes leading to 2.0.2
Saturday, October 20, 2018
====================================
- Fix two minor memory access issues in AAT tables.
Overview of changes leading to 2.0.1
Friday, October 19, 2018
====================================
- Fix hb-version.h reported release version that went wrong (1.8.0)
with previous release.
- Fix extrapolation in 'trak' table.
- Fix hb-font infinite-recursion issue with some font funcs and
subclassed fonts.
- Implement variation-kerning format in kerx table, although without
variation.
- Fix return value of hb_map_is_empty().
Overview of changes leading to 2.0.0
Thursday, October 18, 2018
====================================
- Added AAT shaping support (morx/kerx/trak).
Automatically used if GSUB/GPOS are not available respectively.
Set HB_OPTIONS=aat env var to have morx/kerx preferred over
GSUB/GPOS.
- Apply TrueType kern table internally, instead of relying on
hb_font_t callbacks.
- Khmer shaper significantly rewritten to better match Uniscribe.
- Indic3 tags ('dev3', etc) are passed to USE shaper.
- .dfont Mac font containers implemented.
- Script- and language-mapping revamped to better use BCP 47.
- Misc USE and Indic fixes.
- Misc everything fixes.
- Too many things to list. Biggest release since 0.9.1, with
over 500 commits in just over 5 weeks! Didn't intend it to
be a big release. Just happened to become.
- hb-ft now locks underlying FT_Face during use.
API changes:
- Newly-created hb_font_t's now have our internal "hb-ot-font"
callbacks set on them, so they should work out of the box
without any callbacks set. If callbacks are set, everything
is back to what it was before, the fallback callbacks are
null. If you to get the internal implementation modified,
sub_font it.
- New hb_font_funcs_set_nominal_glyphs_func() allows speeding
up character to glyph mapping.
New API:
+HB_FEATURE_GLOBAL_START
+HB_FEATURE_GLOBAL_END
+hb_buffer_set_invisible_glyph()
+hb_buffer_get_invisible_glyph()
+hb_font_funcs_set_nominal_glyphs_func()
+hb_ot_layout_table_select_script()
+hb_ot_layout_script_select_language()
+hb_ot_layout_feature_get_name_ids()
+hb_ot_layout_feature_get_characters()
+hb_name_id_t
+HB_NAME_ID_INVALID
+HB_OT_MAX_TAGS_PER_SCRIPT
+hb_ot_tags_from_script_and_language()
+hb_ot_tags_to_script_and_language()
Deprecated API:
-hb_font_funcs_set_glyph_func()
-hb_unicode_eastasian_width_func_t
-hb_unicode_funcs_set_eastasian_width_func()
-hb_unicode_eastasian_width()
-hb_unicode_decompose_compatibility_func_t
-HB_UNICODE_MAX_DECOMPOSITION_LEN
-hb_unicode_funcs_set_decompose_compatibility_func()
-hb_unicode_decompose_compatibility()
-hb_font_funcs_set_glyph_h_kerning_func()
-hb_font_funcs_set_glyph_v_kerning_func()
-hb_font_get_glyph_h_kerning()
-hb_font_get_glyph_v_kerning()
-hb_font_get_glyph_kerning_for_direction()
-hb_ot_layout_table_choose_script()
-hb_ot_layout_script_find_language()
-hb_ot_tags_from_script()
-hb_ot_tag_from_language()
Overview of changes leading to 1.9.0
Monday, September 10, 2018
====================================

17
README
View File

@ -1,17 +0,0 @@
[![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)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/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

1
README Symbolic link
View File

@ -0,0 +1 @@
README.md

View File

@ -1 +0,0 @@
README

18
README.md Normal file
View File

@ -0,0 +1,18 @@
[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg?branch=master)](https://travis-ci.org/harfbuzz/harfbuzz)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true&branch=master)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
[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

View File

@ -23,7 +23,7 @@ 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:
import works in your Python interpreter:
```python
from gi.repository import HarfBuzz

View File

@ -1,6 +1,6 @@
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
implemenetation and that specially is important where OpenType specification
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:
@ -27,8 +27,8 @@ steps are recommended:
Now you can use hb-shape using `wine winbuild/util/hb-shape.exe` but if you like to
to use the original Uniscribe,
8. Bring a 32bit version of `usp10.dll` for youself from `C:\Windows\SysWOW64\usp10.dll` of your
Windows installation (asuming you have a 64-bit installation, otherwise `C:\Windows\System32\usp10.dll`)
8. 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.

View File

@ -8,7 +8,8 @@ HarfBuzz release walk-through checklist:
Document them in NEWS. All API and API semantic changes should be clearly
marked as API additions, API changes, or API deletions. Document
deprecations. Ensure all new API / deprecations are in listed correctly in
docs/harfbuzz-sections.txt
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.
@ -27,15 +28,19 @@ HarfBuzz release walk-through checklist:
Otherwise, fix things and commit them separately before making release,
Note: Check src/hb-version.h and make sure the new version number is
there. Sometimes, it does not get updated. If that's the case,
"touch configure.ac" and rebuild. TODO: debug.
"touch configure.ac" and rebuild. Also check that there is no hb-version.h
in your build/src file. Typically it will fail the distcheck if there is.
That's what happened to 2.0.0 going out with 1.8.0 hb-version.h... So, that's
a clue.
7. "make release-files". Enter your GPG password. This creates a sha256 hash
and signs it.
8. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
7. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
as well as any REPLACEME changes you made. The commit message is simply the
release number. Eg. "1.4.7"
8. "make dist" again to get a tarball with your new commit in the ChangeLog. Then
"make release-files". Enter your GPG password. This creates a sha256 hash
and signs it. Check the size of the three resulting files.
9. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your
GPG password again.

12
TODO
View File

@ -1,9 +1,3 @@
General fixes:
=============
- Implement 'rand' feature.
API issues:
===========
@ -19,11 +13,7 @@ API additions
- 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 sanitize API.
- Add query / enumeration API for aalt-like features?

View File

@ -28,15 +28,19 @@ environment:
MINGW_CHOST: i686-w64-mingw32
MSYS2_ARCH: i686
install:
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman -Syu --noconfirm"'
# - 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -Sy && pacman --noconfirm --force -S pacman-mirrors && pacman --force -Syu --noconfirm"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
- set PATH=%PATH%;C:\msys64\mingw64\bin # msys2 is added just for having "ragel" on PATH
- 'if "%compiler%"=="cygwin" %CYGWIN_PREFIX%\setup-%CYGWIN_ARCH%.exe -g -q -P cygwin-devel,libfreetype-devel,libcairo-devel,libicu-devel,gcc,gcc-g++,gobject-introspection,libglib2.0-devel,libgraphite2-devel,pkg-config,python2'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
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" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin'
- '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 ../'
@ -44,13 +48,12 @@ build_script:
- '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 -Syyu mingw-w64-$MSYS2_ARCH-gcc"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S --needed 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 "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make; make check || .ci/fail.sh"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
cache:
- c:\tools\vcpkg\installed\
- '%CYGWIN_PREFIX%\var\cache\setup'
notifications:
- provider: Email
@ -60,5 +63,8 @@ notifications:
on_build_failure: true
on_build_status_changed: true
# Do not build feature branch with open Pull Requests
skip_branch_with_pr: true
# disable automatic tests
test: off

21
azure-pipelines.yml Normal file
View File

@ -0,0 +1,21 @@
pool:
vmImage: 'VS2017-Win2016'
variables:
buildPlatform: 'x86'
buildConfiguration: 'Debug'
triplet: 'x86-windows'
steps:
- script: |
git clone https://github.com/Microsoft/vcpkg
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg integrate install
.\vcpkg install glib:x86-windows freetype:x86-windows cairo:x86-windows
cd ..
cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake ../
msbuild harfbuzz.sln /p:Configuration=Debug /p:Platform=Win32
cd build
ctest --output-on-failure -C Debug
displayName: Build and test

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[1.9.0],
[2.4.0],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@ -19,12 +19,11 @@ 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
dnl AX_CXX_COMPILE_STDCXX(11, noext, optional)
AX_CXX_COMPILE_STDCXX(11,, optional)
AC_SYS_LARGEFILE
PKG_PROG_PKG_CONFIG([0.20])
AM_MISSING_PROG([RAGEL], [ragel])
@ -103,9 +102,6 @@ if test "x$GCC" = "xyes"; then
# by overriding CXXFLAGS.
CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics"
# Assorted warnings
CXXFLAGS="$CXXFLAGS -Wcast-align"
case "$host" in
*-*-mingw*)
;;
@ -148,12 +144,6 @@ 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])
@ -330,7 +320,7 @@ AC_ARG_WITH(graphite2,
[Use the graphite2 library @<:@default=no@:>@])],,
[with_graphite2=no])
have_graphite2=false
GRAPHITE2_DEPS="graphite2"
GRAPHITE2_DEPS="graphite2 >= 1.2.0"
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, :)
@ -514,6 +504,7 @@ test/api/Makefile
test/fuzzing/Makefile
test/shaping/Makefile
test/shaping/data/Makefile
test/shaping/data/aots/Makefile
test/shaping/data/in-house/Makefile
test/shaping/data/text-rendering-tests/Makefile
test/subset/Makefile
@ -524,6 +515,11 @@ docs/version.xml
AC_OUTPUT
echo
echo "C++ compiler version:"
$CXX --version
echo
AC_MSG_NOTICE([
Build configuration:

View File

@ -62,7 +62,6 @@ 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
@ -73,14 +72,15 @@ 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-buffers-language-script-and-direction.xml \
usermanual-clusters.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 \
usermanual-install-harfbuzz.xml \
usermanual-getting-started.xml \
usermanual-shaping-concepts.xml \
usermanual-buffers-language-script-and-direction.xml \
usermanual-fonts-and-faces.xml \
usermanual-clusters.xml \
usermanual-opentype-features.xml \
usermanual-glyph-information.xml \
version.xml
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded

View File

@ -12,28 +12,21 @@
<graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
<para>
HarfBuzz is an <ulink url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>
text shaping engine.
text shaping engine. Using the HarfBuzz library allows
programs to convert a sequence of Unicode input into
properly formatted and positioned glyph output&mdash;for any writing
system and language.
</para>
<para>
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.
The canonical source-code tree is available at
<ulink
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>
and is also available at
<ulink
url="http://cgit.freedesktop.org/harfbuzz/">cgit.freedesktop.org/harfbuzz</ulink>.
See <xref linkend="download" endterm="download.title"/> for
release tarballs.
</para>
</abstract>
</bookinfo>
@ -42,7 +35,8 @@
<title>User's manual</title>
<xi:include href="usermanual-what-is-harfbuzz.xml"/>
<xi:include href="usermanual-install-harfbuzz.xml"/>
<xi:include href="usermanual-hello-harfbuzz.xml"/>
<xi:include href="usermanual-getting-started.xml"/>
<xi:include href="usermanual-shaping-concepts.xml"/>
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
<xi:include href="usermanual-fonts-and-faces.xml"/>
<xi:include href="usermanual-clusters.xml"/>
@ -58,152 +52,124 @@
<ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
</releaseinfo>
</partinfo>
<note>
<para>
The current HarfBuzz codebase is versioned 2.x.x and is stable
and under active maintenance. This is what is used in latest
versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice,
XeTeX, Android, and KDE, among other places.
</para>
<para>
Prior to 2012, the original HarfBuzz codebase (which, these
days, is referred to as <emphasis>harfbuzz-old</emphasis>) was
derived from code in <ulink
url="http://freetype.org/">FreeType</ulink>, <ulink
url="http://pango.org/">Pango</ulink>, and
<ulink url="http://qt-project.org/">Qt</ulink>.
It is <emphasis>not</emphasis> actively developed or
maintained, and is extremely buggy. All users of harfbuzz-old
are encouraged to switch over to the new HarfBuzz as soon as possible.
</para>
<para>
To make this distinction clearer in discussions, the current
HarfBuzz codebase is sometimes referred to as
<emphasis>harfbuzz-ng</emphasis>.
</para>
<para>
For reference purposes, the harfbuzz-old source tree is archived
<ulink
url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>. There
are no release tarballs of harfbuzz-old whatsoever.
</para>
</note>
<title>Reference manual</title>
<chapter>
<title>HarfBuzz API</title>
<xi:include href="xml/hb.xml"/>
<xi:include href="xml/hb-common.xml"/>
<xi:include href="xml/hb-unicode.xml"/>
<xi:include href="xml/hb-buffer.xml"/>
<title>Core API</title>
<xi:include href="xml/hb-blob.xml"/>
<xi:include href="xml/hb-buffer.xml"/>
<xi:include href="xml/hb-common.xml"/>
<xi:include href="xml/hb-deprecated.xml"/>
<xi:include href="xml/hb-face.xml"/>
<xi:include href="xml/hb-font.xml"/>
<xi:include href="xml/hb-shape.xml"/>
<xi:include href="xml/hb-version.xml"/>
<xi:include href="xml/hb-deprecated.xml"/>
<xi:include href="xml/hb-map.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-tag.xml"/>
<xi:include href="xml/hb-ot-font.xml"/>
<xi:include href="xml/hb-ot-shape.xml"/>
<xi:include href="xml/hb-ot-math.xml"/>
<xi:include href="xml/hb-shape-plan.xml"/>
<xi:include href="xml/hb-glib.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-coretext.xml"/>
<xi:include href="xml/hb-gobject.xml"/>
<xi:include href="xml/hb-shape.xml"/>
<xi:include href="xml/hb-unicode.xml"/>
<xi:include href="xml/hb-version.xml"/>
</chapter>
<chapter id="object-tree">
<chapter>
<title>OpenType API</title>
<xi:include href="xml/hb-ot-color.xml"/>
<xi:include href="xml/hb-ot-font.xml"/>
<xi:include href="xml/hb-ot-layout.xml"/>
<xi:include href="xml/hb-ot-math.xml"/>
<xi:include href="xml/hb-ot-name.xml"/>
<xi:include href="xml/hb-ot-shape.xml"/>
<xi:include href="xml/hb-ot-var.xml"/>
</chapter>
<chapter>
<title>Apple Advanced Typography API</title>
<xi:include href="xml/hb-aat-layout.xml"/>
</chapter>
<chapter>
<title>Integration API</title>
<xi:include href="xml/hb-coretext.xml"/>
<xi:include href="xml/hb-ft.xml"/>
<xi:include href="xml/hb-glib.xml"/>
<xi:include href="xml/hb-gobject.xml"/>
<xi:include href="xml/hb-graphite2.xml"/>
<xi:include href="xml/hb-icu.xml"/>
<xi:include href="xml/hb-uniscribe.xml"/>
</chapter>
<!--chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
</index>
<index id="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>
</chapter-->
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-2-0" role="2.2.0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-6" role="1.8.6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-5" role="1.8.5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-1" role="1.8.1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-8-0" role="1.8.0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-7" role="1.7.7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-7-5" role="1.7.5"><title>Index of new symbols in 1.7.5</title><xi:include href="xml/api-index-1.7.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-6-0" role="1.6.0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-2" role="1.1.2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-0-5" role="1.0.5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-42" role="0.9.42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-41" role="0.9.41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-39" role="0.9.39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-38" role="0.9.38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-31" role="0.9.31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-30" role="0.9.30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-28" role="0.9.28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-22" role="0.9.22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-20" role="0.9.20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-11" role="0.9.11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-10" role="0.9.10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-8" role="0.9.8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-7" role="0.9.7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-5" role="0.9.5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
<index id="api-index-0-9-2" role="0.9.2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</part>

View File

@ -1,8 +1,20 @@
<SECTION>
<FILE>hb</FILE>
<SUBSECTION Private>
HB_H_IN
HB_EXTERN
HB_OT_H_IN
</SECTION>
<SECTION>
<FILE>hb-aat-layout</FILE>
HB_AAT_LAYOUT_NO_SELECTOR_INDEX
hb_aat_layout_feature_type_t
hb_aat_layout_feature_selector_t
hb_aat_layout_feature_selector_info_t
hb_aat_layout_feature_type_get_name_id
hb_aat_layout_feature_type_get_selector_infos
hb_aat_layout_get_feature_types
hb_aat_layout_has_positioning
hb_aat_layout_has_substitution
hb_aat_layout_has_tracking
</SECTION>
<SECTION>
@ -67,6 +79,8 @@ hb_buffer_set_user_data
hb_buffer_get_user_data
hb_buffer_get_glyph_infos
hb_buffer_get_glyph_positions
hb_buffer_get_invisible_glyph
hb_buffer_set_invisible_glyph
hb_buffer_set_replacement_codepoint
hb_buffer_get_replacement_codepoint
hb_buffer_normalize_glyphs
@ -110,11 +124,17 @@ hb_script_get_horizontal_direction
hb_language_from_string
hb_language_to_string
hb_language_get_default
hb_feature_from_string
hb_feature_to_string
hb_variation_from_string
hb_variation_to_string
hb_bool_t
hb_codepoint_t
hb_destroy_func_t
hb_direction_t
hb_language_t
hb_feature_t
hb_variation_t
hb_mask_t
hb_position_t
hb_tag_t
@ -133,6 +153,8 @@ HB_DIRECTION_IS_HORIZONTAL
HB_DIRECTION_IS_VALID
HB_DIRECTION_IS_VERTICAL
HB_LANGUAGE_INVALID
HB_FEATURE_GLOBAL_END
HB_FEATURE_GLOBAL_START
<SUBSECTION Private>
HB_BEGIN_DECLS
HB_END_DECLS
@ -144,6 +166,10 @@ uint16_t
uint32_t
uint64_t
uint8_t
<SUBSECTION Private>
HB_EXTERN
HB_DEPRECATED
HB_DEPRECATED_FOR
</SECTION>
<SECTION>
@ -153,7 +179,30 @@ HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
HB_SCRIPT_CANADIAN_ABORIGINAL
hb_font_funcs_set_glyph_func
hb_font_get_glyph_func_t
hb_ot_layout_table_choose_script
hb_ot_layout_table_find_script
hb_ot_tag_from_language
hb_ot_tags_from_script
HB_OT_VAR_NO_AXIS_INDEX
hb_ot_var_axis_t
hb_ot_var_find_axis
hb_ot_var_get_axes
hb_set_invert
hb_unicode_eastasian_width_func_t
hb_unicode_eastasian_width
hb_unicode_funcs_set_eastasian_width_func
HB_UNICODE_MAX_DECOMPOSITION_LEN
hb_unicode_decompose_compatibility_func_t
hb_unicode_decompose_compatibility
hb_unicode_funcs_set_decompose_compatibility_func
hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_v_kerning_func
hb_font_get_glyph_h_kerning
hb_font_get_glyph_h_kerning_func_t
hb_font_get_glyph_kerning_for_direction
hb_font_get_glyph_kerning_func_t
hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
</SECTION>
<SECTION>
@ -167,6 +216,14 @@ hb_coretext_face_get_cg_font
hb_coretext_font_get_ct_font
</SECTION>
<SECTION>
<FILE>hb-directwrite</FILE>
hb_directwrite_face_create
hb_directwrite_face_get_font_face
<SUBSECTION Private>
hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>
<FILE>hb-face</FILE>
hb_face_count
@ -214,14 +271,13 @@ hb_font_funcs_set_glyph_extents_func
hb_font_funcs_set_glyph_from_name_func
hb_font_funcs_set_glyph_h_advance_func
hb_font_funcs_set_glyph_h_advances_func
hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_h_origin_func
hb_font_funcs_set_glyph_name_func
hb_font_funcs_set_glyph_v_advance_func
hb_font_funcs_set_glyph_v_advances_func
hb_font_funcs_set_glyph_v_kerning_func
hb_font_funcs_set_glyph_v_origin_func
hb_font_funcs_set_nominal_glyph_func
hb_font_funcs_set_nominal_glyphs_func
hb_font_funcs_set_user_data
hb_font_funcs_set_variation_glyph_func
hb_font_funcs_t
@ -244,12 +300,8 @@ hb_font_get_glyph_h_advance
hb_font_get_glyph_h_advance_func_t
hb_font_get_glyph_h_advances
hb_font_get_glyph_h_advances_func_t
hb_font_get_glyph_h_kerning
hb_font_get_glyph_h_kerning_func_t
hb_font_get_glyph_h_origin
hb_font_get_glyph_h_origin_func_t
hb_font_get_glyph_kerning_for_direction
hb_font_get_glyph_kerning_func_t
hb_font_get_glyph_name
hb_font_get_glyph_name_func_t
hb_font_get_glyph_origin_for_direction
@ -258,12 +310,12 @@ hb_font_get_glyph_v_advance
hb_font_get_glyph_v_advance_func_t
hb_font_get_glyph_v_advances
hb_font_get_glyph_v_advances_func_t
hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
hb_font_get_glyph_v_origin
hb_font_get_glyph_v_origin_func_t
hb_font_get_nominal_glyph
hb_font_get_nominal_glyph_func_t
hb_font_get_nominal_glyphs
hb_font_get_nominal_glyphs_func_t
hb_font_get_parent
hb_font_get_ppem
hb_font_get_ptem
@ -285,9 +337,6 @@ hb_font_set_ppem
hb_font_set_ptem
hb_font_set_scale
hb_font_set_user_data
hb_variation_t
hb_variation_from_string
hb_variation_to_string
hb_font_set_variations
hb_font_set_var_coords_design
hb_font_set_var_coords_normalized
@ -342,6 +391,7 @@ HB_GOBJECT_TYPE_FONT_FUNCS
HB_GOBJECT_TYPE_GLYPH_FLAGS
HB_GOBJECT_TYPE_MAP
HB_GOBJECT_TYPE_MEMORY_MODE
HB_GOBJECT_TYPE_OT_COLOR_PALETTE_FLAGS
HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
HB_GOBJECT_TYPE_OT_MATH_CONSTANT
HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART
@ -374,6 +424,7 @@ hb_gobject_font_get_type
hb_gobject_glyph_flags_get_type
hb_gobject_map_get_type
hb_gobject_memory_mode_get_type
hb_gobject_ot_color_palette_flags_get_type
hb_gobject_ot_layout_glyph_class_get_type
hb_gobject_ot_math_constant_get_type
hb_gobject_ot_math_glyph_part_get_type
@ -396,11 +447,6 @@ hb_gobject_user_data_key_get_type
HB_GOBJECT_H_IN
</SECTION>
<SECTION>
<FILE>hb-gobject</FILE>
</SECTION>
<SECTION>
<FILE>hb-graphite2</FILE>
HB_GRAPHITE2_TAG_SILF
@ -436,9 +482,27 @@ hb_map_t
</SECTION>
<SECTION>
<FILE>hb-ot</FILE>
<SUBSECTION Private>
HB_OT_H_IN
<FILE>hb-ot-color</FILE>
hb_color_t
HB_COLOR
hb_color_get_alpha
hb_color_get_blue
hb_color_get_green
hb_color_get_red
hb_ot_color_glyph_get_layers
hb_ot_color_glyph_reference_png
hb_ot_color_glyph_reference_svg
hb_ot_color_has_layers
hb_ot_color_has_palettes
hb_ot_color_has_png
hb_ot_color_has_svg
hb_ot_color_layer_t
hb_ot_color_palette_color_get_name_id
hb_ot_color_palette_flags_t
hb_ot_color_palette_get_colors
hb_ot_color_palette_get_count
hb_ot_color_palette_get_flags
hb_ot_color_palette_get_name_id
</SECTION>
<SECTION>
@ -447,23 +511,40 @@ hb_ot_font_set_funcs
</SECTION>
<SECTION>
<FILE>hb-ot-shape</FILE>
hb_ot_shape_glyphs_closure
<FILE>hb-ot-name</FILE>
hb_ot_name_id_t
HB_OT_NAME_ID_INVALID
hb_ot_name_entry_t
hb_ot_name_list_names
hb_ot_name_get_utf16
hb_ot_name_get_utf32
hb_ot_name_get_utf8
</SECTION>
<SECTION>
<FILE>hb-ot-layout</FILE>
HB_OT_MAX_TAGS_PER_LANGUAGE
HB_OT_MAX_TAGS_PER_SCRIPT
HB_OT_TAG_DEFAULT_LANGUAGE
HB_OT_TAG_DEFAULT_SCRIPT
hb_ot_tag_to_language
hb_ot_tag_to_script
hb_ot_tags_from_script_and_language
hb_ot_tags_to_script_and_language
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
HB_OT_LAYOUT_NO_FEATURE_INDEX
HB_OT_LAYOUT_NO_SCRIPT_INDEX
HB_OT_LAYOUT_NO_VARIATIONS_INDEX
HB_OT_TAG_BASE
HB_OT_TAG_GDEF
HB_OT_TAG_GPOS
HB_OT_TAG_GSUB
HB_OT_TAG_JSTF
hb_ot_layout_collect_lookups
hb_ot_layout_collect_features
hb_ot_layout_feature_get_characters
hb_ot_layout_feature_get_lookups
hb_ot_layout_feature_get_name_ids
hb_ot_layout_feature_with_variations_get_lookups
hb_ot_layout_get_attach_points
hb_ot_layout_get_glyph_class
@ -485,12 +566,12 @@ hb_ot_layout_lookups_substitute_closure
hb_ot_layout_lookup_would_substitute
hb_ot_layout_script_find_language
hb_ot_layout_script_get_language_tags
hb_ot_layout_table_choose_script
hb_ot_layout_script_select_language
hb_ot_layout_table_find_feature_variations
hb_ot_layout_table_find_script
hb_ot_layout_table_get_feature_tags
hb_ot_layout_table_get_script_tags
hb_ot_layout_table_get_lookup_count
hb_ot_layout_table_select_script
hb_ot_shape_plan_collect_lookups
hb_ot_layout_language_get_required_feature_index
<SUBSECTION Private>
@ -499,23 +580,6 @@ Xhb_ot_layout_lookup_position
Xhb_ot_layout_lookup_substitute
</SECTION>
<SECTION>
<FILE>hb-ot-var</FILE>
HB_OT_TAG_VAR_AXIS_ITALIC
HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
HB_OT_TAG_VAR_AXIS_SLANT
HB_OT_TAG_VAR_AXIS_WEIGHT
HB_OT_TAG_VAR_AXIS_WIDTH
HB_OT_VAR_NO_AXIS_INDEX
hb_ot_var_axis_t
hb_ot_var_has_data
hb_ot_var_find_axis
hb_ot_var_get_axis_count
hb_ot_var_get_axes
hb_ot_var_normalize_variations
hb_ot_var_normalize_coords
</SECTION>
<SECTION>
<FILE>hb-ot-math</FILE>
HB_OT_TAG_MATH
@ -537,13 +601,29 @@ hb_ot_math_get_glyph_assembly
</SECTION>
<SECTION>
<FILE>hb-ot-tag</FILE>
HB_OT_TAG_DEFAULT_LANGUAGE
HB_OT_TAG_DEFAULT_SCRIPT
hb_ot_tag_from_language
hb_ot_tag_to_language
hb_ot_tag_to_script
hb_ot_tags_from_script
<FILE>hb-ot-shape</FILE>
hb_ot_shape_glyphs_closure
</SECTION>
<SECTION>
<FILE>hb-ot-var</FILE>
HB_OT_TAG_VAR_AXIS_ITALIC
HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
HB_OT_TAG_VAR_AXIS_SLANT
HB_OT_TAG_VAR_AXIS_WEIGHT
HB_OT_TAG_VAR_AXIS_WIDTH
hb_ot_var_has_data
hb_ot_var_axis_flags_t
hb_ot_var_axis_info_t
hb_ot_var_find_axis_info
hb_ot_var_get_axis_count
hb_ot_var_get_axis_infos
hb_ot_var_get_named_instance_count
hb_ot_var_named_instance_get_subfamily_name_id
hb_ot_var_named_instance_get_postscript_name_id
hb_ot_var_named_instance_get_design_coords
hb_ot_var_normalize_variations
hb_ot_var_normalize_coords
</SECTION>
<SECTION>
@ -582,11 +662,6 @@ hb_set_union
<SECTION>
<FILE>hb-shape</FILE>
HB_FEATURE_GLOBAL_END
HB_FEATURE_GLOBAL_START
hb_feature_t
hb_feature_from_string
hb_feature_to_string
hb_shape
hb_shape_full
hb_shape_list_shapers
@ -611,16 +686,13 @@ hb_shape_plan_t
<SECTION>
<FILE>hb-unicode</FILE>
HB_UNICODE_MAX
HB_UNICODE_MAX_DECOMPOSITION_LEN
hb_unicode_combining_class
hb_unicode_combining_class_func_t
hb_unicode_combining_class_t
hb_unicode_compose
hb_unicode_compose_func_t
hb_unicode_decompose
hb_unicode_decompose_compatibility
hb_unicode_decompose_func_t
hb_unicode_eastasian_width
hb_unicode_funcs_create
hb_unicode_funcs_destroy
hb_unicode_funcs_get_default
@ -632,9 +704,7 @@ hb_unicode_funcs_make_immutable
hb_unicode_funcs_reference
hb_unicode_funcs_set_combining_class_func
hb_unicode_funcs_set_compose_func
hb_unicode_funcs_set_decompose_compatibility_func
hb_unicode_funcs_set_decompose_func
hb_unicode_funcs_set_eastasian_width_func
hb_unicode_funcs_set_general_category_func
hb_unicode_funcs_set_mirroring_func
hb_unicode_funcs_set_script_func
@ -653,8 +723,6 @@ hb_unicode_script_func_t
<FILE>hb-uniscribe</FILE>
hb_uniscribe_font_get_hfont
hb_uniscribe_font_get_logfontw
<SUBSECTION Private>
hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>

View File

@ -1,3 +1,9 @@
<?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>
@ -9,14 +15,15 @@
<section id="creating-and-destroying-buffers">
<title>Creating and destroying buffers</title>
<para>
As we saw in our initial example, a buffer is created and
As we saw in our <emphasis>Getting Started</emphasis> 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 that it creates (such as
buffers), so you don't have to. When you have finished working on
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 <literal>hb_buffer_destroy()</literal>:
</para>
<programlisting language="C">
@ -74,4 +81,4 @@ void somefunc(hb_buffer_t *buffer) {
<para>
</para>
</section>
</chapter>
</chapter>

View File

@ -1,304 +1,695 @@
<?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>
<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 &quot;merge&quot;.
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>
<section id="clusters-and-shaping">
<title>Clusters and shaping</title>
<para>
Imagine capital letters are bases and lower case letters are
combining marks. With an input sequence like this:
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 &mdash; such as a ligature or conjunct form
&mdash; 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 &mdash;
even though the two original, underlying letters remain separate
graphemes.
</para>
<para>
HarfBuzz is concerned with clusters, <emphasis>not</emphasis>
with graphemes &mdash; 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 &mdash;
such as reordering, composition, decomposition, and substitution
&mdash; 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:
</para>
<programlisting>
A,a,B,b,C,c
0,1,2,3,4,5
</programlisting>
0,1,2,3,4
</programlisting>
<para>
if <literal>A,B,C</literal> ligate, then here are the cluster
values one would get under the various levels:
</para>
<para>
level 0:
and the final sequence of cluster values is:
</para>
<programlisting>
ABC,a,b,c
0 ,0,0,0
</programlisting>
0,0,3,3
</programlisting>
<para>
level 1:
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 left-to-right scripts (LTR) and top-to-bottom scripts (TTB),
HarfBuzz will preserve the monotonic property: client programs
are guaranteed that monotonically increasing initial clulster
values will be returned as monotonically increasing final
cluster values.
</para>
<para>
For right-to-left scripts (RTL) and bottom-to-top scripts (BTT),
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 clulster 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 and
reproduces the behavior of the old HarfBuzz library.
</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>
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>
Level 1 differs from level 0 by not merging the
clusters of marks and other modifier code points with the
preceding "base" code point's cluster. By preserving the
separate cluster values of these marks and modifier code
points, script shapers can perform additional operations
that might lead to improved results (for example, reordering
a sequence of marks).
</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):
</para>
<programlisting>
ABC,a,b,c
0 ,0,0,5
</programlisting>
A,B,C,D,E
0,1,2,3,4
</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
&quot;merge&quot;. 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 the more complex 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 &mdash; 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>
<programlisting>
ABC,a,b,c
0 ,1,3,5
</programlisting>
<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>
<para>
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.
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.
</para>
<para>
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.
This occurrence sounds similar to a cluster merge, but it is
different. In particular, no subsequent characters &mdash;
including marks and modifiers &mdash; are affected. They retain
their previous cluster values.
</para>
</sect2>
</sect1>
<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>
</chapter>

View File

@ -1,3 +1,9 @@
<?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 and faces</title>
<section id="using-freetype">
@ -15,4 +21,4 @@
<para>
</para>
</section>
</chapter>
</chapter>

View File

@ -0,0 +1,307 @@
<?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>
<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 provide 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>
<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
non-complex scripts.
</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>
<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 &lt;hb.h&gt;
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, using FreeType for now.
</para>
</listitem>
</orderedlist>
<programlisting language="C">
#include &lt;hb-ft.h&gt;
FT_New_Face(ft_library, font_path, index, &amp;face);
FT_Set_Char_Size(face, 0, 1000, 0, 0);
hb_font_t *font = hb_ft_font_create(face);
</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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
<orderedlist numeration="arabic">
<listitem override="6">
<para>
Iterate over each glyph.
</para>
</listitem>
</orderedlist>
<programlisting language="C">
for (i = 0; i &lt; glyph_count; ++i) {
glyphid = glyph_info[i].codepoint;
x_offset = glyph_pos[i].x_offset / 64.0;
y_offset = glyph_pos[i].y_offset / 64.0;
x_advance = glyph_pos[i].x_advance / 64.0;
y_advance = glyph_pos[i].y_advance / 64.0;
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
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>
<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>

View File

@ -1,3 +1,9 @@
<?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">
@ -5,4 +11,4 @@
<para>
</para>
</sect2>
</sect1>
</sect1>

View File

@ -1,183 +0,0 @@
<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 &lt;hb.h&gt;
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 &lt;hb-ft.h&gt;
FT_New_Face(ft_library, font_path, index, &amp;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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
<orderedlist numeration="arabic">
<listitem override="6">
<para>
Iterate over each glyph.
</para>
</listitem>
</orderedlist>
<programlisting language="C">
for (i = 0; i &lt; glyph_count; ++i) {
glyphid = glyph_info[i].codepoint;
x_offset = glyph_pos[i].x_offset / 64.0;
y_offset = glyph_pos[i].y_offset / 64.0;
x_advance = glyph_pos[i].x_advance / 64.0;
y_advance = glyph_pos[i].y_advance / 64.0;
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
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>
(&quot;bidi&quot; 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 &quot;a
<emphasis>huge</emphasis> breakfast&quot;, and you expect
&quot;huge&quot; 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>

View File

@ -1,70 +1,442 @@
<?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>Install HarfBuzz</title>
<title>Installing HarfBuzz</title>
<section id="download">
<title id="download.title">Download</title>
<title id="download.title">Downloading HarfBuzz</title>
<para>
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.
The HarfBuzz source code is hosted at <ulink
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>. The
same source tree is also available at the
<ulink
url="http://cgit.freedesktop.org/harfbuzz/">Freedesktop.org</ulink>
site.
</para>
<para>
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>.
Tarball releases and Win32 binary bundles (which include the
libharfbuzz DLL, hb-view.exe, hb-shape.exe, and all
dependencies) of HarfBuzz can be downloaded from <ulink
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz/releases</ulink>
or from
<ulink url="http://www.freedesktop.org/software/harfbuzz/release/">Freedesktop.org</ulink>.
</para>
<para>
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.
Release notes are posted with each new release to provide an
overview of the changes. The project <ulink url="https://github.com/harfbuzz/harfbuzz/issues">tracks bug
reports and other issues</ulink> on GitHub. Discussion and
questions are welcome on the <ulink
url="http://freedesktop.org/mailman/listinfo/harfbuzz/">HarfBuzz
mailing list</ulink>.
</para>
<para>
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>.
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.
</para>
</section>
<section id="building">
<title>Building</title>
<title>Building HarfBuzz</title>
<section id="building.linux">
<title>Building on Linux</title>
<para>
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>
<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.
</para>
<para>
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>.
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&ndash;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.
</para>
<para>
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>
<emphasis>(2)(a)</emphasis> If you downloaded the HarfBuzz
source code in a tarball, you can now extract the source.
</para>
<para>
From a shell in the top-level directory of the extracted source
code, you can run <command>./configure</command> followed by
<command>make</command> as with any other standard package.
</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> and
<ulink url="http://www.complang.org/ragel/">ragel</ulink>.
</para>
<para>
On Ubuntu or Debian, run:
<programlisting>
<command>sudo apt-get install</command> <package>autoconf automake libtool pkg-config ragel gtk-doc-tools</package>
</programlisting>
On Fedora, RHEL, CentOS, run:
<programlisting>
<command>sudo yum install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
</programlisting>
</para>
<para>
With <package>pkg-config</package> and <package>ragel</package>
installed, you can now run <command>./autogen.sh</command>,
followed by <command>./configure</command> and
<command>make</command> to build HarfBuzz.
</para>
</section>
<section id="building.windows">
<title>Building on Windows</title>
<para>
On Windows, consider using Microsoft's free <ulink
url="https://github.com/Microsoft/vcpkg">vcpkg</ulink> utility
to build HarfBuzz, its dependencies, and other open-source
libraries.
</para>
<para>
If you need to build HarfBuzz from source, first put the
<package>ragel</package> binary on your
<literal>PATH</literal>, then follow the appveyor CI cmake
<ulink
url="https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml">build
instructions</ulink>.
</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>./configure</command>
</programlisting>
followed by:
<programlisting>
<command>make</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>autoconf automake libtool pkgconfig ragel gtk-doc</package>
</programlisting>
to install the build dependencies.
</para>
<para>If you are using Homebrew, you should run:
<programlisting>
<command>brew install</command> <package>autoconf automake libtool pkgconfig ragel gtk-doc</package>
</programlisting>
Finally, you can run:
<programlisting>
<command>./autogen.sh</command>
</programlisting>
</para>
<para>
<emphasis>(3)</emphasis> You can now build HarfBuzz (on either
a MacPorts or a Homebrew system) by running:
<programlisting>
<command>./configure</command>
</programlisting>
followed by:
<programlisting>
<command>make</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>--with-libstdc++</command></term>
<listitem>
<para>
Allow linking with libstdc++. <emphasis>(Default = no)</emphasis>
</para>
<para>
This option enables or disables linking HarfBuzz to the
system's libstdc++ library.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>--with-glib</command></term>
<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>--with-gobject</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>--with-cairo</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>--with-fontconfig</command></term>
<listitem>
<para>
Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
</para>
<para>
This option enables or disables usage of the Fontconfig
library, which provides font-matching functions and
provides access to font properties. The default setting
is to check for the presence of Fontconfig and, if it is
found, build with Fontconfig support.
</para>
<para>
Note: Fontconfig is used only by the HarfBuzz
command-line utilities, and not by the HarfBuzz library.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>--with-icu</command></term>
<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>--with-ucdn</command></term>
<listitem>
<para>
Use HarfBuzz's <ulink url="https://github.com/harfbuzz/harfbuzz/tree/master/src/hb-ucdn">built-in UCDN library</ulink>. <emphasis>(Default = auto)</emphasis>
</para>
<para>
The HarfBuzz source tree includes a <emphasis>Unicode
Database and Normalization</emphasis> (UCDN) library
that provides access to basic character properties in
the Unicode Character Database (UCD) as well as low-level
normalization functions. HarfBuzz can be built without
this UCDN support if the usage of a different UCDN
library is desired.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>--with-graphite2</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>--with-freetype</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>--with-uniscribe</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>--with-directwrite</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>--with-coretext</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>--enable-gtk-doc</command></term>
<listitem>
<para>
Use <ulink url="https://www.gtk.org/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>

View File

@ -1,3 +1,9 @@
<?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>
<section id="opentype-features">
@ -10,4 +16,4 @@
<para>
</para>
</section>
</chapter>
</chapter>

View File

@ -0,0 +1,375 @@
<?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 <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="complex-scripts">
<title>Complex scripts</title>
<para>
In text-shaping terminology, scripts are generally classified as
either <emphasis>complex</emphasis> or <emphasis>non-complex</emphasis>.
</para>
<para>
Complex scripts are those for which transforming the input
sequence into the final layout requires some combination of
operations&mdash;such as context-dependent substitutions,
context-dependent mark positioning, glyph-to-glyph joining,
glyph reordering, or glyph stacking.
</para>
<para>
In some complex scripts, the shaping rules require that a text
run be divided into syllables before the operations can be
applied. Other complex scripts may apply shaping operations over
entire words or over the entire text run, with no subdivision
required.
</para>
<para>
Non-complex scripts, by definition, do not require these
operations. However, correctly shaping a text run in a
non-complex script may still involve Unicode normalization,
ligature substitutions, mark positioning, kerning, and applying
other font features. The key difference is that a text run in a
non-complex script can be processed sequentially and in the same
order as the input sequence of Unicode codepoints, without
requiring an analysis stage.
</para>
</section>
<section id="shaping-operations">
<title>Shaping operations</title>
<para>
Shaping a complex-script 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 complex-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 complex 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 complex 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 complex
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 complex 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
non-complex scripts, 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, Telugu, and Sinhala.
</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 complex 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>

View File

@ -1,115 +1,442 @@
<?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>. It solves
the problem of selecting and positioning glyphs from a font given a
Unicode string.
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.
</para>
<section id="why-do-i-need-it">
<title>Why do I need it?</title>
<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>
<para>
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.
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.
</para>
<para>
However, if you <emphasis>are</emphasis> writing a layout engine
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:
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:
</para>
<itemizedlist>
<listitem>
<para>
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
&quot;a&quot; 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 &quot;cmap&quot; table) which maps
Unicode codepoints to glyph IDs. Text shaping turns codepoints
into glyph IDs.
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 &quot;a&quot; as glyph ID 1, but
many others do not. In order to retrieve the right glyph
from the font to display &quot;a&quot;, 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>.
</para>
</listitem>
<listitem>
<para>
Many OpenType fonts contain ligatures: combinations of
characters which are rendered together. For instance, it's
common for the <literal>fi</literal> combination to appear in
print as the single ligature &quot;&quot;. Whether you should
render text as <literal>fi</literal> or &quot;&quot; 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.
characters that are rendered as a single unit. For instance,
it is common for the &quot;f, i&quot; letter
sequence to appear in print as the single ligature glyph
&quot;&quot;.
</para>
<para>
Whether you should render an &quot;f, i&quot; sequence
as <literal>fi</literal> or as &quot;&quot; does not
depend on the input text. Instead, it depends on the whether
or not the font includes an &quot;&quot; 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>.
</para>
</listitem>
<listitem>
<para>
While ligatures like &quot;&quot; are typographic
refinements, some languages <emphasis>require</emphasis> such
While ligatures like &quot;&quot; are optional typographic
refinements, some languages <emphasis>require</emphasis> certain
substitutions to be made in order to display text correctly.
In Tamil, when the letter &quot;TTA&quot; (ட) letter is
followed by &quot;U&quot; (உ), the combination should appear
as the single glyph &quot;டு&quot;. The sequence of Unicode
characters &quot;டஉ&quot; needs to be rendered as a single
glyph from the font - text shaping chooses the correct glyph
from the sequence of characters provided.
</para>
<para>
For example, in Tamil, when the letter &quot;TTA&quot; (ட)
letter is followed by &quot;U&quot; (உ), the pair
must be replaced by the single glyph &quot;டு&quot;. The
sequence of Unicode characters &quot;டஉ&quot; needs to be
substituted with a single &quot;டு&quot; glyph from the
font.
</para>
<para>
But &quot;டு&quot; 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>.
</para>
</listitem>
<listitem>
<para>
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.
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>.
</para>
</listitem>
<listitem>
<para>
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
&quot;zhe&quot; (ж) 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.
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
&quot;zhe&quot; (ж) with a breve accent, like so: &quot;ӂ&quot;.
</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 &quot;ж&quot; and &quot;˘&quot;
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&mdash;and,
if so, where to position those marks.</emphasis>
</para>
</listitem>
</itemizedlist>
<para>
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.
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>
<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, Telugu, and
Sinhala)
</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.
</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>
(&quot;bidi&quot; 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 &quot;a
<emphasis>huge</emphasis> breakfast&quot;, and you expect
&quot;huge&quot; 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&mdash;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
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 - &quot;HarfBuzz&quot; is the Persian
for &quot;open type&quot;.
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&mdash;&quot;HarfBuzz&quot; is
the Persian for &quot;open type&quot;.
</para>
</section>
</chapter>
</chapter>

View File

@ -0,0 +1,97 @@
# Copied from https://docs.microsoft.com/en-us/typography/script-development/use
# On October 23, 2018; with documentd dated 02/07/2018.
0905 0946 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT E
0905 093E ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AA
0930 094D 0907 ; # DEVANAGARI LETTER RA, DEVANAGARI SIGN VIRAMA, DEVANAGARI LETTER I
0909 0941 ; # DEVANAGARI LETTER U, DEVANAGARI VOWEL SIGN U
090F 0945 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN CANDRA E
090F 0946 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN SHORT E
090F 0947 ; # DEVANAGARI LETTER E, DEVANAGARI VOWEL SIGN E
0905 0949 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA O
0906 0945 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN CANDRA E
0905 094A ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN SHORT O
0906 0946 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN SHORT E
0905 094B ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN O
0906 0947 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN E
0905 094C ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AU
0906 0948 ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN AI
0905 0945 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN CANDRA E
0905 093A ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OE
0905 093B ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN OOE
0906 093A ; # DEVANAGARI LETTER AA, DEVANAGARI VOWEL SIGN OE
0905 094F ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN AW
0905 0956 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UE
0905 0957 ; # DEVANAGARI LETTER A, DEVANAGARI VOWEL SIGN UUE
0985 09BE ; # BENGALI LETTER A, BENGALI VOWEL SIGN AA
098B 09C3 ; # BENGALI LETTER VOCALIC R, BENGALI VOWEL SIGN VOCALIC R
098C 09E2 ; # BENGALI LETTER VOCALIC L, BENGALI VOWEL SIGN VOCALIC L
0A05 0A3E ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AA
0A72 0A3F ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN I
0A72 0A40 ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN II
0A73 0A41 ; # GURMUKHI URA, GURMUKHI VOWEL SIGN U
0A73 0A42 ; # GURMUKHI URA, GURMUKHI VOWEL SIGN UU
0A72 0A47 ; # GURMUKHI IRI, GURMUKHI VOWEL SIGN EE
0A05 0A48 ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AI
0A73 0A4B ; # GURMUKHI URA, GURMUKHI VOWEL SIGN OO
0A05 0A4C ; # GURMUKHI LETTER A, GURMUKHI VOWEL SIGN AU
0A85 0ABE ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA
0A85 0AC5 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA E
0A85 0AC7 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN E
0A85 0AC8 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AI
0A85 0AC9 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN CANDRA O
0A85 0ACB ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN O
0A85 0ABE 0AC5 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN CANDRA E
0A85 0ACC ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AU
0A85 0ABE 0AC8 ; # GUJARATI LETTER A, GUJARATI VOWEL SIGN AA, GUJARATI VOWEL SIGN AI
0AC5 0ABE ; # GUJARATI VOWEL SIGN CANDRA E, GUJARATI VOWEL SIGN AA
0B05 0B3E ; # ORIYA LETTER A, ORIYA VOWEL SIGN AA
0B0F 0B57 ; # ORIYA LETTER E, ORIYA AU LENGTH MARK
0B13 0B57 ; # ORIYA LETTER O, ORIYA AU LENGTH MARK
0C12 0C55 ; # TELUGU LETTER O, TELUGU LENGTH MARK
0C12 0C4C ; # TELUGU LETTER O, TELUGU VOWEL SIGN AU
0C3F 0C55 ; # TELUGU VOWEL SIGN I, TELUGU LENGTH MARK
0C46 0C55 ; # TELUGU VOWEL SIGN E, TELUGU LENGTH MARK
0C4A 0C55 ; # TELUGU VOWEL SIGN O, TELUGU LENGTH MARK
0C89 0CBE ; # KANNADA LETTER U, KANNADA VOWEL SIGN AA
0C92 0CCC ; # KANNADA LETTER O, KANNADA VOWEL SIGN AU
0C8B 0CBE ; # KANNADA LETTER VOCALIC R, KANNADA VOWEL SIGN AA
0D07 0D57 ; # MALAYALAM LETTER I, MALAYALAM AU LENGTH MARK
0D09 0D57 ; # MALAYALAM LETTER U, MALAYALAM AU LENGTH MARK
0D0E 0D46 ; # MALAYALAM LETTER E, MALAYALAM VOWEL SIGN E
0D12 0D3E ; # MALAYALAM LETTER O, MALAYALAM VOWEL SIGN AA
0D12 0D57 ; # MALAYALAM LETTER O, MALAYALAM AU LENGTH MARK
0D85 0DCF ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN AELA-PILLA
0D85 0DD0 ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN KETTI AEDA-PILLA
0D85 0DD1 ; # SINHALA LETTER AYANNA, SINHALA VOWEL SIGN DIGA AEDA-PILLA
0D8B 0DDF ; # SINHALA LETTER UYANNA, SINHALA VOWEL SIGN GAYANUKITTA
0D8D 0DD8 ; # SINHALA LETTER IRUYANNA, SINHALA VOWEL SIGN GAETTA-PILLA
0D8F 0DDF ; # SINHALA LETTER ILUYANNA, SINHALA VOWEL SIGN GAYANUKITTA
0D91 0DCA ; # SINHALA LETTER EYANNA, SINHALA SIGN AL-LAKUNA
0D91 0DD9 ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA
0D91 0DDA ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN DIGA KOMBUVA
0D91 0DDC ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA
0D91 0DDD ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
0D91 0DDD ; # SINHALA LETTER EYANNA, SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA
0D94 0DDF ; # SINHALA LETTER OYANNA, SINHALA VOWEL SIGN GAYANUKITTA
11005 11038 ; # BRAHMI LETTER A, BRAHMI VOWEL SIGN AA
1100B 1103E ; # BRAHMI LETTER VOCALIC R, BRAHMI VOWEL SIGN VOCALIC R
1100F 11042 ; # BRAHMI LETTER E, BRAHMI VOWEL SIGN E
11680 116AD ; # TAKRI LETTER A, TAKRI VOWEL SIGN AA
11686 116B2 ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
11680 116B4 ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
11680 116B5 ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
112B0 112E0 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
112B0 112E5 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
112B0 112E6 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
112B0 112E7 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN O
112B0 112E8 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AU
11481 114B0 ; # TIRHUTA LETTER A, TIRHUTA VOWEL SIGN AA
114AA 114B5 ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC R
114AA 114B6 ; # TIRHUTA LETTER LA, TIRHUTA VOWEL SIGN VOCALIC RR
1148B 114BA ; # TIRHUTA LETTER E, TIRHUTA VOWEL SIGN SHORT E
1148D 114BA ; # TIRHUTA LETTER O, TIRHUTA VOWEL SIGN SHORT E
11600 11639 ; # MODI LETTER A, MODI VOWEL SIGN E
11600 1163A ; # MODI LETTER A, MODI VOWEL SIGN AI
11601 11639 ; # MODI LETTER AA, MODI VOWEL SIGN E
11601 1163A ; # MODI LETTER AA, MODI VOWEL SIGN AI

View File

@ -13,9 +13,8 @@ TESTS =
check_PROGRAMS =
# Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la
lib: $(BUILT_SOURCES) libharfbuzz.la
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
lib_LTLIBRARIES = libharfbuzz.la
@ -29,12 +28,6 @@ HBSOURCES = $(HB_BASE_sources)
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
HBHEADERS = $(HB_BASE_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
@ -171,37 +164,6 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
pkgconfig_DATA += harfbuzz-subset.pc
EXTRA_DIST += harfbuzz-subset.pc.in
FUZZING_CPPFLAGS = \
-DHB_NDEBUG \
-DHB_MAX_NESTING_LEVEL=3 \
-DHB_SANITIZE_MAX_EDITS=3 \
-DHB_SANITIZE_MAX_OPS_FACTOR=3 \
-DHB_SANITIZE_MAX_OPS_MIN=128 \
-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-subset-fuzzing.la
libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS)
libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-fuzzing.la
libharfbuzz_subset_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_subset_fuzzing_la_LDFLAGS)
libharfbuzz_subset_fuzzing_la_SOURCES = $(libharfbuzz_subset_la_SOURCES)
libharfbuzz_subset_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_subset_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
libharfbuzz_subset_fuzzing_la_LIBADD = $(libharfbuzz_subset_la_LIBADD)
EXTRA_libharfbuzz_subset_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_subset_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-subset-fuzzing.la
if HAVE_ICU
if HAVE_ICU_BUILTIN
HBCFLAGS += $(ICU_CFLAGS)
@ -271,7 +233,7 @@ EXTRA_DIST += \
CLEANFILES += $(pkgconfig_DATA)
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated-symbols.txt
if HAVE_GOBJECT
DEF_FILES += harfbuzz-gobject.def
endif
@ -285,17 +247,23 @@ 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 "$@" $^
GENERATORS = \
gen-arabic-table.py \
gen-indic-table.py \
gen-use-table.py \
gen-def.py \
gen-emoji-table.py \
gen-indic-table.py \
gen-os2-unicode-ranges.py \
gen-tag-table.py \
gen-use-table.py \
gen-vowel-constraints.py \
$(NULL)
EXTRA_DIST += $(GENERATORS)
unicode-tables: arabic-table indic-table use-table
unicode-tables: arabic-table indic-table tag-table use-table emoji-table
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
@ -305,22 +273,32 @@ indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategor
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
tag-table: gen-tag-table.py languagetags language-subtag-registry
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
|| ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
vowel-constraints: gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false)
emoji-table: gen-emoji-table.py emoji-data.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
built-sources: $(BUILT_SOURCES)
.PHONY: unicode-tables arabic-table indic-table use-table built-sources
.PHONY: unicode-tables arabic-table indic-table tag-table use-table vowel-constraints emoji-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)
@ -332,6 +310,7 @@ noinst_PROGRAMS = \
main \
test \
test-buffer-serialize \
test-name-table \
test-size-params \
test-would-substitute \
$(NULL)
@ -345,17 +324,30 @@ 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_buffer_serialize_SOURCES = test-buffer-serialize.cc
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
test_name_table_SOURCES = test-name-table.cc
test_name_table_CPPFLAGS = $(HBCFLAGS)
test_name_table_LDADD = libharfbuzz.la $(HBLIBS)
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_would_substitute_SOURCES = test-would-substitute.cc
test_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
test_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
if HAVE_FREETYPE
if HAVE_CAIRO_FT
noinst_PROGRAMS += test-ot-color
test_ot_color_SOURCES = test-ot-color.cc
test_ot_color_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS)
test_ot_color_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS)
endif # HAVE_CAIRO_FT
endif # HAVE_FREETYPE
dist_check_SCRIPTS = \
check-c-linkage-decls.sh \
@ -392,24 +384,27 @@ dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
dump_use_data_CPPFLAGS = $(HBCFLAGS)
dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
if HAVE_FREETYPE
if HAVE_CAIRO_FT
check_PROGRAMS += dump-emoji
dump_emoji_SOURCES = dump-emoji.cc
dump_emoji_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) $(CAIRO_FT_CFLAGS)
dump_emoji_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) $(CAIRO_LIBS) $(CAIRO_FT_LIBS)
endif # HAVE_CAIRO_FT
endif # HAVE_FREETYPE
COMPILED_TESTS = test-algs test-iter test-ot-tag test-unicode-ranges
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
check_PROGRAMS += $(COMPILED_TESTS)
TESTS += $(COMPILED_TESTS)
check_PROGRAMS += test-ot-tag test-unicode-ranges
TESTS += test-ot-tag test-unicode-ranges
test_algs_SOURCES = test-algs.cc hb-static.cc
test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_algs_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_ot_tag_SOURCES = hb-ot-tag.cc
test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
test_unicode_ranges_SOURCES = test-unicode-ranges.cc
test_unicode_ranges_LDADD = libharfbuzz.la $(HBLIBS)
test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
@ -435,6 +430,8 @@ HarfBuzz_0_0_gir_CFLAGS = \
-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= \

View File

@ -1,75 +1,178 @@
# Base and default-included sources and headers
HB_BASE_sources = \
hb-aat-fdsc-table.hh \
hb-aat-layout-ankr-table.hh \
hb-aat-layout-bsln-table.hh \
hb-aat-layout-common.hh \
hb-aat-layout-feat-table.hh \
hb-aat-layout-just-table.hh \
hb-aat-layout-kerx-table.hh \
hb-aat-layout-lcar-table.hh \
hb-aat-layout-morx-table.hh \
hb-aat-layout-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-blob.hh \
hb-blob.cc \
hb-buffer.hh \
hb-blob.hh \
hb-buffer-serialize.cc \
hb-buffer.cc \
hb-buffer.hh \
hb-cache.hh \
hb-cff-interp-common.hh \
hb-cff-interp-cs-common.hh \
hb-cff-interp-dict-common.hh \
hb-cff1-interp-cs.hh \
hb-cff2-interp-cs.hh \
hb-common.cc \
hb-debug.hh \
hb-dsalgs.hh \
hb-face.hh \
hb-dispatch.hh \
hb-face.cc \
hb-font.hh \
hb-face.hh \
hb-font.cc \
hb-font.hh \
hb-iter.hh \
hb-map.hh \
hb-map.cc \
hb-kern.hh \
hb-machinery.hh \
hb-map.cc \
hb-map.hh \
hb-meta.hh \
hb-mutex.hh \
hb-null.hh \
hb-object.hh \
hb-open-file.hh \
hb-open-type.hh \
hb-ot-color-cbdt-table.hh \
hb-ot-cff-common.hh \
hb-ot-cff1-table.cc \
hb-ot-cff1-table.hh \
hb-ot-cff2-table.cc \
hb-ot-cff2-table.hh \
hb-ot-cmap-table.hh \
hb-ot-color-cbdt-table.hh \
hb-ot-color-colr-table.hh \
hb-ot-color-cpal-table.hh \
hb-ot-color-sbix-table.hh \
hb-ot-color-svg-table.hh \
hb-ot-color.cc \
hb-ot-face.cc \
hb-ot-face.hh \
hb-ot-font.cc \
hb-ot-gasp-table.hh \
hb-ot-glyf-table.hh \
hb-ot-hdmx-table.hh \
hb-ot-head-table.hh \
hb-ot-hhea-table.hh \
hb-ot-hmtx-table.hh \
hb-ot-kern-table.hh \
hb-ot-layout-base-table.hh \
hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-ot-layout-gsub-table.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout.cc \
hb-ot-layout.hh \
hb-ot-map.cc \
hb-ot-map.hh \
hb-ot-math-table.hh \
hb-ot-math.cc \
hb-ot-maxp-table.hh \
hb-ot-name-language.cc \
hb-ot-name-language.hh \
hb-ot-name-table.hh \
hb-ot-name.cc \
hb-ot-os2-table.hh \
hb-ot-os2-unicode-ranges.hh \
hb-ot-post-macroman.hh \
hb-ot-post-table.hh \
hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-arabic-win1256.hh \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic.hh \
hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-hangul.cc \
hb-ot-shape-complex-hebrew.cc \
hb-ot-shape-complex-indic-table.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic.hh \
hb-ot-shape-complex-khmer.cc \
hb-ot-shape-complex-khmer.hh \
hb-ot-shape-complex-myanmar.cc \
hb-ot-shape-complex-myanmar.hh \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-complex-use-table.cc \
hb-ot-shape-complex-use.cc \
hb-ot-shape-complex-use.hh \
hb-ot-shape-complex-vowel-constraints.cc \
hb-ot-shape-complex-vowel-constraints.hh \
hb-ot-shape-complex.hh \
hb-ot-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.hh \
hb-ot-var-avar-table.hh \
hb-ot-var-fvar-table.hh \
hb-ot-var-hvar-table.hh \
hb-ot-var-mvar-table.hh \
hb-ot-var.cc \
hb-ot-vorg-table.hh \
hb-pool.hh \
hb-sanitize.hh \
hb-serialize.hh \
hb-set-digest.hh \
hb-set.hh \
hb-set.cc \
hb-shape.cc \
hb-shape-plan.hh \
hb-set.hh \
hb-shape-plan.cc \
hb-shaper-list.hh \
hb-shape-plan.hh \
hb-shape.cc \
hb-shaper-impl.hh \
hb-shaper.hh \
hb-shaper-list.hh \
hb-shaper.cc \
hb-shaper.hh \
hb-static.cc \
hb-string-array.hh \
hb-unicode.hh \
hb-unicode-emoji-table.hh \
hb-unicode.cc \
hb-vector.hh \
hb-unicode.hh \
hb-utf.hh \
hb-vector.hh \
hb-warning.cc \
hb.hh \
$(NULL)
HB_BASE_RAGEL_GENERATED_sources = \
hb-buffer-deserialize-json.hh \
hb-buffer-deserialize-text.hh \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-khmer-machine.hh \
hb-ot-shape-complex-myanmar-machine.hh \
hb-ot-shape-complex-use-machine.hh \
$(NULL)
HB_BASE_RAGEL_sources = \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text.rl \
hb-ot-shape-complex-indic-machine.rl \
hb-ot-shape-complex-khmer-machine.rl \
hb-ot-shape-complex-myanmar-machine.rl \
hb-ot-shape-complex-use-machine.rl \
$(NULL)
HB_BASE_headers = \
hb.h \
hb-aat-layout.h \
hb-aat.h \
hb-blob.h \
hb-buffer.h \
hb-common.h \
@ -77,106 +180,27 @@ HB_BASE_headers = \
hb-face.h \
hb-font.h \
hb-map.h \
hb-ot-color.h \
hb-ot-deprecated.h \
hb-ot-font.h \
hb-ot-layout.h \
hb-ot-math.h \
hb-ot-name.h \
hb-ot-shape.h \
hb-ot-var.h \
hb-ot.h \
hb-set.h \
hb-shape.h \
hb-shape-plan.h \
hb-shape.h \
hb-unicode.h \
hb-version.h \
hb.h \
$(NULL)
HB_FALLBACK_sources = \
hb-fallback-shape.cc \
$(NULL)
HB_OT_sources = \
hb-aat-layout.cc \
hb-aat-layout-common.hh \
hb-aat-layout-ankr-table.hh \
hb-aat-layout-bsln-table.hh \
hb-aat-layout-feat-table.hh \
hb-aat-layout-kerx-table.hh \
hb-aat-layout-morx-table.hh \
hb-aat-layout-trak-table.hh \
hb-aat-layout.hh \
hb-aat-ltag-table.hh \
hb-ot-face.hh \
hb-ot-face.cc \
hb-ot-font.cc \
hb-ot-layout.cc \
hb-ot-layout-base-table.hh \
hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-gsub-table.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout.hh \
hb-ot-color.cc \
hb-ot-color-colr-table.hh \
hb-ot-color-cpal-table.hh \
hb-ot-color-sbix-table.hh \
hb-ot-color-svg-table.hh \
hb-ot-map.cc \
hb-ot-map.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.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.hh \
hb-ot-shape-complex-indic-table.cc \
hb-ot-shape-complex-khmer.hh \
hb-ot-shape-complex-khmer.cc \
hb-ot-shape-complex-myanmar.hh \
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.hh \
hb-ot-shape-complex-use-table.cc \
hb-ot-shape-complex.hh \
hb-ot-shape-normalize.hh \
hb-ot-shape-normalize.cc \
hb-ot-shape-fallback.hh \
hb-ot-shape-fallback.cc \
hb-ot-shape.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-shape.h \
hb-ot-tag.h \
hb-ot-var.h \
$(NULL)
# Optional Sources and Headers with external deps
HB_FT_sources = hb-ft.cc
@ -208,15 +232,26 @@ HB_ICU_headers = hb-icu.h
# Sources for libharfbuzz-subset
HB_SUBSET_sources = \
hb-ot-cff1-table.cc \
hb-ot-cff2-table.cc \
hb-static.cc \
hb-subset.cc \
hb-subset.hh \
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-glyf.cc \
hb-subset-glyf.hh \
hb-subset-glyf.hh \
hb-subset-input.cc \
hb-subset-input.hh \
hb-subset-plan.cc \
hb-subset-plan.hh \
hb-subset-plan.hh \
hb-subset.cc \
hb-subset.hh \
hb-subset.hh \
$(NULL)
HB_SUBSET_headers = \

View File

@ -26,7 +26,7 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
symprefix=
if test $suffix = dylib; then symprefix=_; fi
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
EXPORTED_SYMBOLS=`nm "$so" | grep ' [BCDGINRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`
prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`

View File

@ -1,261 +0,0 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include "hb-static.cc"
#include "hb-ot-color-cbdt-table.hh"
#include "hb-ot-color-colr-table.hh"
#include "hb-ot-color-cpal-table.hh"
#include "hb-ot-color-sbix-table.hh"
#include "hb-ot-color-svg-table.hh"
#include "hb-ft.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <cairo.h>
#include <cairo-ft.h>
#include <cairo-svg.h>
#ifdef HAVE_GLIB
#include <glib.h>
#endif
#include <stdlib.h>
#include <stdio.h>
void cbdt_callback (const uint8_t* data, unsigned int length,
unsigned int group, unsigned int gid)
{
char output_path[255];
sprintf (output_path, "out/cbdt-%d-%d.png", group, gid);
FILE *f = fopen (output_path, "wb");
fwrite (data, 1, length, f);
fclose (f);
}
void sbix_callback (const uint8_t* data, unsigned int length,
unsigned int group, unsigned int gid)
{
char output_path[255];
sprintf (output_path, "out/sbix-%d-%d.png", group, gid);
FILE *f = fopen (output_path, "wb");
fwrite (data, 1, length, f);
fclose (f);
}
void svg_callback (const uint8_t* data, unsigned int length,
unsigned int start_glyph, unsigned int end_glyph)
{
char output_path[255];
if (start_glyph == end_glyph)
sprintf (output_path, "out/svg-%d.svg", start_glyph);
else
sprintf (output_path, "out/svg-%d-%d.svg", start_glyph, end_glyph);
// append "z" if the content is gzipped
if ((data[0] == 0x1F) && (data[1] == 0x8B))
strcat (output_path, "z");
FILE *f = fopen (output_path, "wb");
fwrite (data, 1, length, f);
fclose (f);
}
void colr_cpal_rendering (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs,
const OT::COLR *colr, const OT::CPAL *cpal)
{
for (unsigned int i = 0; i < num_glyphs; ++i)
{
unsigned int first_layer_index, num_layers;
if (colr->get_base_glyph_record (i, &first_layer_index, &num_layers))
{
// Measure
cairo_text_extents_t extents;
{
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
cairo_t *cr = cairo_create (surface);
cairo_set_font_face (cr, cairo_face);
cairo_set_font_size (cr, upem);
cairo_glyph_t *glyphs = (cairo_glyph_t *) calloc (num_layers, sizeof (cairo_glyph_t));
for (unsigned int j = 0; j < num_layers; ++j)
{
hb_codepoint_t glyph_id;
unsigned int color_index;
colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index);
glyphs[j].index = glyph_id;
}
cairo_glyph_extents (cr, glyphs, num_layers, &extents);
free (glyphs);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
// Add a slight margin
extents.width += extents.width / 10;
extents.height += extents.height / 10;
extents.x_bearing -= extents.width / 20;
extents.y_bearing -= extents.height / 20;
// Render
unsigned int pallet_count = cpal->get_palette_count ();
for (unsigned int pallet = 0; pallet < pallet_count; ++pallet) {
char output_path[255];
// If we have more than one pallet, use a better namin
if (pallet_count == 1)
sprintf (output_path, "out/colr-%d.svg", i);
else
sprintf (output_path, "out/colr-%d-%d.svg", i, pallet);
cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
cairo_t *cr = cairo_create (surface);
cairo_set_font_face (cr, cairo_face);
cairo_set_font_size (cr, upem);
for (unsigned int j = 0; j < num_layers; ++j)
{
hb_codepoint_t glyph_id;
unsigned int color_index;
colr->get_layer_record (first_layer_index + j, &glyph_id, &color_index);
uint32_t color = cpal->get_color_record_argb (color_index, pallet);
int alpha = color & 0xFF;
int r = (color >> 8) & 0xFF;
int g = (color >> 16) & 0xFF;
int b = (color >> 24) & 0xFF;
cairo_set_source_rgba (cr, r / 255.f, g / 255.f, b / 255.f, alpha);
cairo_glyph_t glyph;
glyph.index = glyph_id;
glyph.x = -extents.x_bearing;
glyph.y = -extents.y_bearing;
cairo_show_glyphs (cr, &glyph, 1);
}
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
}
}
}
void dump_glyphs (cairo_font_face_t *cairo_face, unsigned int upem, unsigned int num_glyphs)
{
// Dump every glyph available on the font
return; // disabled for now
for (unsigned int i = 0; i < num_glyphs; ++i)
{
cairo_text_extents_t extents;
cairo_glyph_t glyph = {0};
glyph.index = i;
// Measure
{
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
cairo_t *cr = cairo_create (surface);
cairo_set_font_face (cr, cairo_face);
cairo_set_font_size (cr, upem);
cairo_glyph_extents (cr, &glyph, 1, &extents);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
// Add a slight margin
extents.width += extents.width / 10;
extents.height += extents.height / 10;
extents.x_bearing -= extents.width / 20;
extents.y_bearing -= extents.height / 20;
// Render
{
char output_path[255];
sprintf (output_path, "out/%d.svg", i);
cairo_surface_t *surface = cairo_svg_surface_create (output_path, extents.width, extents.height);
cairo_t *cr = cairo_create (surface);
cairo_set_font_face (cr, cairo_face);
cairo_set_font_size (cr, upem);
glyph.x = -extents.x_bearing;
glyph.y = -extents.y_bearing;
cairo_show_glyphs (cr, &glyph, 1);
cairo_surface_destroy (surface);
cairo_destroy (cr);
}
}
}
int main (int argc, char **argv)
{
if (argc != 2) {
fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
exit (1);
}
hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
hb_face_t *face = hb_face_create (blob, 0);
hb_font_t *font = hb_font_create (face);
OT::CBDT::accelerator_t cbdt;
cbdt.init (face);
cbdt.dump (cbdt_callback);
cbdt.fini ();
OT::sbix::accelerator_t sbix;
sbix.init (face);
sbix.dump (sbix_callback);
sbix.fini ();
OT::SVG::accelerator_t svg;
svg.init (face);
svg.dump (svg_callback);
svg.fini ();
hb_blob_t* colr_blob = hb_sanitize_context_t ().reference_table<OT::COLR> (face);
const OT::COLR *colr = colr_blob->as<OT::COLR> ();
hb_blob_t* cpal_blob = hb_sanitize_context_t ().reference_table<OT::CPAL> (face);
const OT::CPAL *cpal = cpal_blob->as<OT::CPAL> ();
cairo_font_face_t *cairo_face;
{
FT_Library library;
FT_Init_FreeType (&library);
FT_Face ftface;
FT_New_Face (library, argv[1], 0, &ftface);
cairo_face = cairo_ft_font_face_create_for_ft_face (ftface, 0);
}
unsigned int num_glyphs = hb_face_get_glyph_count (face);
unsigned int upem = hb_face_get_upem (face);
colr_cpal_rendering (cairo_face, upem, num_glyphs, colr, cpal);
dump_glyphs (cairo_face, upem, num_glyphs);
hb_font_destroy (font);
hb_face_destroy (face);
hb_blob_destroy (blob);
return 0;
}

View File

@ -27,7 +27,7 @@
#include "hb-ot-shape-complex-indic.hh"
int
main (void)
main ()
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{

View File

@ -27,17 +27,15 @@
#include "hb-ot-shape-complex-khmer.hh"
int
main (void)
main ()
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{
hb_glyph_info_t info;
info.codepoint = u;
set_khmer_properties (info);
if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
info.khmer_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
printf("U+%04X %u %u\n", u,
info.khmer_category(),
info.khmer_position());
if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER)
printf("U+%04X %u\n", u,
info.khmer_category());
}
}

View File

@ -27,7 +27,7 @@
#include "hb-ot-shape-complex-myanmar.hh"
int
main (void)
main ()
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{

View File

@ -27,7 +27,7 @@
#include "hb-ot-shape-complex-use.hh"
int
main (void)
main ()
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{

View File

@ -15,11 +15,10 @@ for h in header_paths:
if h.endswith (".h"):
with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
result = """EXPORTS
symbols = "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M)))
result = symbols if os.environ.get('PLAIN_LIST', '') else """EXPORTS
%s
LIBRARY lib%s-0.dll""" % (
"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))),
output_file.replace ('.def', '')
)
LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('.def', ''))
with open (output_file, "w") as f: f.write (result)

67
src/gen-emoji-table.py Executable file
View File

@ -0,0 +1,67 @@
#!/usr/bin/python
from __future__ import print_function, division, absolute_import
import sys
import os.path
from collections import OrderedDict
if len (sys.argv) != 2:
print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr)
sys.exit (1)
f = open(sys.argv[1])
header = [f.readline () for _ in range(10)]
ranges = OrderedDict()
for line in f.readlines():
line = line.strip()
if not line or line[0] == '#':
continue
rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]]
rang = [int(s, 16) for s in rang.split('..')]
if len(rang) > 1:
start, end = rang
else:
start = end = rang[0]
if typ not in ranges:
ranges[typ] = []
if ranges[typ] and ranges[typ][-1][1] == start - 1:
ranges[typ][-1] = (ranges[typ][-1][0], end)
else:
ranges[typ].append((start, end))
print ("/* == Start of generated table == */")
print ("/*")
print (" * The following tables are generated by running:")
print (" *")
print (" * ./gen-emoji-table.py emoji-data.txt")
print (" *")
print (" * on file with this header:")
print (" *")
for l in header:
print (" * %s" % (l.strip()))
print (" */")
print ()
print ("#ifndef HB_UNICODE_EMOJI_TABLE_HH")
print ("#define HB_UNICODE_EMOJI_TABLE_HH")
print ()
print ('#include "hb-unicode.hh"')
print ()
for typ,s in ranges.items():
if typ != "Extended_Pictographic": continue
print()
print("static const struct hb_unicode_range_t _hb_unicode_emoji_%s_table[] =" % typ)
print("{")
for pair in sorted(s):
print(" {0x%04X, 0x%04X}," % pair)
print("};")
print ()
print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
print ()
print ("/* == End of generated table == */")

View File

@ -79,10 +79,6 @@ data = combined
del combined
num = len (data)
for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0, 0x17D3]:
if data[u][0] == 'Other':
data[u][0] = "Vowel_Dependent"
# Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
singles = {}
for u in ALLOWED_SINGLES:
@ -131,6 +127,8 @@ for i in range (2):
what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
what_short = ["ISC", "IMC"]
print ('#pragma GCC diagnostic push')
print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
for i in range (2):
print ()
vv = sorted (values[i].keys ())
@ -148,6 +146,7 @@ for i in range (2):
(what_short[i], s, what[i], v.upper (),
' '* ((48-1 - len (what[i]) - 1 - len (v)) // 8),
values[i][v], v))
print ('#pragma GCC diagnostic pop')
print ()
print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
print ()

View File

@ -10,10 +10,13 @@ import io
import re
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
try:
reload(sys)
sys.setdefaultencoding('utf-8')
except NameError:
pass # Python 3
print ("""static Range os2UnicodeRangesSorted[] =
print ("""static OS2Range _hb_os2_unicode_ranges[] =
{""")
args = sys.argv[1:]
@ -32,12 +35,12 @@ with io.open(input_file, mode="r", encoding="utf-8") as f:
current_bit = fields[0]
fields = fields[1:]
elif len(fields) > 3:
raise Error("bad input :(.")
raise Exception("bad input :(.")
name = fields[0]
ranges = re.split("-", fields[1])
if len(ranges) != 2:
raise Error("bad input :(.")
raise Exception("bad input :(.")
v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name))
all_ranges.append(v)

1126
src/gen-tag-table.py Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,16 @@
#!/usr/bin/env python
# flake8: noqa
from __future__ import print_function, division, absolute_import
import io, sys
import io
import sys
if len (sys.argv) != 5:
print ("usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
sys.exit (1)
BLACKLISTED_BLOCKS = ["Thai", "Lao", "Tibetan"]
BLACKLISTED_BLOCKS = ["Thai", "Lao"]
files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
@ -46,10 +48,11 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
# TODO Characters that are not in Unicode Indic files, but used in USE
data[0][0x034F] = defaults[0]
data[0][0x2060] = defaults[0]
data[0][0x20F0] = defaults[0]
# TODO https://github.com/roozbehp/unicode-data/issues/9
data[0][0x11C44] = 'Consonant_Placeholder'
data[0][0x11C45] = 'Consonant_Placeholder'
# TODO https://github.com/harfbuzz/harfbuzz/pull/1399
data[0][0x111C8] = 'Consonant_Placeholder'
for u in range (0xFE00, 0xFE0F + 1):
data[0][u] = defaults[0]
@ -168,7 +171,7 @@ def is_BASE(U, UISC, UGC):
def is_BASE_IND(U, UISC, UGC):
#SPEC-DRAFT return (UISC in [Consonant_Dead, Modifying_Letter] or UGC == Po)
return (UISC in [Consonant_Dead, Modifying_Letter] or
(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
(UGC == Po and not U in [0x104B, 0x104E, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
False # SPEC-DRAFT-OUTDATED! U == 0x002D
)
def is_BASE_NUM(U, UISC, UGC):
@ -197,7 +200,11 @@ def is_CONS_SUB(U, UISC, UGC):
def is_CONS_WITH_STACKER(U, UISC, UGC):
return UISC == Consonant_With_Stacker
def is_HALANT(U, UISC, UGC):
return UISC in [Virama, Invisible_Stacker]
return UISC in [Virama, Invisible_Stacker] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
# https://github.com/harfbuzz/harfbuzz/issues/1102
# https://github.com/harfbuzz/harfbuzz/issues/1379
return U in [0x11046, 0x1134D]
def is_HALANT_NUM(U, UISC, UGC):
return UISC == Number_Joiner
def is_ZWNJ(U, UISC, UGC):
@ -248,6 +255,7 @@ use_mapping = {
'SUB': is_CONS_SUB,
'CS': is_CONS_WITH_STACKER,
'H': is_HALANT,
'HVM': is_HALANT_OR_VOWEL_MODIFIER,
'HN': is_HALANT_NUM,
'ZWNJ': is_ZWNJ,
'ZWJ': is_ZWJ,
@ -281,8 +289,8 @@ use_positions = {
'V': {
'Abv': [Top, Top_And_Bottom, Top_And_Bottom_And_Right, Top_And_Right],
'Blw': [Bottom, Overstruck, Bottom_And_Right],
'Pst': [Right],
'Pre': [Left, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
'Pst': [Right, Top_And_Left, Top_And_Left_And_Right, Left_And_Right],
'Pre': [Left],
},
'VM': {
'Abv': [Top],
@ -295,6 +303,7 @@ use_positions = {
'Blw': [Bottom],
},
'H': None,
'HVM': None,
'B': None,
'FM': None,
'SUB': None,
@ -307,11 +316,27 @@ def map_to_use(data):
# Resolve Indic_Syllabic_Category
# TODO: These don't have UISC assigned in Unicode 8.0, but
# have UIPC
if U == 0x17DD: UISC = Vowel_Dependent
# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
# Tibetan:
# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark
# Overrides to allow NFC order matching syllable
# https://github.com/harfbuzz/harfbuzz/issues/1012
if UBlock == 'Tibetan' and is_VOWEL (U, UISC, UGC):
if UIPC == Top:
UIPC = Bottom
# TODO: https://github.com/harfbuzz/harfbuzz/pull/982
# also https://github.com/harfbuzz/harfbuzz/issues/1012
if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC):
if UIPC == Top:
UIPC = Bottom
elif UIPC == Bottom:
UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/627
if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
@ -320,51 +345,33 @@ def map_to_use(data):
if U == 0x1CED: UISC = Tone_Mark
# TODO: https://github.com/harfbuzz/harfbuzz/issues/525
if U == 0x1A7F: UISC = Consonant_Final; UIPC = Bottom
# TODO: https://github.com/harfbuzz/harfbuzz/pull/609
if U == 0x20F0: UISC = Cantillation_Mark; UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/626
if U == 0xA8B4: UISC = Consonant_Medial
if U == 0x1A7F: UISC = Consonant_Final
# TODO: https://github.com/harfbuzz/harfbuzz/issues/1105
if U == 0x11134: UISC = Gemination_Mark
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1399
if U == 0x111C9: UISC = Consonant_Final
values = [k for k,v in items if v(U,UISC,UGC)]
assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
USE = values[0]
# Resolve Indic_Positional_Category
# TODO: Not in Unicode 8.0 yet, but in spec.
if U == 0x1B6C: UIPC = Bottom
# TODO: These should die, but have UIPC in Unicode 8.0
# TODO: These should die, but have UIPC in Unicode 12.0
if U in [0x953, 0x954]: UIPC = Not_Applicable
# TODO: In USE's override list but not in Unicode 11.0
# TODO: In USE's override list but not in Unicode 12.0
if U == 0x103C: UIPC = Left
# TODO: These are not in USE's override list that we have, nor are they in Unicode 11.0
# TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0
if 0xA926 <= U <= 0xA92A: UIPC = Top
if U == 0x111CA: UIPC = Bottom
if U == 0x11300: UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
if U == 0x11302: UIPC = Top
if U == 0x1133C: UIPC = Bottom
if U == 0x1171E: UIPC = Left # Correct?!
if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
# and https://github.com/harfbuzz/harfbuzz/issues/1631
if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
if U == 0x1171E: UIPC = Left
if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
# https://github.com/roozbehp/unicode-data/issues/8
if U == 0x0A51: UIPC = Bottom
# TODO: https://github.com/harfbuzz/harfbuzz/pull/982
if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC):
if UIPC == Top:
UIPC = Bottom
elif UIPC == Bottom:
UIPC = Top
assert (UIPC in [Not_Applicable, Visual_Order_Left] or
USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
@ -432,6 +439,8 @@ num = 0
offset = 0
starts = []
ends = []
print ('#pragma GCC diagnostic push')
print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
for k,v in sorted(use_mapping.items()):
if k in use_positions and use_positions[k]: continue
print ("#define %s USE_%s /* %s */" % (k, k, v.__name__[3:]))
@ -440,6 +449,7 @@ for k,v in sorted(use_positions.items()):
for suf in v.keys():
tag = k + suf
print ("#define %s USE_%s" % (tag, tag))
print ('#pragma GCC diagnostic pop')
print ("")
print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {")
for u in uu:

223
src/gen-vowel-constraints.py Executable file
View File

@ -0,0 +1,223 @@
#!/usr/bin/python
"""Generator of the function to prohibit certain vowel sequences.
It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted
circles into sequences prohibited by the USE script development spec.
This function should be used as the ``preprocess_text`` of an
``hb_ot_complex_shaper_t``.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import collections
try:
from HTMLParser import HTMLParser
def write (s):
print (s.encode ('utf-8'), end='')
except ImportError:
from html.parser import HTMLParser
def write (s):
sys.stdout.flush ()
sys.stdout.buffer.write (s.encode ('utf-8'))
import itertools
import io
import sys
if len (sys.argv) != 3:
print ('usage: ./gen-vowel-constraints.py HBIndicVowelConstraints.txt Scripts.txt', file=sys.stderr)
sys.exit (1)
with io.open (sys.argv[2], encoding='utf-8') as f:
scripts_header = [f.readline () for i in range (2)]
scripts = {}
script_order = {}
for line in f:
j = line.find ('#')
if j >= 0:
line = line[:j]
fields = [x.strip () for x in line.split (';')]
if len (fields) == 1:
continue
uu = fields[0].split ('..')
start = int (uu[0], 16)
if len (uu) == 1:
end = start
else:
end = int (uu[1], 16)
script = fields[1]
for u in range (start, end + 1):
scripts[u] = script
if script not in script_order:
script_order[script] = start
class ConstraintSet (object):
"""A set of prohibited code point sequences.
Args:
constraint (List[int]): A prohibited code point sequence.
"""
def __init__ (self, constraint):
# Either a list or a dictionary. As a list of code points, it
# represents a prohibited code point sequence. As a dictionary,
# it represents a set of prohibited sequences, where each item
# represents the set of prohibited sequences starting with the
# key (a code point) concatenated with any of the values
# (ConstraintSets).
self._c = constraint
def add (self, constraint):
"""Add a constraint to this set."""
if not constraint:
return
first = constraint[0]
rest = constraint[1:]
if isinstance (self._c, list):
if constraint == self._c[:len (constraint)]:
self._c = constraint
elif self._c != constraint[:len (self._c)]:
self._c = {self._c[0]: ConstraintSet (self._c[1:])}
if isinstance (self._c, dict):
if first in self._c:
self._c[first].add (rest)
else:
self._c[first] = ConstraintSet (rest)
def _indent (self, depth):
return (' ' * depth).replace (' ', '\t')
def __str__ (self, index=0, depth=4):
s = []
indent = self._indent (depth)
if isinstance (self._c, list):
if len (self._c) == 0:
s.append ('{}matched = true;\n'.format (indent))
elif len (self._c) == 1:
s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or ''))
else:
s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index))
s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), len (self._c)))
for i, cp in enumerate (self._c[1:], start=1):
s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format (
self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
s.append ('{}{{\n'.format (indent))
for i in range (len (self._c)):
s.append ('{}buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
s.append ('{}_output_dotted_circle (buffer);\n'.format (self._indent (depth + 1)))
s.append ('{}}}\n'.format (indent))
else:
s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or ''))
s.append ('{}{{\n'.format (indent))
cases = collections.defaultdict (set)
for first, rest in sorted (self._c.items ()):
cases[rest.__str__ (index + 1, depth + 2)].add (first)
for body, labels in sorted (cases.items (), key=lambda b_ls: sorted (b_ls[1])[0]):
for i, cp in enumerate (sorted (labels)):
if i % 4 == 0:
s.append (self._indent (depth + 1))
else:
s.append (' ')
s.append ('case 0x{:04X}u:{}'.format (cp, '\n' if i % 4 == 3 else ''))
if len (labels) % 4 != 0:
s.append ('\n')
s.append (body)
s.append ('{}break;\n'.format (self._indent (depth + 2)))
s.append ('{}}}\n'.format (indent))
return ''.join (s)
constraints = {}
with io.open (sys.argv[1], encoding='utf-8') as f:
constraints_header = [f.readline ().strip () for i in range (2)]
for line in f:
j = line.find ('#')
if j >= 0:
line = line[:j]
constraint = [int (cp, 16) for cp in line.split (';')[0].split ()]
if not constraint: continue
assert 2 <= len (constraint), 'Prohibited sequence is too short: {}'.format (constraint)
script = scripts[constraint[0]]
if script in constraints:
constraints[script].add (constraint)
else:
constraints[script] = ConstraintSet (constraint)
assert constraints, 'No constraints found'
print ('/* == Start of generated functions == */')
print ('/*')
print (' * The following functions are generated by running:')
print (' *')
print (' * %s use Scripts.txt' % sys.argv[0])
print (' *')
print (' * on files with these headers:')
print (' *')
for line in constraints_header:
print (' * %s' % line.strip ())
print (' *')
for line in scripts_header:
print (' * %s' % line.strip ())
print (' */')
print ()
print ('#include "hb-ot-shape-complex-vowel-constraints.hh"')
print ()
print ('static void')
print ('_output_dotted_circle (hb_buffer_t *buffer)')
print ('{')
print (' hb_glyph_info_t &dottedcircle = buffer->output_glyph (0x25CCu);')
print (' _hb_glyph_info_reset_continuation (&dottedcircle);')
print ('}')
print ()
print ('static void')
print ('_output_with_dotted_circle (hb_buffer_t *buffer)')
print ('{')
print (' _output_dotted_circle (buffer);')
print (' buffer->next_glyph ();')
print ('}')
print ()
print ('void')
print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,')
print ('\t\t\t\t hb_buffer_t *buffer,')
print ('\t\t\t\t hb_font_t *font HB_UNUSED)')
print ('{')
print (' if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
print (' return;')
print ()
print (' /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
print (' * vowel-sequences that look like another vowel. Data for each script')
print (' * collected from the USE script development spec.')
print (' *')
print (' * https://github.com/harfbuzz/harfbuzz/issues/1019')
print (' */')
print (' bool processed = false;')
print (' buffer->clear_output ();')
print (' unsigned int count = buffer->len;')
print (' switch ((unsigned) buffer->props.script)')
print (' {')
for script, constraints in sorted (constraints.items (), key=lambda s_c: script_order[s_c[0]]):
print (' case HB_SCRIPT_{}:'.format (script.upper ()))
print (' for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)')
print (' {')
print ('\tbool matched = false;')
write (str (constraints))
print ('\tbuffer->next_glyph ();')
print ('\tif (matched) _output_with_dotted_circle (buffer);')
print (' }')
print (' processed = true;')
print (' break;')
print ()
print (' default:')
print (' break;')
print (' }')
print (' if (processed)')
print (' {')
print (' if (buffer->idx < count)')
print (' buffer->next_glyph ();')
print (' buffer->swap_buffers ();')
print (' }')
print ('}')
print ()
print ('/* == End of generated functions == */')

126
src/hb-aat-fdsc-table.hh Normal file
View File

@ -0,0 +1,126 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_FDSC_TABLE_HH
#define HB_AAT_FDSC_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-open-type.hh"
/*
* fdsc -- Font descriptors
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html
*/
#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c')
namespace AAT {
struct FontDescriptor
{
bool has_data () const { return tag; }
int cmp (hb_tag_t a) const { return tag.cmp (a); }
float get_value () const { return u.value.to_float (); }
enum non_alphabetic_value_t {
Alphabetic = 0,
Dingbats = 1,
PiCharacters = 2,
Fleurons = 3,
DecorativeBorders = 4,
InternationalSymbols= 5,
MathSymbols = 6
};
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
Tag tag; /* The 4-byte table tag name. */
union {
Fixed value; /* The value for the descriptor tag. */
HBUINT32 nalfType; /* If the tag is `nalf`, see non_alphabetic_value_t */
} u;
public:
DEFINE_SIZE_STATIC (8);
};
struct fdsc
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
enum {
Weight = HB_TAG ('w','g','h','t'),
/* Percent weight relative to regular weight.
* (defaul value: 1.0) */
Width = HB_TAG ('w','d','t','h'),
/* Percent width relative to regular width.
* (default value: 1.0) */
Slant = HB_TAG ('s','l','n','t'),
/* Angle of slant in degrees, where positive
* is clockwise from straight up.
* (default value: 0.0) */
OpticalSize = HB_TAG ('o','p','s','z'),
/* Point size the font was designed for.
* (default value: 12.0) */
NonAlphabetic= HB_TAG ('n','a','l','f')
/* These values are treated as integers,
* not fixed32s. 0 means alphabetic, and greater
* integers mean the font is non-alphabetic (e.g. symbols).
* (default value: 0) */
};
const FontDescriptor &get_descriptor (hb_tag_t style) const
{ return descriptors.lsearch (style); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
descriptors.sanitize (c));
}
protected:
Fixed version; /* Version number of the font descriptors
* table (0x00010000 for the current version). */
LArrayOf<FontDescriptor>
descriptors; /* List of tagged-coordinate pairs style descriptors
* that will be included to characterize this font.
* Each descriptor consists of a <tag, value> pair.
* These pairs are located in the gxFontDescriptor
* array that follows. */
public:
DEFINE_SIZE_ARRAY (8, descriptors);
};
} /* namespace AAT */
#endif /* HB_AAT_FDSC_TABLE_HH */

View File

@ -36,41 +36,57 @@
namespace AAT {
using namespace OT;
struct Anchor
{
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
FWORD xCoordinate;
FWORD yCoordinate;
public:
DEFINE_SIZE_STATIC (4);
};
typedef LArrayOf<Anchor> GlyphAnchors;
struct ankr
{
static const hb_tag_t tableTag = HB_AAT_TAG_ankr;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
inline bool sanitize (hb_sanitize_context_t *c) const
const Anchor &get_anchor (hb_codepoint_t glyph_id,
unsigned int i,
unsigned int num_glyphs) const
{
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
if (!offset)
return Null(Anchor);
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
return anchors[i];
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version == 0 &&
lookupTable.sanitize (c, this) &&
anchors.sanitize (c, this)));
c->check_range (this, anchorData) &&
lookupTable.sanitize (c, this, &(this+anchorData))));
}
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
LOffsetTo<Lookup<HBUINT16> >
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > >
lookupTable; /* Offset to the table's lookup table */
LOffsetTo<LArrayOf<Anchor> >
anchors; /* Offset to the glyph data table */
LNNOffsetTo<HBUINT8>
anchorData; /* Offset to the glyph data table */
public:
DEFINE_SIZE_STATIC (12);

View File

@ -39,7 +39,7 @@ namespace AAT {
struct BaselineTableFormat0Part
{
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
@ -57,7 +57,7 @@ struct BaselineTableFormat0Part
struct BaselineTableFormat1Part
{
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
@ -75,7 +75,7 @@ struct BaselineTableFormat1Part
struct BaselineTableFormat2Part
{
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
@ -98,7 +98,7 @@ struct BaselineTableFormat2Part
struct BaselineTableFormat3Part
{
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && lookupTable.sanitize (c));
@ -116,15 +116,16 @@ struct BaselineTableFormat3Part
struct bsln
{
static const hb_tag_t tableTag = HB_AAT_TAG_bsln;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
return_trace (false);
switch (format) {
switch (format)
{
case 0: return_trace (parts.format0.sanitize (c));
case 1: return_trace (parts.format1.sanitize (c));
case 2: return_trace (parts.format2.sanitize (c));

View File

@ -28,6 +28,7 @@
#define HB_AAT_LAYOUT_COMMON_HH
#include "hb-aat-layout.hh"
#include "hb-open-type.hh"
namespace AAT {
@ -35,111 +36,6 @@ namespace AAT {
using namespace OT;
/*
* Binary Searching Tables
*/
struct BinSearchHeader
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
* that is less than or equal to the value of nUnits. */
HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
* or equal to the value of nUnits. */
HBUINT16 rangeShift; /* The value of unitSize times the difference of the
* value of nUnits minus the largest power of 2 less
* than or equal to the value of nUnits. */
public:
DEFINE_SIZE_STATIC (10);
};
template <typename Type>
struct BinSearchArrayOf
{
inline const Type& operator [] (unsigned int i) const
{
if (unlikely (i >= header.nUnits)) return Null(Type);
return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
}
inline Type& operator [] (unsigned int i)
{
return StructAtOffset<Type> (&bytesZ, i * header.unitSize);
}
inline unsigned int get_size (void) const
{ return header.static_size + header.nUnits * header.unitSize; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
/* Note: for structs that do not reference other structs,
* we do not need to call their sanitize() as we already did
* a bound check on the aggregate array size. We just include
* a small unreachable expression to make sure the structs
* pointed to do have a simple sanitize(), ie. they do not
* reference other structs via offsets.
*/
(void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
unsigned int count = header.nUnits;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(*this)[i].sanitize (c, base)))
return_trace (false);
return_trace (true);
}
template <typename T>
inline const Type *bsearch (const T &key) const
{
unsigned int size = header.unitSize;
int min = 0, max = (int) header.nUnits - 1;
while (min <= max)
{
int mid = (min + max) / 2;
const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
int c = p->cmp (key);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
return p;
}
return nullptr;
}
private:
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (header.sanitize (c) &&
Type::static_size >= header.unitSize &&
c->check_array (bytesZ.arrayZ, header.nUnits, header.unitSize));
}
protected:
BinSearchHeader header;
UnsizedArrayOf<HBUINT8> bytesZ;
public:
DEFINE_SIZE_ARRAY (10, bytesZ);
};
/*
* Lookup Table
*/
@ -152,39 +48,50 @@ struct LookupFormat0
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
if (unlikely (glyph_id >= num_glyphs)) return nullptr;
return &arrayZ[glyph_id];
}
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
}
protected:
HBUINT16 format; /* Format identifier--format = 0 */
UnsizedArrayOf<T>
arrayZ; /* Array of lookup values, indexed by glyph index. */
public:
DEFINE_SIZE_ARRAY (2, arrayZ);
DEFINE_SIZE_UNBOUNDED (2);
};
template <typename T>
struct LookupSegmentSingle
{
inline int cmp (hb_codepoint_t g) const {
return g < first ? -1 : g <= last ? 0 : +1 ;
}
static constexpr unsigned TerminationWordCount = 2u;
inline bool sanitize (hb_sanitize_context_t *c) const
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1 ; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c, base));
}
GlyphID last; /* Last GlyphID in this segment */
GlyphID first; /* First GlyphID in this segment */
@ -199,21 +106,26 @@ struct LookupFormat2
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
return v ? &v->value : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
BinSearchArrayOf<LookupSegmentSingle<T> >
VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
@ -224,26 +136,35 @@ struct LookupFormat2
template <typename T>
struct LookupSegmentArray
{
inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
static constexpr unsigned TerminationWordCount = 2u;
const T* get_value (hb_codepoint_t glyph_id, const void *base) const
{
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
}
inline int cmp (hb_codepoint_t g) const {
return g < first ? -1 : g <= last ? 0 : +1 ;
}
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1));
}
template <typename T2>
bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1, user_data));
}
GlyphID last; /* Last GlyphID in this segment */
GlyphID first; /* First GlyphID in this segment */
OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
NNOffsetTo<UnsizedArrayOf<T> >
valuesZ; /* A 16-bit offset from the start of
* the table to the data. */
public:
@ -256,21 +177,26 @@ struct LookupFormat4
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
return v ? v->get_value (glyph_id, this) : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, this));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, this, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
BinSearchArrayOf<LookupSegmentArray<T> >
HBUINT16 format; /* Format identifier--format = 4 */
VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
segments; /* The actual segments. These must already be sorted,
* according to the first word in each one (the last
* glyph in each segment). */
@ -281,18 +207,25 @@ struct LookupFormat4
template <typename T>
struct LookupSingle
{
inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
static constexpr unsigned TerminationWordCount = 1u;
inline bool sanitize (hb_sanitize_context_t *c) const
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c, base));
}
GlyphID glyph; /* Last GlyphID */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
DEFINE_SIZE_STATIC (2 + T::static_size);
};
template <typename T>
@ -301,21 +234,26 @@ struct LookupFormat6
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSingle<T> *v = entries.bsearch (glyph_id);
return v ? &v->value : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (entries.sanitize (c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (entries.sanitize (c, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 6 */
BinSearchArrayOf<LookupSingle<T> >
VarSizedBinSearchArrayOf<LookupSingle<T> >
entries; /* The actual entries, sorted by glyph index. */
public:
DEFINE_SIZE_ARRAY (8, entries);
@ -327,19 +265,25 @@ struct LookupFormat8
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
const T* get_value (hb_codepoint_t glyph_id) const
{
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
&valueArrayZ[glyph_id - firstGlyph] : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
}
protected:
HBUINT16 format; /* Format identifier--format = 6 */
HBUINT16 format; /* Format identifier--format = 8 */
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
@ -350,10 +294,52 @@ struct LookupFormat8
DEFINE_SIZE_ARRAY (6, valueArrayZ);
};
template <typename T>
struct LookupFormat10
{
friend struct Lookup<T>;
private:
const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
{
if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
return Null(T);
const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
unsigned int v = 0;
unsigned int count = valueSize;
for (unsigned int i = 0; i < count; i++)
v = (v << 8) | *p++;
return v;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
valueSize <= 4 &&
valueArrayZ.sanitize (c, glyphCount * valueSize));
}
protected:
HBUINT16 format; /* Format identifier--format = 8 */
HBUINT16 valueSize; /* Byte size of each value. */
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<HBUINT8>
valueArrayZ; /* The lookup values (indexed by the glyph index
* minus the value of firstGlyph). */
public:
DEFINE_SIZE_ARRAY (8, valueArrayZ);
};
template <typename T>
struct Lookup
{
inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
case 0: return u.format0.get_value (glyph_id, num_glyphs);
@ -365,7 +351,26 @@ struct Lookup
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
/* Format 10 cannot return a pointer. */
case 10: return u.format10.get_value_or_null (glyph_id);
default:
const T *v = get_value (glyph_id, num_glyphs);
return v ? *v : Null(T);
}
}
typename T::type get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
unsigned int outOfRange) const
{
const T *v = get_value (glyph_id, num_glyphs);
return v ? *v : outOfRange;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
@ -375,6 +380,21 @@ struct Lookup
case 4: return_trace (u.format4.sanitize (c));
case 6: return_trace (u.format6.sanitize (c));
case 8: return_trace (u.format8.sanitize (c));
case 10: return_trace (u.format10.sanitize (c));
default:return_trace (true);
}
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c, base));
case 2: return_trace (u.format2.sanitize (c, base));
case 4: return_trace (u.format4.sanitize (c, base));
case 6: return_trace (u.format6.sanitize (c, base));
case 8: return_trace (u.format8.sanitize (c, base));
case 10: return_trace (false); /* We don't support format10 here currently. */
default:return_trace (true);
}
}
@ -387,26 +407,45 @@ struct Lookup
LookupFormat4<T> format4;
LookupFormat6<T> format6;
LookupFormat8<T> format8;
LookupFormat10<T> format10;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
* special NULL objects for Lookup<> objects, but since it's template our macros
* don't work. So we have to hand-code them here. UGLY. */
} /* Close namespace. */
/* Ugly hand-coded null objects for template Lookup<> :(. */
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
template <typename T>
struct Null<AAT::Lookup<T> > {
static AAT::Lookup<T> const & get_null ()
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
};
namespace AAT {
enum { DELETED_GLYPH = 0xFFFF };
/*
* Extended State Table
* (Extended) State Table
*/
template <typename T>
struct Entry
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
/* Note, we don't recurse-sanitize data because we don't access it.
* That said, in our DEFINE_SIZE_STATIC we access T::static_size,
* which ensures that data has a simple sanitize(). To be determined
* if I need to remove that as well. */
* if I need to remove that as well.
*
* HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
* assertion wouldn't be checked, hence the line below. */
static_assert (T::static_size, "");
return_trace (c->check_struct (this));
}
@ -423,7 +462,7 @@ struct Entry
template <>
struct Entry<void>
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
@ -436,9 +475,13 @@ struct Entry<void>
DEFINE_SIZE_STATIC (4);
};
template <typename Extra>
template <typename Types, typename Extra>
struct StateTable
{
typedef typename Types::HBUINT HBUINT;
typedef typename Types::HBUSHORT HBUSHORT;
typedef typename Types::ClassTypeNarrow ClassType;
enum State
{
STATE_START_OF_TEXT = 0,
@ -452,63 +495,125 @@ struct StateTable
CLASS_END_OF_LINE = 3,
};
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
int new_state (unsigned int newState) const
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
return (this+classTable).get_class (glyph_id, num_glyphs, 1);
}
inline const Entry<Extra> *get_entries () const
{
return (this+entryTable).arrayZ;
}
const Entry<Extra> *get_entries () const
{ return (this+entryTable).arrayZ; }
inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses)) return nullptr;
if (unlikely (klass >= nClasses))
klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int entry = states[state * nClasses + klass];
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
return &entries[entry];
return entries[entry];
}
inline bool sanitize (hb_sanitize_context_t *c,
unsigned int *num_entries_out = nullptr) const
bool sanitize (hb_sanitize_context_t *c,
unsigned int *num_entries_out = nullptr) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) &&
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
classTable.sanitize (c, this)))) return_trace (false);
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int num_states = 1;
unsigned int num_classes = nClasses;
if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
return_trace (false);
unsigned int row_stride = num_classes * states[0].static_size;
/* Apple 'kern' table has this peculiarity:
*
* "Because the stateTableOffset in the state table header is (strictly
* speaking) redundant, some 'kern' tables use it to record an initial
* state where that should not be StartOfText. To determine if this is
* done, calculate what the stateTableOffset should be. If it's different
* from the actual stateTableOffset, use it as the initial state."
*
* We implement this by calling the initial state zero, but allow *negative*
* states if the start state indeed was not the first state. Since the code
* is shared, this will also apply to 'mort' table. The 'kerx' / 'morx'
* tables are not affected since those address states by index, not offset.
*/
int min_state = 0;
int max_state = 0;
unsigned int num_entries = 0;
unsigned int state = 0;
int state_pos = 0;
int state_neg = 0;
unsigned int entry = 0;
while (state < num_states)
while (min_state < state_neg || state_pos <= max_state)
{
if (unlikely (!c->check_array (states,
num_states,
states[0].static_size * nClasses)))
return_trace (false);
{ /* Sweep new states. */
const HBUINT16 *stop = &states[num_states * nClasses];
for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
num_entries = MAX<unsigned int> (num_entries, *p + 1);
state = num_states;
if (min_state < state_neg)
{
/* Negative states. */
if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
return_trace (false);
if (unlikely (!c->check_range (&states[min_state * num_classes],
-min_state,
row_stride)))
return_trace (false);
if ((c->max_ops -= state_neg - min_state) <= 0)
return_trace (false);
{ /* Sweep new states. */
const HBUSHORT *stop = &states[min_state * num_classes];
if (unlikely (stop > states))
return_trace (false);
for (const HBUSHORT *p = states; stop < p; p--)
num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
state_neg = min_state;
}
}
if (state_pos <= max_state)
{
/* Positive states. */
if (unlikely (!c->check_range (states,
max_state + 1,
row_stride)))
return_trace (false);
if ((c->max_ops -= max_state - state_pos + 1) <= 0)
return_trace (false);
{ /* Sweep new states. */
if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
return_trace (false);
const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
if (unlikely (stop < states))
return_trace (false);
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
num_entries = MAX<unsigned int> (num_entries, *p + 1);
state_pos = max_state + 1;
}
}
if (unlikely (!c->check_array (entries, num_entries)))
return_trace (false);
if ((c->max_ops -= num_entries - entry) <= 0)
return_trace (false);
{ /* Sweep new entries. */
const Entry<Extra> *stop = &entries[num_entries];
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
num_states = MAX<unsigned int> (num_states, p->newState + 1);
{
int newState = new_state (p->newState);
min_state = MIN (min_state, newState);
max_state = MAX (max_state, newState);
}
entry = num_entries;
}
}
@ -520,133 +625,213 @@ struct StateTable
}
protected:
HBUINT32 nClasses; /* Number of classes, which is the number of indices
HBUINT nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
LOffsetTo<Lookup<HBUINT16>, false>
NNOffsetTo<ClassType, HBUINT>
classTable; /* Offset to the class table. */
LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
stateArrayTable;/* Offset to the state array. */
LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT>
entryTable; /* Offset to the entry array. */
public:
DEFINE_SIZE_STATIC (16);
DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
};
template <typename EntryData>
template <typename HBUCHAR>
struct ClassTable
{
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
{
unsigned int i = glyph_id - firstGlyph;
return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
}
unsigned int get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs HB_UNUSED,
unsigned int outOfRange) const
{
return get_class (glyph_id, outOfRange);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && classArray.sanitize (c));
}
protected:
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
* firstGlyph). */
public:
DEFINE_SIZE_ARRAY (4, classArray);
};
struct ObsoleteTypes
{
static constexpr bool extended = false;
typedef HBUINT16 HBUINT;
typedef HBUINT8 HBUSHORT;
typedef ClassTable<HBUINT8> ClassTypeNarrow;
typedef ClassTable<HBUINT16> ClassTypeWide;
template <typename T>
static unsigned int offsetToIndex (unsigned int offset,
const void *base,
const T *array)
{
return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
}
template <typename T>
static unsigned int byteOffsetToIndex (unsigned int offset,
const void *base,
const T *array)
{
return offsetToIndex (offset, base, array);
}
template <typename T>
static unsigned int wordOffsetToIndex (unsigned int offset,
const void *base,
const T *array)
{
return offsetToIndex (2 * offset, base, array);
}
};
struct ExtendedTypes
{
static constexpr bool extended = true;
typedef HBUINT32 HBUINT;
typedef HBUINT16 HBUSHORT;
typedef Lookup<HBUINT16> ClassTypeNarrow;
typedef Lookup<HBUINT16> ClassTypeWide;
template <typename T>
static unsigned int offsetToIndex (unsigned int offset,
const void *base HB_UNUSED,
const T *array HB_UNUSED)
{
return offset;
}
template <typename T>
static unsigned int byteOffsetToIndex (unsigned int offset,
const void *base HB_UNUSED,
const T *array HB_UNUSED)
{
return offset / 2;
}
template <typename T>
static unsigned int wordOffsetToIndex (unsigned int offset,
const void *base HB_UNUSED,
const T *array HB_UNUSED)
{
return offset;
}
};
template <typename Types, typename EntryData>
struct StateTableDriver
{
inline StateTableDriver (const StateTable<EntryData> &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
StateTableDriver (const StateTable<Types, EntryData> &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
buffer (buffer_),
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t>
inline void drive (context_t *c)
void drive (context_t *c)
{
hb_glyph_info_t *info = buffer->info;
if (!c->in_place)
buffer->clear_output ();
unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
bool last_was_dont_advance = false;
for (buffer->idx = 0;;)
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
for (buffer->idx = 0; buffer->successful;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
(unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry))
break;
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const Entry<EntryData> &entry = machine.get_entry (state, klass);
/* Unsafe-to-break before this if not in state 0, as things might
* go differently if we start from state 0 here. */
if (state && buffer->idx)
* go differently if we start from state 0 here.
*
* Ugh. The indexing here is ugly... */
if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
{
/* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */
if (c->is_actionable (this, entry) ||
!(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
entry->flags == context_t::DontAdvance))
buffer->unsafe_to_break (buffer->idx - 1, buffer->idx + 1);
!(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
entry.flags == context_t::DontAdvance))
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
}
/* Unsafe-to-break if end-of-text would kick in here. */
if (buffer->idx + 2 <= buffer->len)
{
const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
if (c->is_actionable (this, end_entry))
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
}
if (unlikely (!c->transition (this, entry)))
break;
c->transition (this, entry);
last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
state = entry->newState;
state = machine.new_state (entry.newState);
DEBUG_MSG (APPLY, nullptr, "s%d", state);
if (buffer->idx == buffer->len)
break;
break;
if (!last_was_dont_advance)
buffer->next_glyph ();
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
buffer->next_glyph ();
}
if (!c->in_place)
{
for (; buffer->idx < buffer->len;)
buffer->next_glyph ();
for (; buffer->successful && buffer->idx < buffer->len;)
buffer->next_glyph ();
buffer->swap_buffers ();
}
}
public:
const StateTable<EntryData> &machine;
const StateTable<Types, EntryData> &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};
struct ankr;
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
inline const char *get_name (void) { return "APPLY"; }
const char *get_name () { return "APPLY"; }
template <typename T>
inline return_t dispatch (const T &obj) { return obj.apply (this); }
static return_t default_return_value (void) { return false; }
return_t dispatch (const T &obj) { return obj.apply (this); }
static return_t default_return_value () { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
const hb_ot_shape_plan_t *plan;
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
unsigned int debug_depth;
inline hb_aat_apply_context_t (hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *table) :
font (font_), face (font->face), buffer (buffer_),
sanitizer (), lookup_index (0), debug_depth (0)
{
sanitizer.init (table);
sanitizer.set_num_glyphs (face->get_num_glyphs ());
sanitizer.start_processing ();
}
HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
inline void set_lookup_index (unsigned int i) { lookup_index = i; }
HB_INTERNAL ~hb_aat_apply_context_t ();
inline ~hb_aat_apply_context_t (void)
{
sanitizer.end_processing ();
}
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
};

View File

@ -39,7 +39,28 @@ namespace AAT {
struct SettingName
{
inline bool sanitize (hb_sanitize_context_t *c) const
friend struct FeatureName;
int cmp (hb_aat_layout_feature_selector_t key) const
{ return (int) key - (int) setting; }
hb_aat_layout_feature_selector_t get_selector () const
{ return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
void get_info (hb_aat_layout_feature_selector_info_t *s,
hb_aat_layout_feature_selector_t default_selector) const
{
s->name_id = nameIndex;
s->enable = (hb_aat_layout_feature_selector_t) (unsigned int) setting;
s->disable = default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID ?
(hb_aat_layout_feature_selector_t) (s->enable + 1) :
default_selector;
s->reserved = 0;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
@ -51,35 +72,75 @@ struct SettingName
public:
DEFINE_SIZE_STATIC (4);
};
DECLARE_NULL_NAMESPACE_BYTES (AAT, SettingName);
struct feat;
struct FeatureName
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(base+settingTable).sanitize (c, nSettings)));
}
int cmp (hb_aat_layout_feature_type_t key) const
{ return (int) key - (int) feature; }
enum {
Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */
NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in
Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */
NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in
* the setting name array for this feature should
* be taken as the default for the feature
* (if one is required). If set, then bits 0-15 of this
* featureFlags field contain the index of the setting
* which is to be taken as the default. */
IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits
IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits
* indicate the index of the setting in the setting name
* array for this feature which should be taken
* as the default. */
};
unsigned int get_selector_infos (unsigned int start_offset,
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *pdefault_index, /* OUT. May be NULL. */
const void *base) const
{
hb_array_t< const SettingName> settings_table = (base+settingTableZ).as_array (nSettings);
static_assert (Index::NOT_FOUND_INDEX == HB_AAT_LAYOUT_NO_SELECTOR_INDEX, "");
hb_aat_layout_feature_selector_t default_selector = HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID;
unsigned int default_index = Index::NOT_FOUND_INDEX;
if (featureFlags & Exclusive)
{
default_index = (featureFlags & NotDefault) ? featureFlags & IndexMask : 0;
default_selector = settings_table[default_index].get_selector ();
}
if (pdefault_index)
*pdefault_index = default_index;
if (selectors_count)
{
hb_array_t<const SettingName> arr = settings_table.sub_array (start_offset, selectors_count);
for (unsigned int i = 0; i < arr.length; i++)
settings_table[start_offset + i].get_info (&selectors[i], default_selector);
}
return settings_table.length;
}
hb_aat_layout_feature_type_t get_feature_type () const
{ return (hb_aat_layout_feature_type_t) (unsigned int) feature; }
hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(base+settingTableZ).sanitize (c, nSettings)));
}
protected:
HBUINT16 feature; /* Feature type. */
HBUINT16 nSettings; /* The number of records in the setting name array. */
LOffsetTo<UnsizedArrayOf<SettingName>, false>
settingTable; /* Offset in bytes from the beginning of this table to
settingTableZ; /* Offset in bytes from the beginning of this table to
* this feature's setting name array. The actual type of
* record this offset refers to will depend on the
* exclusivity value, as described below. */
@ -93,13 +154,49 @@ struct FeatureName
struct feat
{
static const hb_tag_t tableTag = HB_AAT_TAG_feat;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
inline bool sanitize (hb_sanitize_context_t *c) const
bool has_data () const { return version.to_int (); }
unsigned int get_feature_types (unsigned int start_offset,
unsigned int *count,
hb_aat_layout_feature_type_t *features) const
{
unsigned int feature_count = featureNameCount;
if (count && *count)
{
unsigned int len = MIN (feature_count - start_offset, *count);
for (unsigned int i = 0; i < len; i++)
features[i] = namesZ[i + start_offset].get_feature_type ();
*count = len;
}
return featureNameCount;
}
const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
{
return namesZ.bsearch (featureNameCount, feature_type);
}
hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
{ return get_feature (feature).get_feature_name_id (); }
unsigned int get_selector_infos (hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */) const
{
return get_feature (feature_type).get_selector_infos (start_offset, selectors_count, selectors,
default_index, this);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
names.sanitize (c, featureNameCount, this)));
version.major == 1 &&
namesZ.sanitize (c, featureNameCount, this)));
}
protected:
@ -109,8 +206,8 @@ struct feat
/* The number of entries in the feature name array. */
HBUINT16 reserved1; /* Reserved (set to zero). */
HBUINT32 reserved2; /* Reserved (set to zero). */
UnsizedArrayOf<FeatureName>
names; /* The feature name array. */
SortedUnsizedArrayOf<FeatureName>
namesZ; /* The feature name array. */
public:
DEFINE_SIZE_STATIC (24);
};

View File

@ -0,0 +1,417 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_JUST_TABLE_HH
#define HB_AAT_LAYOUT_JUST_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
#include "hb-aat-layout-morx-table.hh"
/*
* just -- Justification
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html
*/
#define HB_AAT_TAG_just HB_TAG('j','u','s','t')
namespace AAT {
using namespace OT;
struct ActionSubrecordHeader
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
HBUINT16 actionClass; /* The JustClass value associated with this
* ActionSubrecord. */
HBUINT16 actionType; /* The type of postcompensation action. */
HBUINT16 actionLength; /* Length of this ActionSubrecord record, which
* must be a multiple of 4. */
public:
DEFINE_SIZE_STATIC (6);
};
struct DecompositionAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
ActionSubrecordHeader
header;
Fixed lowerLimit; /* If the distance factor is less than this value,
* then the ligature is decomposed. */
Fixed upperLimit; /* If the distance factor is greater than this value,
* then the ligature is decomposed. */
HBUINT16 order; /* Numerical order in which this ligature will
* be decomposed; you may want infrequent ligatures
* to decompose before more frequent ones. The ligatures
* on the line of text will decompose in increasing
* value of this field. */
ArrayOf<HBUINT16>
decomposedglyphs;
/* Number of 16-bit glyph indexes that follow;
* the ligature will be decomposed into these glyphs.
*
* Array of decomposed glyphs. */
public:
DEFINE_SIZE_ARRAY (18, decomposedglyphs);
};
struct UnconditionalAddGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
ActionSubrecordHeader
header;
GlyphID addGlyph; /* Glyph that should be added if the distance factor
* is growing. */
public:
DEFINE_SIZE_STATIC (8);
};
struct ConditionalAddGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
ActionSubrecordHeader
header;
Fixed substThreshold; /* Distance growth factor (in ems) at which
* this glyph is replaced and the growth factor
* recalculated. */
GlyphID addGlyph; /* Glyph to be added as kashida. If this value is
* 0xFFFF, no extra glyph will be added. Note that
* generally when a glyph is added, justification
* will need to be redone. */
GlyphID substGlyph; /* Glyph to be substituted for this glyph if the
* growth factor equals or exceeds the value of
* substThreshold. */
public:
DEFINE_SIZE_STATIC (14);
};
struct DuctileGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
ActionSubrecordHeader
header;
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
* This would normally be 0x64756374 ('duct'),
* but you may use any axis the font contains. */
Fixed minimumLimit; /* The lowest value for the ductility axis tha
* still yields an acceptable appearance. Normally
* this will be 1.0. */
Fixed noStretchValue; /* This is the default value that corresponds to
* no change in appearance. Normally, this will
* be 1.0. */
Fixed maximumLimit; /* The highest value for the ductility axis that
* still yields an acceptable appearance. */
public:
DEFINE_SIZE_STATIC (22);
};
struct RepeatedAddGlyphAction
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
ActionSubrecordHeader
header;
HBUINT16 flags; /* Currently unused; set to 0. */
GlyphID glyph; /* Glyph that should be added if the distance factor
* is growing. */
public:
DEFINE_SIZE_STATIC (10);
};
struct ActionSubrecord
{
unsigned int get_length () const { return u.header.actionLength; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
switch (u.header.actionType)
{
case 0: return_trace (u.decompositionAction.sanitize (c));
case 1: return_trace (u.unconditionalAddGlyphAction.sanitize (c));
case 2: return_trace (u.conditionalAddGlyphAction.sanitize (c));
// case 3: return_trace (u.stretchGlyphAction.sanitize (c));
case 4: return_trace (u.decompositionAction.sanitize (c));
case 5: return_trace (u.decompositionAction.sanitize (c));
default: return_trace (true);
}
}
protected:
union {
ActionSubrecordHeader header;
DecompositionAction decompositionAction;
UnconditionalAddGlyphAction unconditionalAddGlyphAction;
ConditionalAddGlyphAction conditionalAddGlyphAction;
/* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */
DuctileGlyphAction ductileGlyphAction;
RepeatedAddGlyphAction repeatedAddGlyphAction;
} u; /* Data. The format of this data depends on
* the value of the actionType field. */
public:
DEFINE_SIZE_UNION (6, header);
};
struct PostcompensationActionChain
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
unsigned int offset = min_size;
for (unsigned int i = 0; i < count; i++)
{
const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset);
if (unlikely (!subrecord.sanitize (c))) return_trace (false);
offset += subrecord.get_length ();
}
return_trace (true);
}
protected:
HBUINT32 count;
public:
DEFINE_SIZE_STATIC (4);
};
struct JustWidthDeltaEntry
{
enum Flags
{
Reserved1 =0xE000,/* Reserved. You should set these bits to zero. */
UnlimiteGap =0x1000,/* The glyph can take unlimited gap. When this
* glyph participates in the justification process,
* it and any other glyphs on the line having this
* bit set absorb all the remaining gap. */
Reserved2 =0x0FF0,/* Reserved. You should set these bits to zero. */
Priority =0x000F /* The justification priority of the glyph. */
};
enum Priority
{
Kashida = 0, /* Kashida priority. This is the highest priority
* during justification. */
Whitespace = 1, /* Whitespace priority. Any whitespace glyphs (as
* identified in the glyph properties table) will
* get this priority. */
InterCharacter = 2, /* Inter-character priority. Give this to any
* remaining glyphs. */
NullPriority = 3 /* Null priority. You should set this priority for
* glyphs that only participate in justification
* after the above priorities. Normally all glyphs
* have one of the previous three values. If you
* don't want a glyph to participate in justification,
* and you don't want to set its factors to zero,
* you may instead assign it to the null priority. */
};
protected:
Fixed beforeGrowLimit;/* The ratio by which the advance width of the
* glyph is permitted to grow on the left or top side. */
Fixed beforeShrinkLimit;
/* The ratio by which the advance width of the
* glyph is permitted to shrink on the left or top side. */
Fixed afterGrowLimit; /* The ratio by which the advance width of the glyph
* is permitted to shrink on the left or top side. */
Fixed afterShrinkLimit;
/* The ratio by which the advance width of the glyph
* is at most permitted to shrink on the right or
* bottom side. */
HBUINT16 growFlags; /* Flags controlling the grow case. */
HBUINT16 shrinkFlags; /* Flags controlling the shrink case. */
public:
DEFINE_SIZE_STATIC (20);
};
struct WidthDeltaPair
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this)));
}
protected:
HBUINT32 justClass; /* The justification category associated
* with the wdRecord field. Only 7 bits of
* this field are used. (The other bits are
* used as padding to guarantee longword
* alignment of the following record). */
JustWidthDeltaEntry
wdRecord; /* The actual width delta record. */
public:
DEFINE_SIZE_STATIC (24);
};
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
struct JustificationCategory
{
typedef void EntryData;
enum Flags
{
SetMark =0x8000,/* If set, make the current glyph the marked
* glyph. */
DontAdvance =0x4000,/* If set, don't advance to the next glyph before
* going to the new state. */
MarkCategory =0x3F80,/* The justification category for the marked
* glyph if nonzero. */
CurrentCategory =0x007F /* The justification category for the current
* glyph if nonzero. */
};
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
morphHeader.sanitize (c) &&
stHeader.sanitize (c)));
}
protected:
ChainSubtable<ObsoleteTypes>
morphHeader; /* Metamorphosis-style subtable header. */
StateTable<ObsoleteTypes, EntryData>
stHeader; /* The justification insertion state table header */
public:
DEFINE_SIZE_STATIC (30);
};
struct JustificationHeader
{
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
justClassTable.sanitize (c, base, base) &&
wdcTable.sanitize (c, base) &&
pcTable.sanitize (c, base) &&
lookupTable.sanitize (c, base)));
}
protected:
OffsetTo<JustificationCategory>
justClassTable; /* Offset to the justification category state table. */
OffsetTo<WidthDeltaCluster>
wdcTable; /* Offset from start of justification table to start
* of the subtable containing the width delta factors
* for the glyphs in your font.
*
* The width delta clusters table. */
OffsetTo<PostcompensationActionChain>
pcTable; /* Offset from start of justification table to start
* of postcompensation subtable (set to zero if none).
*
* The postcompensation subtable, if present in the font. */
Lookup<OffsetTo<WidthDeltaCluster> >
lookupTable; /* Lookup table associating glyphs with width delta
* clusters. See the description of Width Delta Clusters
* table for details on how to interpret the lookup values. */
public:
DEFINE_SIZE_MIN (8);
};
struct just
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
}
protected:
FixedVersion<>version; /* Version of the justification table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the justification table (set to 0). */
OffsetTo<JustificationHeader>
horizData; /* Byte offset from the start of the justification table
* to the header for tables that contain justification
* information for horizontal text.
* If you are not including this information,
* store 0. */
OffsetTo<JustificationHeader>
vertData; /* ditto, vertical */
public:
DEFINE_SIZE_STATIC (10);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH
#define HB_AAT_LAYOUT_LCAR_TABLE_HH
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
/*
* lcar -- Ligature caret
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
*/
#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r')
namespace AAT {
typedef ArrayOf<HBINT16> LigCaretClassEntry;
struct lcar
{
static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph,
font->face->get_num_glyphs ());
const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
if (caret_count)
{
hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
unsigned int count = arr.length;
for (unsigned int i = 0; i < count; ++i)
switch (format)
{
case 0: caret_array[i] = font->em_scale_dir (arr[i], direction); break;
case 1:
hb_position_t x, y;
font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
break;
}
}
return array.len;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
lookup.sanitize (c, this)));
}
protected:
FixedVersion<>version; /* Version number of the ligature caret table */
HBUINT16 format; /* Format of the ligature caret table. */
Lookup<OffsetTo<LigCaretClassEntry> >
lookup; /* data Lookup table associating glyphs */
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */

File diff suppressed because it is too large Load Diff

View File

@ -46,29 +46,27 @@ struct TrackTableEntry
{
friend struct TrackData;
inline bool sanitize (hb_sanitize_context_t *c, const void *base,
unsigned int size) const
float get_track_value () const { return track.to_float (); }
int get_value (const void *base, unsigned int index,
unsigned int table_size) const
{ return (base+valuesZ).as_array (table_size)[index]; }
public:
bool sanitize (hb_sanitize_context_t *c, const void *base,
unsigned int table_size) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(valuesZ.sanitize (c, base, size))));
}
private:
inline float get_track_value () const
{
return track.to_float ();
}
inline int get_value (const void *base, unsigned int index) const
{
return (base+valuesZ)[index];
(valuesZ.sanitize (c, base, table_size))));
}
protected:
Fixed track; /* Track value for this record. */
NameID trackNameID; /* The 'name' table index for this track */
OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
NNOffsetTo<UnsizedArrayOf<FWORD> >
valuesZ; /* Offset from start of tracking table to
* per-size tracking values for this track. */
@ -78,15 +76,22 @@ struct TrackTableEntry
struct TrackData
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
float interpolate_at (unsigned int idx,
float target_size,
const TrackTableEntry &trackTableEntry,
const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
sizeTable.sanitize (c, base, nSizes) &&
trackTable.sanitize (c, nTracks, base, nSizes));
unsigned int sizes = nSizes;
hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
return t * trackTableEntry.get_value (base, idx + 1, sizes) +
(1.f - t) * trackTableEntry.get_value (base, idx, sizes);
}
inline float get_tracking (const void *base, float ptem) const
int get_tracking (const void *base, float ptem) const
{
/* CoreText points are CSS pixels (96 per inch),
* NOT typographic points (72 per inch).
@ -94,48 +99,58 @@ struct TrackData
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
*/
float csspx = ptem * 96.f / 72.f;
Fixed fixed_size;
fixed_size.set_float (csspx);
/* XXX Clean this up. Make it work with nSizes==1 and 0. */
unsigned int sizes = nSizes;
/*
* Choose track.
*/
const TrackTableEntry *trackTableEntry = nullptr;
for (unsigned int i = 0; i < sizes; ++i)
// For now we only seek for track entries with zero tracking value
if (trackTable[i].get_track_value () == 0.f)
trackTableEntry = &trackTable[0];
unsigned int count = nTracks;
for (unsigned int i = 0; i < count; i++)
{
/* Note: Seems like the track entries are sorted by values. But the
* spec doesn't explicitly say that. It just mentions it in the example. */
// We couldn't match any, exit
/* For now we only seek for track entries with zero tracking value */
if (trackTable[i].get_track_value () == 0.f)
{
trackTableEntry = &trackTable[i];
break;
}
}
if (!trackTableEntry) return 0.;
/* TODO bfind() */
/*
* Choose size.
*/
unsigned int sizes = nSizes;
if (!sizes) return 0.;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
UnsizedArrayOf<Fixed> size_table = base+sizeTable;
for (size_index = 0; size_index < sizes; ++size_index)
if (size_table[size_index] >= fixed_size)
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= csspx)
break;
// TODO(ebraminio): We don't attempt to extrapolate to larger or
// smaller values for now but we should do, per spec
if (size_index == sizes)
return trackTableEntry->get_value (base, sizes - 1);
if (size_index == 0 || size_table[size_index] == fixed_size)
return trackTableEntry->get_value (base, size_index);
return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
*trackTableEntry, base));
}
float s0 = size_table[size_index - 1].to_float ();
float s1 = size_table[size_index].to_float ();
float t = (csspx - s0) / (s1 - s0);
return (float) t * trackTableEntry->get_value (base, size_index) +
((float) 1.0 - t) * trackTableEntry->get_value (base, size_index - 1);
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
sizeTable.sanitize (c, base, nSizes) &&
trackTable.sanitize (c, nTracks, base, nSizes)));
}
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
LOffsetTo<UnsizedArrayOf<Fixed>, false>
sizeTable; /* Offset to array[nSizes] of size values. */
sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry>
trackTable; /* Array[nTracks] of TrackTableEntry records. */
@ -145,21 +160,16 @@ struct TrackData
struct trak
{
static const hb_tag_t tableTag = HB_AAT_TAG_trak;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
bool has_data () const { return version.to_int (); }
return_trace (unlikely (c->check_struct (this) &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
}
inline bool apply (hb_aat_apply_context_t *c) const
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_mask_t trak_mask = c->plan->trak_mask;
const float ptem = c->font->ptem;
if (unlikely (ptem <= 0.f))
return_trace (false);
@ -168,41 +178,57 @@ struct trak
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
const TrackData &trackData = this+horizData;
float tracking = trackData.get_tracking (this, ptem);
hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
foreach_grapheme (buffer, start, end)
{
buffer->pos[start].x_offset += advance_to_add;
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[end].x_advance += advance_to_add;
buffer->pos[start].x_offset += offset_to_add;
}
}
else
{
const TrackData &trackData = this+vertData;
float tracking = trackData.get_tracking (this, ptem);
hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2);
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
foreach_grapheme (buffer, start, end)
{
buffer->pos[start].y_offset += advance_to_add;
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[end].y_advance += advance_to_add;
buffer->pos[start].y_offset += offset_to_add;
}
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version.major == 1 &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
}
protected:
FixedVersion<> version; /* Version of the tracking table--currently
* 0x00010000u for version 1.0. */
HBUINT16 format; /* Format of the tracking table */
OffsetTo<TrackData> horizData; /* TrackData for horizontal text */
OffsetTo<TrackData> vertData; /* TrackData for vertical text */
HBUINT16 reserved; /* Reserved. Set to 0. */
FixedVersion<>version; /* Version of the tracking table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the tracking table (set to 0). */
OffsetTo<TrackData>
horizData; /* Offset from start of tracking table to TrackData
* for horizontal text (or 0 if none). */
OffsetTo<TrackData>
vertData; /* Offset from start of tracking table to TrackData
* for vertical text (or 0 if none). */
HBUINT16 reserved; /* Reserved. Set to 0. */
public:
DEFINE_SIZE_MIN (12);
DEFINE_SIZE_STATIC (12);
};
} /* namespace AAT */

View File

@ -1,5 +1,6 @@
/*
* Copyright © 2017 Google, Inc.
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
@ -28,54 +29,356 @@
#include "hb-ot-face.hh"
#include "hb-aat-layout.hh"
#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-ankr-table.hh"
#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-feat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-feat-table.hh"
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
#include "hb-aat-ltag-table.hh"
/**
* SECTION:hb-aat-layout
* @title: hb-aat-layout
* @short_description: Apple Advanced Typography Layout
* @include: hb-aat.h
*
* Functions for querying OpenType Layout features in the font face.
**/
/* Table data courtesy of Apple. Converted from mnemonics to integers
* when moving to this file. */
static const hb_aat_feature_mapping_t feature_mappings[] =
{
{HB_TAG ('a','f','r','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG ('c','2','p','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
{HB_TAG ('c','2','s','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
{HB_TAG ('c','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF},
{HB_TAG ('c','a','s','e'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF},
{HB_TAG ('c','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF},
{HB_TAG ('c','p','s','p'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF},
{HB_TAG ('c','s','w','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF},
{HB_TAG ('d','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF},
{HB_TAG ('e','x','p','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('f','r','a','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
{HB_TAG ('f','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('h','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('h','i','s','t'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG ('h','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF},
{HB_TAG ('h','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
{HB_TAG ('h','n','g','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION},
{HB_TAG ('h','o','j','o'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('h','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('i','t','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF},
{HB_TAG ('j','p','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('j','p','7','8'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('j','p','8','3'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('j','p','9','0'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('l','i','g','a'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF},
{HB_TAG ('l','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2},
{HB_TAG ('m','g','r','k'), HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF},
{HB_TAG ('n','l','c','k'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('o','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2},
{HB_TAG ('o','r','d','n'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('p','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('p','c','a','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
{HB_TAG ('p','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
{HB_TAG ('s','m','p','l'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('s','s','0','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF},
{HB_TAG ('s','s','0','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF},
{HB_TAG ('s','s','0','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF},
{HB_TAG ('s','s','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF},
{HB_TAG ('s','s','0','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF},
{HB_TAG ('s','s','0','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF},
{HB_TAG ('s','s','0','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF},
{HB_TAG ('s','s','0','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF},
{HB_TAG ('s','s','0','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF},
{HB_TAG ('s','s','1','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF},
{HB_TAG ('s','s','1','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF},
{HB_TAG ('s','s','1','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF},
{HB_TAG ('s','s','1','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF},
{HB_TAG ('s','s','1','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF},
{HB_TAG ('s','s','1','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF},
{HB_TAG ('s','s','1','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF},
{HB_TAG ('s','s','1','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF},
{HB_TAG ('s','s','1','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF},
{HB_TAG ('s','s','1','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF},
{HB_TAG ('s','s','2','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF},
{HB_TAG ('s','u','b','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','u','p','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
{HB_TAG ('s','w','s','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF},
{HB_TAG ('t','i','t','l'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS},
{HB_TAG ('t','n','a','m'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('t','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
{HB_TAG ('t','r','a','d'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
{HB_TAG ('t','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('u','n','i','c'), HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE, (hb_aat_layout_feature_selector_t) 14, (hb_aat_layout_feature_selector_t) 15},
{HB_TAG ('v','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','e','r','t'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
{HB_TAG ('v','h','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF},
{HB_TAG ('v','p','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
{HB_TAG ('v','r','t','2'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
{HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
};
const hb_aat_feature_mapping_t *
hb_aat_layout_find_feature_mapping (hb_tag_t tag)
{
return (const hb_aat_feature_mapping_t *) bsearch (&tag,
feature_mappings,
ARRAY_LENGTH (feature_mappings),
sizeof (feature_mappings[0]),
hb_aat_feature_mapping_t::cmp);
}
/*
* morx/kerx/trak/ankr
* hb_aat_apply_context_t
*/
static inline const AAT::morx&
_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *blob) :
plan (plan_),
font (font_),
face (font->face),
buffer (buffer_),
sanitizer (),
ankr_table (&Null(AAT::ankr)),
lookup_index (0),
debug_depth (0)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
sanitizer.init (blob);
sanitizer.set_num_glyphs (face->get_num_glyphs ());
sanitizer.start_processing ();
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
}
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
{ sanitizer.end_processing (); }
void
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
{ ankr_table = ankr_table_; }
/*
* mort/morx/kerx/trak
*/
void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map)
{
const AAT::morx& morx = *mapper->face->table.morx;
if (morx.has_data ())
{
if (blob)
*blob = hb_blob_get_empty ();
return Null(AAT::morx);
morx.compile_flags (mapper, map);
return;
}
const AAT::morx& morx = *(hb_ot_face_data (face)->morx.get ());
if (blob)
*blob = hb_ot_face_data (face)->morx.get_blob ();
return morx;
const AAT::mort& mort = *mapper->face->table.mort;
if (mort.has_data ())
{
mort.compile_flags (mapper, map);
return;
}
}
/*
* hb_aat_layout_has_substitution:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t
hb_aat_layout_has_substitution (hb_face_t *face)
{
return face->table.morx->has_data () ||
face->table.mort->has_data ();
}
void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
hb_blob_t *blob;
const AAT::morx& morx = _get_morx (font->face, &blob);
hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
if (morx.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
morx.apply (&c);
return;
}
AAT::hb_aat_apply_context_t c (font, buffer, blob);
morx.apply (&c);
hb_blob_t *mort_blob = font->face->table.mort.get_blob ();
const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
if (mort.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
mort.apply (&c);
return;
}
}
void
hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer)
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
{
#if 0
hb_blob_t *blob;
const AAT::ankr& ankr = _get_ankr (font->face, &blob);
const AAT::kerx& kerx = _get_kerx (font->face, &blob);
const AAT::trak& trak = _get_trak (font->face, &blob);
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++)
if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
AAT::hb_aat_apply_context_t c (font, buffer, blob);
kerx.apply (&c, &ankr);
static bool
is_deleted_glyph (const hb_glyph_info_t *info)
{
return info->codepoint == AAT::DELETED_GLYPH;
}
void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
{
hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
}
/*
* hb_aat_layout_has_positioning:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t
hb_aat_layout_has_positioning (hb_face_t *face)
{
return face->table.kerx->has_data ();
}
void
hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
c.set_ankr_table (font->face->table.ankr.get ());
kerx.apply (&c);
}
/*
* hb_aat_layout_has_tracking:
* @face:
*
* Returns:
* Since: 2.3.0
*/
hb_bool_t
hb_aat_layout_has_tracking (hb_face_t *face)
{
return face->table.trak->has_data ();
}
void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
const AAT::trak& trak = *font->face->table.trak;
AAT::hb_aat_apply_context_t c (plan, font, buffer);
trak.apply (&c);
#endif
}
hb_language_t
_hb_aat_language_get (hb_face_t *face,
unsigned int i)
{
return face->table.ltag->get_language (i);
}
/**
* hb_aat_layout_get_feature_types:
* @face: a face object
* @start_offset: iteration's start offset
* @feature_count:(inout) (allow-none): buffer size as input, filled size as output
* @features: (out caller-allocates) (array length=feature_count): features buffer
*
* Return value: Number of all available feature types.
*
* Since: 2.2.0
*/
unsigned int
hb_aat_layout_get_feature_types (hb_face_t *face,
unsigned int start_offset,
unsigned int *feature_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */)
{
return face->table.feat->get_feature_types (start_offset, feature_count, features);
}
/**
* hb_aat_layout_feature_type_get_name_id:
* @face: a face object
* @feature_type: feature id
*
* Return value: Name ID index
*
* Since: 2.2.0
*/
hb_ot_name_id_t
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type)
{
return face->table.feat->get_feature_name_id (feature_type);
}
/**
* hb_aat_layout_feature_type_get_selectors:
* @face: a face object
* @feature_type: feature id
* @start_offset: iteration's start offset
* @selector_count: (inout) (allow-none): buffer size as input, filled size as output
* @selectors: (out caller-allocates) (array length=selector_count): settings buffer
* @default_index: (out) (allow-none): index of default selector if any
*
* If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then
* the feature type is non-exclusive. Otherwise, @default_index is the index of
* the selector that is selected by default.
*
* Return value: Number of all available feature selectors.
*
* Since: 2.2.0
*/
unsigned int
hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selector_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */)
{
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
}

486
src/hb-aat-layout.h Normal file
View File

@ -0,0 +1,486 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_H_IN
#error "Include <hb-aat.h> instead."
#endif
#ifndef HB_AAT_LAYOUT_H
#define HB_AAT_LAYOUT_H
#include "hb.h"
#include "hb-ot.h"
HB_BEGIN_DECLS
/**
* hb_aat_layout_feature_type_t:
*
*
* Since: 2.2.0
*/
typedef enum
{
HB_AAT_LAYOUT_FEATURE_TYPE_INVALID = 0xFFFF,
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2,
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING = 6,
HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE = 8,
HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE = 9,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION = 10,
HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS = 11,
HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE = 13,
HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS = 14,
HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS = 15,
HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE = 16,
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES = 17,
HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE = 18,
HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS = 19,
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE = 20,
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE = 21,
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING = 22,
HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION = 23,
HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE = 24,
HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE = 25,
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE = 26,
HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE = 27,
HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA = 28,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE = 29,
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE = 30,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE = 31,
HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN = 32,
HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT = 33,
HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA = 34,
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES = 35,
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES = 36,
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE = 37,
HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE = 38,
HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39,
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103,
_HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
} hb_aat_layout_feature_type_t;
/**
* hb_aat_layout_feature_selector_t:
*
*
* Since: 2.2.0
*/
typedef enum
{
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID = 0xFFFF,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON = 14,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF = 15,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON = 16,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF = 17,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON = 18,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF = 19,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON = 20,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF = 21,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE = 0, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS = 1, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE = 2, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS = 3, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS = 4, /* deprecated */
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS = 5, /* deprecated */
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT */
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING */
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF = 9,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS = 4,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF = 11,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF = 11,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS = 6,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES = 0,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1 = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2 = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3 = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4 = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5 = 4,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS = 14,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING */
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT = 6,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE = 9,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION= 10,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE = 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE = 1,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA */
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF = 3,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF = 5,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON = 6,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF = 7,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON = 8,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF = 9,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON = 10,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF = 11,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON = 12,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF = 13,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON = 14,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF = 15,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON = 16,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF = 17,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON = 18,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF = 19,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON = 20,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF = 21,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON = 22,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF = 23,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON = 24,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF = 25,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON = 26,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF = 27,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON = 28,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF = 29,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON = 30,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF = 31,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON = 32,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF = 33,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON = 34,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF = 35,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON = 36,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF = 37,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON = 38,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF = 39,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON = 40,
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF = 41,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES */
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF = 3,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON = 4,
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF= 5,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS = 2,
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE */
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN = 0,
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN = 1,
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2,
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3,
_HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
} hb_aat_layout_feature_selector_t;
HB_EXTERN unsigned int
hb_aat_layout_get_feature_types (hb_face_t *face,
unsigned int start_offset,
unsigned int *feature_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */);
HB_EXTERN hb_ot_name_id_t
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type);
typedef struct hb_aat_layout_feature_selector_info_t
{
hb_ot_name_id_t name_id;
hb_aat_layout_feature_selector_t enable;
hb_aat_layout_feature_selector_t disable;
/*< private >*/
unsigned int reserved;
} hb_aat_layout_feature_selector_info_t;
#define HB_AAT_LAYOUT_NO_SELECTOR_INDEX 0xFFFFu
HB_EXTERN unsigned int
hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face,
hb_aat_layout_feature_type_t feature_type,
unsigned int start_offset,
unsigned int *selector_count, /* IN/OUT. May be NULL. */
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
unsigned int *default_index /* OUT. May be NULL. */);
/*
* morx/mort
*/
HB_EXTERN hb_bool_t
hb_aat_layout_has_substitution (hb_face_t *face);
/*
* kerx
*/
HB_EXTERN hb_bool_t
hb_aat_layout_has_positioning (hb_face_t *face);
/*
* trak
*/
HB_EXTERN hb_bool_t
hb_aat_layout_has_tracking (hb_face_t *face);
HB_END_DECLS
#endif /* HB_AAT_LAYOUT_H */

View File

@ -29,15 +29,57 @@
#include "hb.hh"
#include "hb-font.hh"
#include "hb-buffer.hh"
#include "hb-open-type.hh"
#include "hb-ot-shape.hh"
struct hb_aat_feature_mapping_t
{
hb_tag_t otFeatureTag;
hb_aat_layout_feature_type_t aatFeatureType;
hb_aat_layout_feature_selector_t selectorToEnable;
hb_aat_layout_feature_selector_t selectorToDisable;
HB_INTERNAL static int cmp (const void *key_, const void *entry_)
{
hb_tag_t key = * (unsigned int *) key_;
const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
return key < entry->otFeatureTag ? -1 :
key > entry->otFeatureTag ? 1 :
0;
}
};
HB_INTERNAL const hb_aat_feature_mapping_t *
hb_aat_layout_find_feature_mapping (hb_tag_t tag);
HB_INTERNAL void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map);
HB_INTERNAL void
hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer);
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer);
HB_INTERNAL hb_language_t
_hb_aat_language_get (hb_face_t *face,
unsigned int i);
#endif /* HB_AAT_LAYOUT_HH */

View File

@ -25,7 +25,7 @@
#ifndef HB_AAT_LTAG_TABLE_HH
#define HB_AAT_LTAG_TABLE_HH
#include "hb-aat-layout-common.hh"
#include "hb-open-type.hh"
/*
* ltag -- Language Tag
@ -36,17 +36,21 @@
namespace AAT {
using namespace OT;
struct FTStringRange
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
friend struct ltag;
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && (base+tag).sanitize (c, length));
}
protected:
OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
NNOffsetTo<UnsizedArrayOf<HBUINT8> >
tag; /* Offset from the start of the table to
* the beginning of the string */
HBUINT16 length; /* String length (in bytes) */
@ -56,12 +60,21 @@ struct FTStringRange
struct ltag
{
static const hb_tag_t tableTag = HB_AAT_TAG_ltag;
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
inline bool sanitize (hb_sanitize_context_t *c) const
hb_language_t get_language (unsigned int i) const
{
const FTStringRange &range = tagRanges[i];
return hb_language_from_string ((const char *) (this+range.tag).arrayZ,
range.length);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && tagRanges.sanitize (c, this)));
return_trace (likely (c->check_struct (this) &&
version >= 1 &&
tagRanges.sanitize (c, this)));
}
protected:

68
src/hb-aat-map.cc Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright © 2009,2010 Red Hat, Inc.
* Copyright © 2010,2011,2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#include "hb-aat-map.hh"
#include "hb-aat-layout.hh"
void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
unsigned int value)
{
if (tag == HB_TAG ('a','a','l','t'))
{
feature_info_t *info = features.push();
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
info->setting = (hb_aat_layout_feature_selector_t) value;
return;
}
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
if (!mapping) return;
feature_info_t *info = features.push();
info->type = mapping->aatFeatureType;
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
}
void
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
{
/* Sort features and merge duplicates */
if (features.length)
{
features.qsort ();
unsigned int j = 0;
for (unsigned int i = 1; i < features.length; i++)
if (features[i].type != features[j].type)
features[++j] = features[i];
features.shrink (j + 1);
}
hb_aat_layout_compile_map (this, &m);
}

91
src/hb-aat-map.hh Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_MAP_HH
#define HB_AAT_MAP_HH
#include "hb.hh"
struct hb_aat_map_t
{
friend struct hb_aat_map_builder_t;
public:
void init ()
{
memset (this, 0, sizeof (*this));
chain_flags.init ();
}
void fini () { chain_flags.fini (); }
public:
hb_vector_t<hb_mask_t> chain_flags;
};
struct hb_aat_map_builder_t
{
public:
HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_,
const hb_segment_properties_t *props_ HB_UNUSED) :
face (face_) {}
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
HB_INTERNAL void compile (hb_aat_map_t &m);
public:
struct feature_info_t
{
hb_aat_layout_feature_type_t type;
hb_aat_layout_feature_selector_t setting;
unsigned seq; /* For stable sorting only. */
HB_INTERNAL static int cmp (const void *pa, const void *pb)
{
const feature_info_t *a = (const feature_info_t *) pa;
const feature_info_t *b = (const feature_info_t *) pb;
return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
(a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
}
int cmp (hb_aat_layout_feature_type_t ty) const
{
return (type != ty) ? (type < ty ? -1 : 1) : 0;
}
};
public:
hb_face_t *face;
public:
hb_sorted_vector_t<feature_info_t> features;
};
#endif /* HB_AAT_MAP_HH */

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2009 Red Hat, Inc.
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
@ -20,40 +20,19 @@
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_H_IN
#error "Include <hb-ot.h> instead."
#endif
#ifndef HB_OT_TAG_H
#define HB_OT_TAG_H
#ifndef HB_AAT_H
#define HB_AAT_H
#define HB_AAT_H_IN
#include "hb.h"
#include "hb-aat-layout.h"
HB_BEGIN_DECLS
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
HB_EXTERN void
hb_ot_tags_from_script (hb_script_t script,
hb_tag_t *script_tag_1,
hb_tag_t *script_tag_2);
HB_EXTERN hb_script_t
hb_ot_tag_to_script (hb_tag_t tag);
HB_EXTERN hb_tag_t
hb_ot_tag_from_language (hb_language_t language);
HB_EXTERN hb_language_t
hb_ot_tag_to_language (hb_tag_t tag);
HB_END_DECLS
#endif /* HB_OT_TAG_H */
#undef HB_AAT_H_IN
#endif /* HB_AAT_H */

View File

@ -24,17 +24,90 @@
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_DSALGS_HH
#define HB_DSALGS_HH
#ifndef HB_ALGS_HH
#define HB_ALGS_HH
#include "hb.hh"
#include "hb-meta.hh"
#include "hb-null.hh"
/* Void! For when we need a expression-type of void. */
typedef const struct _hb_void_t *hb_void_t;
#define HB_VOID ((const _hb_void_t *) nullptr)
static const struct
{
/* Don't know how to set priority of following. Doesn't work right now. */
//template <typename T>
//uint32_t operator () (const T& v) const
//{ return hb_deref_pointer (v).hash (); }
/* Instead, the following ugly soution: */
template <typename T,
hb_enable_if (!hb_is_integer (hb_remove_const (hb_remove_reference (T))) && !hb_is_pointer (T))>
uint32_t operator () (T&& v) const { return v.hash (); }
template <typename T>
uint32_t operator () (const T *v) const
{ return operator() (*v); }
template <typename T,
hb_enable_if (hb_is_integer (T))>
uint32_t operator () (T v) const
{
/* Knuth's multiplicative method: */
return (uint32_t) v * 2654435761u;
}
} hb_hash HB_UNUSED;
static const struct
{
template <typename T> T
operator () (const T& v) const { return v; }
} hb_identity HB_UNUSED;
static const struct
{
template <typename T> bool
operator () (const T& v) const { return bool (v); }
} hb_bool HB_UNUSED;
template <typename T1, typename T2>
struct hb_pair_t
{
typedef T1 first_t;
typedef T2 second_t;
typedef hb_pair_t<T1, T2> pair_t;
hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
hb_pair_t (const pair_t& o) : first (o.first), second (o.second) {}
bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
T1 first;
T2 second;
};
template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
static const struct
{
template <typename Pair> decltype (hb_declval (Pair).first)
operator () (const Pair& pair) const { return pair.first; }
} hb_first HB_UNUSED;
static const struct
{
template <typename Pair> decltype (hb_declval (Pair).second)
operator () (const Pair& pair) const { return pair.second; }
} hb_second HB_UNUSED;
static const struct
{
template <typename T, typename T2> T
operator () (const T& a, const T2& b) const { return a <= b ? a : b; }
} hb_min HB_UNUSED;
static const struct
{
template <typename T, typename T2> T
operator () (const T& a, const T2& b) const { return a >= b ? a : b; }
} hb_max HB_UNUSED;
/*
@ -46,7 +119,7 @@ template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_popcount (T v)
{
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) && defined(__OPTIMIZE__)
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (v);
@ -89,7 +162,7 @@ hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v);
@ -107,7 +180,7 @@ hb_bit_storage (T v)
_BitScanReverse (&where, v);
return 1 + where;
}
# if _WIN64
# if defined(_WIN64)
if (sizeof (T) <= 8)
{
unsigned long where;
@ -163,7 +236,7 @@ hb_ctz (T v)
{
if (unlikely (!v)) return 0;
#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__OPTIMIZE__)
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v);
@ -181,7 +254,7 @@ hb_ctz (T v)
_BitScanForward (&where, v);
return where;
}
# if _WIN64
# if defined(_WIN64)
if (sizeof (T) <= 8)
{
unsigned long where;
@ -264,6 +337,17 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
static inline int
hb_memcmp (const void *a, const void *b, unsigned int len)
{
/* It's illegal to pass NULL to memcmp(), even if len is zero.
* So, wrap it.
* https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
if (!len) return 0;
return memcmp (a, b, len);
}
static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
{
@ -276,21 +360,10 @@ hb_ceil_to_4 (unsigned int v)
return ((v - 1) | 3) + 1;
}
template <typename T> class hb_assert_unsigned_t;
template <> class hb_assert_unsigned_t<unsigned char> {};
template <> class hb_assert_unsigned_t<unsigned short> {};
template <> class hb_assert_unsigned_t<unsigned int> {};
template <> class hb_assert_unsigned_t<unsigned long> {};
template <typename T> static inline bool
hb_in_range (T u, T lo, T hi)
{
/* The sizeof() is here to force template instantiation.
* I'm sure there are better ways to do this but can't think of
* one right now. Declaring a variable won't work as HB_UNUSED
* is unusable on some platforms and unused types are less likely
* to generate a warning than unused variables. */
static_assert ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
static_assert (!hb_is_signed<T>::value, "");
/* The casts below are important as if T is smaller than int,
* the subtract results will become a signed int! */
@ -312,6 +385,27 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
* Sort and search.
*/
static inline void *
hb_bsearch (const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *_key, const void *_item))
{
int min = 0, max = (int) nmemb - 1;
while (min <= max)
{
int mid = (min + max) / 2;
const void *p = (const void *) (((const char *) base) + (mid * size));
int c = compar (key, p);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
return (void *) p;
}
return nullptr;
}
static inline void *
hb_bsearch_r (const void *key, const void *base,
size_t nmemb, size_t size,
@ -321,7 +415,7 @@ hb_bsearch_r (const void *key, const void *base,
int min = 0, max = (int) nmemb - 1;
while (min <= max)
{
int mid = (min + max) / 2;
int mid = ((unsigned int) min + (unsigned int) max) / 2;
const void *p = (const void *) (((const char *) base) + (mid * size));
int c = compar (key, p, arg);
if (c < 0)
@ -335,7 +429,12 @@ hb_bsearch_r (const void *key, const void *base,
}
/* From https://github.com/noporpoise/sort_r */
/* From https://github.com/noporpoise/sort_r
* With following modifications:
*
* 10 November 2018:
* https://github.com/noporpoise/sort_r/issues/7
*/
/* Isaac Turner 29 April 2014 Public Domain */
@ -391,7 +490,7 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w,
/* Use median of first, middle and last items as pivot */
char *x, *y, *xend, ch;
char *pl, *pr;
char *pl, *pm, *pr;
char *last = b+w*(nel-1), *tmp;
char *l[3];
l[0] = b;
@ -413,13 +512,15 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w,
pr = last;
while(pl < pr) {
for(; pl < pr; pl += w) {
pm = pl+((pr-pl+1)>>1);
for(; pl < pm; pl += w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pr -= w; /* pivot now at pl */
break;
}
}
for(; pl < pr; pr -= w) {
pm = pl+((pr-pl)>>1);
for(; pm < pr; pr -= w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pl += w; /* pivot now at pr */
break;
@ -432,16 +533,17 @@ static inline void sort_r_simple(void *base, size_t nel, size_t w,
}
}
static inline void hb_sort_r(void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg)
static inline void
hb_sort_r (void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg)
{
sort_r_simple(base, nel, width, compar, arg);
}
template <typename T, typename T2> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
template <typename T, typename T2, typename T3> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
{
for (unsigned int i = 1; i < len; i++)
{
@ -458,8 +560,8 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *),
}
if (array2)
{
T2 t = array2[i];
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
T3 t = array2[i];
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
array2[j] = t;
}
}
@ -490,94 +592,28 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
}
template <typename Type>
struct hb_auto_t : Type
{
hb_auto_t (void) { Type::init (); }
/* Explicitly allow the following only for pointer and references,
* to avoid any accidental copies.
*
* Apparently if we template for all types, then gcc seems to
* capture a reference argument in the type, but clang doesn't,
* causing unwanted copies and bugs that come with it. Ideally
* we should use C++11-style rvalue reference &&t1. */
template <typename T1> explicit hb_auto_t (T1 *t1) { Type::init (t1); }
template <typename T1> explicit hb_auto_t (T1 &t1) { Type::init (t1); }
~hb_auto_t (void) { Type::fini (); }
private: /* Hide */
void init (void) {}
void fini (void) {}
};
template <typename T>
struct hb_array_t
{
inline hb_array_t (void) : arrayZ (nullptr), len (0) {}
inline hb_array_t (const T *array_, unsigned int len_) : arrayZ (array_), len (len_) {}
inline const T& operator [] (unsigned int i) const
{
if (unlikely (i >= len)) return Null(T);
return arrayZ[i];
}
inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
const T *arrayZ;
unsigned int len;
};
struct hb_bytes_t
{
inline hb_bytes_t (void) : arrayZ (nullptr), len (0) {}
inline hb_bytes_t (const char *bytes_, unsigned int len_) : arrayZ (bytes_), len (len_) {}
inline hb_bytes_t (const void *bytes_, unsigned int len_) : arrayZ ((const char *) bytes_), len (len_) {}
template <typename T>
inline hb_bytes_t (const T& array) : arrayZ ((const char *) array.arrayZ), len (array.len) {}
inline void free (void) { ::free ((void *) arrayZ); arrayZ = nullptr; len = 0; }
inline int cmp (const hb_bytes_t &a) const
{
if (len != a.len)
return (int) a.len - (int) len;
return memcmp (a.arrayZ, arrayZ, len);
}
static inline int cmp (const void *pa, const void *pb)
{
hb_bytes_t *a = (hb_bytes_t *) pa;
hb_bytes_t *b = (hb_bytes_t *) pb;
return b->cmp (*a);
}
const char *arrayZ;
unsigned int len;
};
struct HbOpOr
{
static const bool passthru_left = true;
static const bool passthru_right = true;
static constexpr bool passthru_left = true;
static constexpr bool passthru_right = true;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
};
struct HbOpAnd
{
static const bool passthru_left = false;
static const bool passthru_right = false;
static constexpr bool passthru_left = false;
static constexpr bool passthru_right = false;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
};
struct HbOpMinus
{
static const bool passthru_left = true;
static const bool passthru_right = false;
static constexpr bool passthru_left = true;
static constexpr bool passthru_right = false;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
};
struct HbOpXor
{
static const bool passthru_left = true;
static const bool passthru_right = true;
static constexpr bool passthru_left = true;
static constexpr bool passthru_right = true;
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
};
@ -593,8 +629,10 @@ struct hb_vector_size_t
elt_t& operator [] (unsigned int i) { return u.v[i]; }
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
template <class Op>
inline hb_vector_size_t process (const hb_vector_size_t &o) const
hb_vector_size_t process (const hb_vector_size_t &o) const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE
@ -607,13 +645,13 @@ struct hb_vector_size_t
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
return r;
}
inline hb_vector_size_t operator | (const hb_vector_size_t &o) const
hb_vector_size_t operator | (const hb_vector_size_t &o) const
{ return process<HbOpOr> (o); }
inline hb_vector_size_t operator & (const hb_vector_size_t &o) const
hb_vector_size_t operator & (const hb_vector_size_t &o) const
{ return process<HbOpAnd> (o); }
inline hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
{ return process<HbOpXor> (o); }
inline hb_vector_size_t operator ~ () const
hb_vector_size_t operator ~ () const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE && 0
@ -638,4 +676,4 @@ struct hb_vector_size_t
};
#endif /* HB_DSALGS_HH */
#endif /* HB_ALGS_HH */

312
src/hb-array.hh Normal file
View File

@ -0,0 +1,312 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_ARRAY_HH
#define HB_ARRAY_HH
#include "hb.hh"
#include "hb-algs.hh"
#include "hb-iter.hh"
#include "hb-null.hh"
template <typename Type>
struct hb_sorted_array_t;
template <typename Type>
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
{
/*
* Constructors.
*/
hb_array_t () : arrayZ (nullptr), length (0) {}
hb_array_t (const hb_array_t<Type> &o) : arrayZ (o.arrayZ), length (o.length) {}
template <typename U = Type, hb_enable_if (hb_is_const (U))>
hb_array_t (const hb_array_t<hb_remove_const (Type)> &o) : arrayZ (o.arrayZ), length (o.length) {}
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
template <typename U = Type, hb_enable_if (hb_is_const (U))>
hb_array_t& operator = (const hb_array_t<hb_remove_const (Type)> &o)
{ arrayZ = o.arrayZ; length = o.length; return *this; }
hb_array_t& operator = (const hb_array_t &o)
{ arrayZ = o.arrayZ; length = o.length; return *this; }
/*
* Iterator implementation.
*/
typedef Type& __item_t__;
static constexpr bool is_random_access_iterator = true;
Type& __item_at__ (unsigned i) const
{
if (unlikely (i >= length)) return CrapOrNull (Type);
return arrayZ[i];
}
void __forward__ (unsigned n)
{
if (unlikely (n > length))
n = length;
length -= n;
arrayZ += n;
}
void __rewind__ (unsigned n)
{
if (unlikely (n > length))
n = length;
length -= n;
}
unsigned __len__ () const { return length; }
/* Extra operators.
*/
Type * operator & () const { return arrayZ; }
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
template <typename T> operator T * () const { return arrayZ; }
HB_INTERNAL bool operator == (const hb_array_t &o) const;
HB_INTERNAL uint32_t hash () const;
/*
* Compare, Sort, and Search.
*/
/* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
int cmp (const hb_array_t<Type> &a) const
{
if (length != a.length)
return (int) a.length - (int) length;
return hb_memcmp (a.arrayZ, arrayZ, get_size ());
}
HB_INTERNAL static int cmp (const void *pa, const void *pb)
{
hb_array_t<Type> *a = (hb_array_t<Type> *) pa;
hb_array_t<Type> *b = (hb_array_t<Type> *) pb;
return b->cmp (*a);
}
template <typename T>
Type *lsearch (const T &x, Type *not_found = nullptr)
{
unsigned int count = length;
for (unsigned int i = 0; i < count; i++)
if (!this->arrayZ[i].cmp (x))
return &this->arrayZ[i];
return not_found;
}
template <typename T>
const Type *lsearch (const T &x, const Type *not_found = nullptr) const
{
unsigned int count = length;
for (unsigned int i = 0; i < count; i++)
if (!this->arrayZ[i].cmp (x))
return &this->arrayZ[i];
return not_found;
}
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
{
if (likely (length))
::qsort (arrayZ, length, this->item_size, cmp_);
return hb_sorted_array_t<Type> (*this);
}
hb_sorted_array_t<Type> qsort ()
{
if (likely (length))
::qsort (arrayZ, length, this->item_size, Type::cmp);
return hb_sorted_array_t<Type> (*this);
}
void qsort (unsigned int start, unsigned int end)
{
end = MIN (end, length);
assert (start <= end);
if (likely (start < end))
::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
}
/*
* Other methods.
*/
unsigned int get_size () const { return length * this->item_size; }
hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
{
if (!start_offset && !seg_count)
return *this;
unsigned int count = length;
if (unlikely (start_offset > count))
count = 0;
else
count -= start_offset;
if (seg_count)
count = *seg_count = MIN (count, *seg_count);
return hb_array_t<Type> (arrayZ + start_offset, count);
}
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
{ return sub_array (start_offset, &seg_count); }
/* Only call if you allocated the underlying array using malloc() or similar. */
void free ()
{ ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
template <typename hb_sanitize_context_t>
bool sanitize (hb_sanitize_context_t *c) const
{ return c->check_array (arrayZ, length); }
/*
* Members
*/
public:
Type *arrayZ;
unsigned int length;
};
template <typename T> inline hb_array_t<T>
hb_array (T *array, unsigned int length)
{ return hb_array_t<T> (array, length); }
template <typename T, unsigned int length_> inline hb_array_t<T>
hb_array (T (&array_)[length_])
{ return hb_array_t<T> (array_); }
enum hb_bfind_not_found_t
{
HB_BFIND_NOT_FOUND_DONT_STORE,
HB_BFIND_NOT_FOUND_STORE,
HB_BFIND_NOT_FOUND_STORE_CLOSEST,
};
template <typename Type>
struct hb_sorted_array_t :
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
hb_array_t<Type>
{
typedef hb_iter_t<hb_sorted_array_t<Type>, Type&> iter_base_t;
HB_ITER_USING (iter_base_t);
static constexpr bool is_random_access_iterator = true;
static constexpr bool is_sorted_iterator = true;
hb_sorted_array_t () : hb_array_t<Type> () {}
hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
template <typename U = Type, hb_enable_if (hb_is_const (U))>
hb_sorted_array_t (const hb_sorted_array_t<hb_remove_const (Type)> &o) : hb_array_t<Type> (o) {}
hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
{ return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
{ return sub_array (start_offset, &seg_count); }
template <typename T>
Type *bsearch (const T &x, Type *not_found = nullptr)
{
unsigned int i;
return bfind (x, &i) ? &this->arrayZ[i] : not_found;
}
template <typename T>
const Type *bsearch (const T &x, const Type *not_found = nullptr) const
{
unsigned int i;
return bfind (x, &i) ? &this->arrayZ[i] : not_found;
}
template <typename T>
bool bfind (const T &x, unsigned int *i = nullptr,
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{
int min = 0, max = (int) this->length - 1;
const Type *array = this->arrayZ;
while (min <= max)
{
int mid = ((unsigned int) min + (unsigned int) max) / 2;
int c = array[mid].cmp (x);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
{
if (i)
*i = mid;
return true;
}
}
if (i)
{
switch (not_found)
{
case HB_BFIND_NOT_FOUND_DONT_STORE:
break;
case HB_BFIND_NOT_FOUND_STORE:
*i = to_store;
break;
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
max++;
*i = max;
break;
}
}
return false;
}
};
template <typename T> inline hb_sorted_array_t<T>
hb_sorted_array (T *array, unsigned int length)
{ return hb_sorted_array_t<T> (array, length); }
template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
hb_sorted_array (T (&array_)[length_])
{ return hb_sorted_array_t<T> (array_); }
template <typename T>
bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
{
return length == o.length &&
+ hb_zip (*this, o)
| hb_map ([] (hb_pair_t<T&, T&> &&_) -> bool { return _.first == _.second; })
| hb_all
;
}
template <typename T>
uint32_t hb_array_t<T>::hash () const
{
return
+ hb_iter (*this)
| hb_map (hb_hash)
| hb_reduce ([] (uint32_t a, uint32_t b) -> uint32_t { return a * 31 + b; }, 0)
;
}
typedef hb_array_t<const char> hb_bytes_t;
typedef hb_array_t<const unsigned char> hb_ubytes_t;
/* TODO Specialize opeator==/hash() for hb_bytes_t and hb_ubytes_t. */
//template <>
//uint32_t hb_array_t<const char>::hash () const { return 0; }
#endif /* HB_ARRAY_HH */

View File

@ -33,6 +33,7 @@
#define HB_ATOMIC_HH
#include "hb.hh"
#include "hb-meta.hh"
/*
@ -84,12 +85,12 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
@ -100,11 +101,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
#elif !defined(HB_NO_MT) && defined(_WIN32)
#include <windows.h>
static inline void _hb_memory_barrier (void)
static inline void _hb_memory_barrier ()
{
#if !defined(MemoryBarrier)
/* MinGW has a convoluted history of supporting MemoryBarrier. */
@ -119,7 +120,7 @@ static inline void _hb_memory_barrier (void)
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
static_assert ((sizeof (LONG) == sizeof (int)), "");
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
@ -143,21 +144,21 @@ static_assert ((sizeof (LONG) == sizeof (int)), "");
static inline int _hb_fetch_and_add (int *AI, int V)
{
_hb_memory_w_barrier ();
int result = atomic_add_int_nv ((uint_t *) AI, V);
int result = atomic_add_int_nv ((uint_t *) AI, V) - V;
_hb_memory_r_barrier ();
return result;
}
static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, const void *N)
static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
{
_hb_memory_w_barrier ();
int result = atomic_cas_ptr ((void **) P, (void *) O, (void *) N) == (void *) O;
bool result = atomic_cas_ptr (P, O, N) == O;
_hb_memory_r_barrier ();
return result;
}
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((const void **) (P), (O), (N))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
@ -174,17 +175,17 @@ static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, cons
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
#endif
#endif
#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
#include <builtins.h>
@ -253,44 +254,47 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
#ifndef hb_atomic_ptr_impl_get_relaxed
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
#endif
#ifndef hb_atomic_int_impl_set
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
#endif
#ifndef hb_atomic_int_impl_get
inline int hb_atomic_int_impl_get (int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
#endif
#ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; }
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
#define HB_ATOMIC_INT_INIT(V) {V}
struct hb_atomic_int_t
{
inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); }
inline void set (int v_) const { hb_atomic_int_impl_set (&v, v_); }
inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); }
inline int get (void) const { return hb_atomic_int_impl_get (&v); }
inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); }
inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); }
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
int get () const { return hb_atomic_int_impl_get (&v); }
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
mutable int v;
int v;
};
template <typename T> struct hb_remove_ptr_t { typedef T value; };
template <typename T> struct hb_remove_ptr_t<T *> { typedef T value; };
#define HB_ATOMIC_PTR_INIT(V) {V}
template <typename P>
struct hb_atomic_ptr_t
{
typedef typename hb_remove_ptr_t<P>::value T;
typedef hb_remove_pointer (P) T;
inline void init (T* v_ = nullptr) { set_relaxed (v_); }
inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
inline T *get_relaxed (void) const { return hb_atomic_ptr_impl_get_relaxed (&v); }
inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
inline bool cmpexch (const T *old, T *new_) const{ return hb_atomic_ptr_impl_cmpexch (&v, old, new_); }
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
mutable T *v;
T * operator -> () const { return get (); }
template <typename C> operator C * () const { return get (); }
T *v;
};

View File

@ -25,9 +25,16 @@
* Red Hat Author(s): Behdad Esfahbod
*/
/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
#ifndef _POSIX_C_SOURCE
/* https://github.com/harfbuzz/harfbuzz/issues/1308
* http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
* https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
*/
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
#define _POSIX_C_SOURCE 200809L
#pragma GCC diagnostic pop
#endif
#include "hb.hh"
@ -45,19 +52,18 @@
#include <stdlib.h>
DEFINE_NULL_INSTANCE (hb_blob_t) =
{
HB_OBJECT_HEADER_STATIC,
/**
* SECTION: hb-blob
* @title: hb-blob
* @short_description: Binary data containers
* @include: hb.h
*
* Blobs wrap a chunk of binary data to handle lifecycle management of data
* while it is passed between client and HarfBuzz. Blobs are primarily used
* to create font faces, but also to access font face tables, as well as
* pass around other binary data.
**/
true, /* immutable */
nullptr, /* data */
0, /* length */
HB_MEMORY_MODE_READONLY, /* mode */
nullptr, /* user_data */
nullptr /* destroy */
};
/**
* hb_blob_create: (skip)
@ -143,7 +149,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
{
hb_blob_t *blob;
if (!length || offset >= parent->length)
if (!length || !parent || offset >= parent->length)
return hb_blob_get_empty ();
hb_blob_make_immutable (parent);
@ -194,7 +200,7 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob)
* Since: 0.9.2
**/
hb_blob_t *
hb_blob_get_empty (void)
hb_blob_get_empty ()
{
return const_cast<hb_blob_t *> (&Null(hb_blob_t));
}
@ -291,12 +297,10 @@ hb_blob_get_user_data (hb_blob_t *blob,
void
hb_blob_make_immutable (hb_blob_t *blob)
{
if (hb_object_is_inert (blob))
return;
if (blob->immutable)
if (hb_object_is_immutable (blob))
return;
blob->immutable = true;
hb_object_make_immutable (blob);
}
/**
@ -312,7 +316,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
hb_bool_t
hb_blob_is_immutable (hb_blob_t *blob)
{
return blob->immutable;
return hb_object_is_immutable (blob);
}
@ -386,7 +390,7 @@ hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
bool
hb_blob_t::try_make_writable_inplace_unix (void)
hb_blob_t::try_make_writable_inplace_unix ()
{
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
uintptr_t pagesize = -1, mask, length;
@ -429,7 +433,7 @@ hb_blob_t::try_make_writable_inplace_unix (void)
}
bool
hb_blob_t::try_make_writable_inplace (void)
hb_blob_t::try_make_writable_inplace ()
{
DEBUG_MSG_FUNC (BLOB, this, "making writable inplace\n");
@ -444,9 +448,9 @@ hb_blob_t::try_make_writable_inplace (void)
}
bool
hb_blob_t::try_make_writable (void)
hb_blob_t::try_make_writable ()
{
if (this->immutable)
if (hb_object_is_immutable (this))
return false;
if (this->mode == HB_MEMORY_MODE_WRITABLE)
@ -489,11 +493,11 @@ hb_blob_t::try_make_writable (void)
# include <fcntl.h>
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#ifdef _WIN32
# include <windows.h>
#else
# ifndef _O_BINARY
# define _O_BINARY 0
# ifndef O_BINARY
# define O_BINARY 0
# endif
#endif
@ -505,18 +509,19 @@ struct hb_mapped_file_t
{
char *contents;
unsigned long length;
#if defined(_WIN32) || defined(__CYGWIN__)
#ifdef _WIN32
HANDLE mapping;
#endif
};
#if (defined(HAVE_MMAP) || defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP)
static void
_hb_mapped_file_destroy (hb_mapped_file_t *file)
_hb_mapped_file_destroy (void *file_)
{
hb_mapped_file_t *file = (hb_mapped_file_t *) file_;
#ifdef HAVE_MMAP
munmap (file->contents, file->length);
#elif defined(_WIN32) || defined(__CYGWIN__)
#elif defined(_WIN32)
UnmapViewOfFile (file->contents);
CloseHandle (file->mapping);
#else
@ -544,7 +549,7 @@ hb_blob_create_from_file (const char *file_name)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();
int fd = open (file_name, O_RDONLY | _O_BINARY, 0);
int fd = open (file_name, O_RDONLY | O_BINARY, 0);
if (unlikely (fd == -1)) goto fail_without_close;
struct stat st;
@ -567,7 +572,7 @@ fail:
fail_without_close:
free (file);
#elif (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_MMAP)
#elif defined(_WIN32) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();

View File

@ -38,12 +38,9 @@
struct hb_blob_t
{
inline void fini_shallow (void)
{
destroy_user_data ();
}
void fini_shallow () { destroy_user_data (); }
inline void destroy_user_data (void)
void destroy_user_data ()
{
if (destroy)
{
@ -53,25 +50,20 @@ struct hb_blob_t
}
}
HB_INTERNAL bool try_make_writable (void);
HB_INTERNAL bool try_make_writable_inplace (void);
HB_INTERNAL bool try_make_writable_inplace_unix (void);
HB_INTERNAL bool try_make_writable ();
HB_INTERNAL bool try_make_writable_inplace ();
HB_INTERNAL bool try_make_writable_inplace_unix ();
template <typename Type>
inline const Type* as (void) const
const Type* as () const
{
return unlikely (!data) ? &Null(Type) : reinterpret_cast<const Type *> (data);
}
inline hb_bytes_t as_bytes (void) const
{
return hb_bytes_t (data, length);
return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast<const Type *> (data);
}
hb_bytes_t as_bytes () const
{ return hb_bytes_t (data, length); }
public:
hb_object_header_t header;
ASSERT_POD ();
bool immutable;
const char *data;
unsigned int length;
@ -80,7 +72,30 @@ struct hb_blob_t
void *user_data;
hb_destroy_func_t destroy;
};
DECLARE_NULL_INSTANCE (hb_blob_t);
/*
* hb_blob_ptr_t
*/
template <typename P>
struct hb_blob_ptr_t
{
typedef hb_remove_pointer (P) T;
hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {}
hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; }
const T * operator -> () const { return get (); }
const T & operator * () const { return *get (); }
template <typename C> operator const C * () const { return get (); }
operator const char * () const { return (const char *) get (); }
const T * get () const { return b->as<T> (); }
hb_blob_t * get_blob () const { return b.get_raw (); }
unsigned int get_length () const { return b.get ()->length; }
void destroy () { hb_blob_destroy (b.get ()); b = nullptr; }
hb_nonnull_ptr_t<hb_blob_t> b;
};
#endif /* HB_BLOB_HH */

View File

@ -44,7 +44,7 @@ static const char *serialize_formats[] = {
* Since: 0.9.7
**/
const char **
hb_buffer_serialize_list_formats (void)
hb_buffer_serialize_list_formats ()
{
return serialize_formats;
}
@ -58,7 +58,7 @@ hb_buffer_serialize_list_formats (void)
* @str is a valid buffer serialization format, use
* hb_buffer_serialize_list_formats() to get the list of supported formats.
*
* Return value:
* Return value:
* The parsed #hb_buffer_serialize_format_t.
*
* Since: 0.9.7
@ -246,7 +246,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
{
if (info[i].mask &HB_GLYPH_FLAG_DEFINED)
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
}
@ -319,7 +319,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
* ## json
* TODO.
*
* Return value:
* Return value:
* The number of serialized items.
*
* Since: 0.9.7
@ -425,14 +425,14 @@ parse_int (const char *pp, const char *end, int32_t *pv)
* hb_buffer_deserialize_glyphs:
* @buffer: an #hb_buffer_t buffer.
* @buf: (array length=buf_len):
* @buf_len:
* @buf_len:
* @end_ptr: (out):
* @font:
* @format:
* @font:
* @format:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.7
**/
@ -440,8 +440,8 @@ hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
int buf_len, /* -1 means nul-terminated */
const char **end_ptr, /* May be nullptr */
hb_font_t *font, /* May be nullptr */
const char **end_ptr, /* May be NULL */
hb_font_t *font, /* May be NULL */
hb_buffer_serialize_format_t format)
{
const char *end;

View File

@ -33,14 +33,15 @@
/**
* SECTION: hb-buffer
* @title: Buffers
* @title: hb-buffer
* @short_description: Input and output buffers
* @include: hb.h
*
* Buffers serve dual role in HarfBuzz; they hold the input characters that are
* passed hb_shape(), and after shaping they hold the output glyphs.
* passed to hb_shape(), and after shaping they hold the output glyphs.
**/
/**
* hb_segment_properties_equal:
* @a: first #hb_segment_properties_t to compare.
@ -182,7 +183,11 @@ hb_buffer_t::shift_forward (unsigned int count)
if (idx + count > len)
{
/* Under memory failure we might expose this area. At least
* clean it up. Oh well... */
* clean it up. Oh well...
*
* Ideally, we should at least set Default_Ignorable bits on
* these, as well as consistent cluster values. But the former
* is layering violation... */
memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
}
len += count;
@ -210,23 +215,24 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
/* HarfBuzz-Internal API */
void
hb_buffer_t::reset (void)
hb_buffer_t::reset ()
{
if (unlikely (hb_object_is_inert (this)))
if (unlikely (hb_object_is_immutable (this)))
return;
hb_unicode_funcs_destroy (unicode);
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
flags = HB_BUFFER_FLAG_DEFAULT;
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
invisible = 0;
clear ();
}
void
hb_buffer_t::clear (void)
hb_buffer_t::clear ()
{
if (unlikely (hb_object_is_inert (this)))
if (unlikely (hb_object_is_immutable (this)))
return;
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
@ -281,9 +287,9 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
void
hb_buffer_t::remove_output (void)
hb_buffer_t::remove_output ()
{
if (unlikely (hb_object_is_inert (this)))
if (unlikely (hb_object_is_immutable (this)))
return;
have_output = false;
@ -294,9 +300,9 @@ hb_buffer_t::remove_output (void)
}
void
hb_buffer_t::clear_output (void)
hb_buffer_t::clear_output ()
{
if (unlikely (hb_object_is_inert (this)))
if (unlikely (hb_object_is_immutable (this)))
return;
have_output = true;
@ -307,9 +313,9 @@ hb_buffer_t::clear_output (void)
}
void
hb_buffer_t::clear_positions (void)
hb_buffer_t::clear_positions ()
{
if (unlikely (hb_object_is_inert (this)))
if (unlikely (hb_object_is_immutable (this)))
return;
have_output = false;
@ -322,7 +328,7 @@ hb_buffer_t::clear_positions (void)
}
void
hb_buffer_t::swap_buffers (void)
hb_buffer_t::swap_buffers ()
{
if (unlikely (!successful)) return;
@ -354,6 +360,8 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
{
if (unlikely (!make_room_for (num_in, num_out))) return;
assert (idx + num_in <= len);
merge_clusters (idx, idx + num_in);
hb_glyph_info_t orig_info = info[idx];
@ -369,37 +377,6 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
out_len += num_out;
}
void
hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = info[idx];
out_info[out_len].codepoint = glyph_index;
out_len++;
}
void
hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = glyph_info;
out_len++;
}
void
hb_buffer_t::copy_glyph (void)
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = info[idx];
out_len++;
}
bool
hb_buffer_t::move_to (unsigned int i)
{
@ -429,8 +406,14 @@ hb_buffer_t::move_to (unsigned int i)
unsigned int count = out_len - i;
/* This will blow in our face if memory allocation fails later
* in this same lookup... */
if (unlikely (idx < count && !shift_forward (count + 32))) return false;
* in this same lookup...
*
* We used to shift with extra 32 items, instead of the 0 below.
* But that would leave empty slots in the buffer in case of allocation
* failures. Setting to zero for now to avoid other problems (see
* comments in shift_forward(). This can cause O(N^2) behavior more
* severely than adding 32 empty slots can... */
if (unlikely (idx < count && !shift_forward (count + 0))) return false;
assert (idx >= count);
@ -442,19 +425,6 @@ hb_buffer_t::move_to (unsigned int i)
return true;
}
void
hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (out_info != info || out_len != idx)) {
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
out_info[out_len].codepoint = glyph_index;
idx++;
out_len++;
}
void
hb_buffer_t::set_masks (hb_mask_t value,
@ -510,7 +480,7 @@ hb_buffer_t::reverse_range (unsigned int start,
}
void
hb_buffer_t::reverse (void)
hb_buffer_t::reverse ()
{
if (unlikely (!len))
return;
@ -519,7 +489,7 @@ hb_buffer_t::reverse (void)
}
void
hb_buffer_t::reverse_clusters (void)
hb_buffer_t::reverse_clusters ()
{
unsigned int i, start, count, last_cluster;
@ -666,7 +636,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en
}
void
hb_buffer_t::guess_segment_properties (void)
hb_buffer_t::guess_segment_properties ()
{
assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
(!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
@ -709,6 +679,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_BUFFER_FLAG_DEFAULT,
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
0, /* invisible */
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_MAX_OPS_DEFAULT,
@ -738,7 +709,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
* Since: 0.9.2
**/
hb_buffer_t *
hb_buffer_create (void)
hb_buffer_create ()
{
hb_buffer_t *buffer;
@ -756,14 +727,14 @@ hb_buffer_create (void)
/**
* hb_buffer_get_empty:
*
*
*
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
hb_buffer_t *
hb_buffer_get_empty (void)
hb_buffer_get_empty ()
{
return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
}
@ -814,14 +785,14 @@ hb_buffer_destroy (hb_buffer_t *buffer)
/**
* hb_buffer_set_user_data: (skip)
* @buffer: an #hb_buffer_t.
* @key:
* @data:
* @destroy:
* @replace:
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -838,11 +809,11 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
/**
* hb_buffer_get_user_data: (skip)
* @buffer: an #hb_buffer_t.
* @key:
* @key:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -892,9 +863,9 @@ hb_buffer_get_content_type (hb_buffer_t *buffer)
/**
* hb_buffer_set_unicode_funcs:
* @buffer: an #hb_buffer_t.
* @unicode_funcs:
* @unicode_funcs:
*
*
*
*
* Since: 0.9.2
**/
@ -902,7 +873,7 @@ void
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
hb_unicode_funcs_t *unicode_funcs)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
if (!unicode_funcs)
@ -917,9 +888,9 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
* hb_buffer_get_unicode_funcs:
* @buffer: an #hb_buffer_t.
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -949,7 +920,7 @@ hb_buffer_set_direction (hb_buffer_t *buffer,
hb_direction_t direction)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->props.direction = direction;
@ -993,7 +964,7 @@ void
hb_buffer_set_script (hb_buffer_t *buffer,
hb_script_t script)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->props.script = script;
@ -1028,7 +999,7 @@ hb_buffer_get_script (hb_buffer_t *buffer)
* are orthogonal to the scripts, and though they are related, they are
* different concepts and should not be confused with each other.
*
* Use hb_language_from_string() to convert from ISO 639 language codes to
* Use hb_language_from_string() to convert from BCP 47 language tags to
* #hb_language_t.
*
* Since: 0.9.2
@ -1037,7 +1008,7 @@ void
hb_buffer_set_language (hb_buffer_t *buffer,
hb_language_t language)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->props.language = language;
@ -1075,7 +1046,7 @@ void
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
const hb_segment_properties_t *props)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->props = *props;
@ -1111,7 +1082,7 @@ void
hb_buffer_set_flags (hb_buffer_t *buffer,
hb_buffer_flags_t flags)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->flags = flags;
@ -1123,7 +1094,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
*
* See hb_buffer_set_flags().
*
* Return value:
* Return value:
* The @buffer flags.
*
* Since: 0.9.7
@ -1137,9 +1108,9 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
/**
* hb_buffer_set_cluster_level:
* @buffer: an #hb_buffer_t.
* @cluster_level:
* @cluster_level:
*
*
*
*
* Since: 0.9.42
**/
@ -1147,7 +1118,7 @@ void
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
hb_buffer_cluster_level_t cluster_level)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->cluster_level = cluster_level;
@ -1157,9 +1128,9 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
* hb_buffer_get_cluster_level:
* @buffer: an #hb_buffer_t.
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.42
**/
@ -1186,7 +1157,7 @@ void
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
hb_codepoint_t replacement)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->replacement = replacement;
@ -1198,7 +1169,7 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
*
* See hb_buffer_set_replacement_codepoint().
*
* Return value:
* Return value:
* The @buffer replacement #hb_codepoint_t.
*
* Since: 0.9.31
@ -1210,6 +1181,46 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
}
/**
* hb_buffer_set_invisible_glyph:
* @buffer: an #hb_buffer_t.
* @invisible: the invisible #hb_codepoint_t
*
* Sets the #hb_codepoint_t that replaces invisible characters in
* the shaping result. If set to zero (default), the glyph for the
* U+0020 SPACE character is used. Otherwise, this value is used
* verbatim.
*
* Since: 2.0.0
**/
void
hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
hb_codepoint_t invisible)
{
if (unlikely (hb_object_is_immutable (buffer)))
return;
buffer->invisible = invisible;
}
/**
* hb_buffer_get_invisible_glyph:
* @buffer: an #hb_buffer_t.
*
* See hb_buffer_set_invisible_glyph().
*
* Return value:
* The @buffer invisible #hb_codepoint_t.
*
* Since: 2.0.0
**/
hb_codepoint_t
hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
{
return buffer->invisible;
}
/**
* hb_buffer_reset:
* @buffer: an #hb_buffer_t.
@ -1309,7 +1320,7 @@ hb_buffer_add (hb_buffer_t *buffer,
* Similar to hb_buffer_pre_allocate(), but clears any new items added at the
* end.
*
* Return value:
* Return value:
* %true if @buffer memory allocation succeeded, %false otherwise.
*
* Since: 0.9.2
@ -1318,7 +1329,7 @@ hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer,
unsigned int length)
{
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return length == 0;
if (!buffer->ensure (length))
@ -1499,6 +1510,8 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
* it will be set to the process's default language as returned by
* hb_language_get_default(). This may change in the future by
* taking buffer script into consideration when choosing a language.
* Note that hb_language_get_default() is NOT threadsafe the first time
* it is called. See documentation for that function for details.
*
* Since: 0.9.7
**/
@ -1522,7 +1535,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
if (unlikely (hb_object_is_inert (buffer)))
if (unlikely (hb_object_is_immutable (buffer)))
return;
if (text_length == -1)
@ -1653,7 +1666,7 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);
}
/**
@ -1714,7 +1727,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length)
{
hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);
}
@ -1987,7 +2000,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
* @user_data:
* @destroy:
*
*
*
*
* Since: 1.1.3
**/

View File

@ -89,11 +89,13 @@ typedef struct hb_glyph_info_t
* of each line after line-breaking, or limiting
* the reshaping to a small piece around the
* breaking point only.
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
* Since: 1.5.0
*/
typedef enum { /*< flags >*/
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
/*< private >*/
HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
} hb_glyph_flags_t;
@ -282,6 +284,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* space glyph and zeroing the advance width.)
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
* precedence over this flag. Since: 1.8.0
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
* flag indicating that a dotted circle should
* not be inserted in the rendering of incorrect
* character sequences (such at <0905 093E>). Since: 2.4
*
* Since: 0.9.20
*/
@ -290,7 +296,8 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
} hb_buffer_flags_t;
HB_EXTERN void
@ -342,6 +349,13 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
hb_codepoint_t invisible);
HB_EXTERN hb_codepoint_t
hb_buffer_get_invisible_glyph (hb_buffer_t *buffer);
HB_EXTERN void
hb_buffer_reset (hb_buffer_t *buffer);

View File

@ -86,13 +86,13 @@ HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
struct hb_buffer_t
{
hb_object_header_t header;
ASSERT_POD ();
/* Information about how the text in the buffer should be treated */
hb_unicode_funcs_t *unicode; /* Unicode functions */
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_codepoint_t invisible; /* 0 or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
@ -119,7 +119,7 @@ struct hb_buffer_t
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
enum { CONTEXT_LENGTH = 5 };
static constexpr unsigned CONTEXT_LENGTH = 5u;
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
@ -137,7 +137,9 @@ struct hb_buffer_t
/* Methods */
inline void allocate_var (unsigned int start, unsigned int count)
bool in_error () const { return !successful; }
void allocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
@ -147,7 +149,7 @@ struct hb_buffer_t
allocated_var_bits |= bits;
#endif
}
inline void deallocate_var (unsigned int start, unsigned int count)
void deallocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
@ -157,7 +159,7 @@ struct hb_buffer_t
allocated_var_bits &= ~bits;
#endif
}
inline void assert_var (unsigned int start, unsigned int count)
void assert_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
@ -166,67 +168,102 @@ struct hb_buffer_t
assert (bits == (allocated_var_bits & bits));
#endif
}
inline void deallocate_var_all (void)
void deallocate_var_all ()
{
#ifndef HB_NDEBUG
allocated_var_bits = 0;
#endif
}
inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
inline bool has_separate_output (void) const { return info != out_info; }
bool has_separate_output () const { return info != out_info; }
HB_INTERNAL void reset (void);
HB_INTERNAL void clear (void);
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
inline unsigned int backtrack_len (void) const
{ return have_output? out_len : idx; }
inline unsigned int lookahead_len (void) const
{ return len - idx; }
inline unsigned int next_serial (void) { return serial++; }
unsigned int backtrack_len () const { return have_output? out_len : idx; }
unsigned int lookahead_len () const { return len - idx; }
unsigned int next_serial () { return serial++; }
HB_INTERNAL void add (hb_codepoint_t codepoint,
unsigned int cluster);
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
HB_INTERNAL void reverse (void);
HB_INTERNAL void reverse_clusters (void);
HB_INTERNAL void guess_segment_properties (void);
HB_INTERNAL void reverse ();
HB_INTERNAL void reverse_clusters ();
HB_INTERNAL void guess_segment_properties ();
HB_INTERNAL void swap_buffers (void);
HB_INTERNAL void remove_output (void);
HB_INTERNAL void clear_output (void);
HB_INTERNAL void clear_positions (void);
HB_INTERNAL void swap_buffers ();
HB_INTERNAL void remove_output ();
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
HB_INTERNAL void replace_glyphs (unsigned int num_in,
unsigned int num_out,
const hb_codepoint_t *glyph_data);
HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
void replace_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (out_info != info || out_len != idx)) {
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
out_info[out_len].codepoint = glyph_index;
idx++;
out_len++;
}
/* Makes a copy of the glyph at idx to output and replace glyph_index */
HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
{
if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
if (unlikely (idx == len && !out_len))
return Crap(hb_glyph_info_t);
out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
out_info[out_len].codepoint = glyph_index;
out_len++;
return out_info[out_len - 1];
}
void output_info (const hb_glyph_info_t &glyph_info)
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = glyph_info;
out_len++;
}
/* Copies glyph at idx to output but doesn't advance idx */
HB_INTERNAL void copy_glyph (void);
HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
void copy_glyph ()
{
if (unlikely (!make_room_for (0, 1))) return;
out_info[out_len] = info[idx];
out_len++;
}
/* Copies glyph at idx to output and advance idx.
* If there's no output, just advance idx. */
inline void
next_glyph (void)
void
next_glyph ()
{
if (have_output)
{
if (unlikely (out_info != info || out_len != idx)) {
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (1, 1))) return;
out_info[out_len] = info[idx];
}
@ -235,16 +272,31 @@ struct hb_buffer_t
idx++;
}
/* Copies n glyphs at idx to output and advance idx.
* If there's no output, just advance idx. */
void
next_glyphs (unsigned int n)
{
if (have_output)
{
if (out_info != info || out_len != idx)
{
if (unlikely (!make_room_for (n, n))) return;
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
}
out_len += n;
}
idx += n;
}
/* Advance idx without copying to output. */
inline void skip_glyph (void) { idx++; }
inline void reset_masks (hb_mask_t mask)
void skip_glyph () { idx++; }
void reset_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask = mask;
}
inline void add_masks (hb_mask_t mask)
void add_masks (hb_mask_t mask)
{
for (unsigned int j = 0; j < len; j++)
info[j].mask |= mask;
@ -252,7 +304,7 @@ struct hb_buffer_t
HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
unsigned int cluster_start, unsigned int cluster_end);
inline void merge_clusters (unsigned int start, unsigned int end)
void merge_clusters (unsigned int start, unsigned int end)
{
if (end - start < 2)
return;
@ -261,9 +313,9 @@ struct hb_buffer_t
HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph (void);
HB_INTERNAL void delete_glyph ();
inline void unsafe_to_break (unsigned int start,
void unsafe_to_break (unsigned int start,
unsigned int end)
{
if (end - start < 2)
@ -275,12 +327,14 @@ struct hb_buffer_t
/* Internal methods */
HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
HB_INTERNAL bool enlarge (unsigned int size);
inline bool ensure (unsigned int size)
bool ensure (unsigned int size)
{ return likely (!size || size < allocated) ? true : enlarge (size); }
inline bool ensure_inplace (unsigned int size)
bool ensure_inplace (unsigned int size)
{ return likely (!size || size < allocated); }
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
@ -289,12 +343,12 @@ struct hb_buffer_t
typedef long scratch_buffer_t;
HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
inline void clear_context (unsigned int side) { context_len[side] = 0; }
void clear_context (unsigned int side) { context_len[side] = 0; }
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
inline bool messaging (void) { return unlikely (message_func); }
inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
bool messaging () { return unlikely (message_func); }
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
if (!messaging ())
return true;
@ -306,7 +360,7 @@ struct hb_buffer_t
}
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
static inline void
static void
set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
{
if (inf.cluster != cluster)
@ -319,7 +373,7 @@ struct hb_buffer_t
inf.cluster = cluster;
}
inline int
int
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
unsigned int start, unsigned int end,
unsigned int cluster) const
@ -328,7 +382,7 @@ struct hb_buffer_t
cluster = MIN<unsigned int> (cluster, infos[i].cluster);
return cluster;
}
inline void
void
_unsafe_to_break_set_mask (hb_glyph_info_t *infos,
unsigned int start, unsigned int end,
unsigned int cluster)
@ -341,13 +395,9 @@ struct hb_buffer_t
}
}
inline void
unsafe_to_break_all (void)
{
unsafe_to_break_impl (0, len);
}
inline void
safe_to_break_all (void)
void unsafe_to_break_all ()
{ unsafe_to_break_impl (0, len); }
void safe_to_break_all ()
{
for (unsigned int i = 0; i < len; i++)
info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;

View File

@ -36,25 +36,30 @@ template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bit
struct hb_cache_t
{
static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (unsigned int)), "");
static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), "");
static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), "");
inline void init (void) { clear (); }
inline void fini (void) {}
void init () { clear (); }
void fini () {}
inline void clear (void)
{ memset (values, 255, sizeof (values)); }
void clear ()
{
for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
values[i].set_relaxed (-1);
}
inline bool get (unsigned int key, unsigned int *value) const
bool get (unsigned int key, unsigned int *value) const
{
unsigned int k = key & ((1u<<cache_bits)-1);
unsigned int v = values[k].get_relaxed ();
if ((v >> value_bits) != (key >> cache_bits))
if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) ||
(v >> value_bits) != (key >> cache_bits))
return false;
*value = v & ((1u<<value_bits)-1);
return true;
}
inline bool set (unsigned int key, unsigned int value)
bool set (unsigned int key, unsigned int value)
{
if (unlikely ((key >> key_bits) || (value >> value_bits)))
return false; /* Overflows */

725
src/hb-cff-interp-common.hh Normal file
View File

@ -0,0 +1,725 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF_INTERP_COMMON_HH
#define HB_CFF_INTERP_COMMON_HH
namespace CFF {
using namespace OT;
typedef unsigned int op_code_t;
/* === Dict operators === */
/* One byte operators (0-31) */
#define OpCode_version 0 /* CFF Top */
#define OpCode_Notice 1 /* CFF Top */
#define OpCode_FullName 2 /* CFF Top */
#define OpCode_FamilyName 3 /* CFF Top */
#define OpCode_Weight 4 /* CFF Top */
#define OpCode_FontBBox 5 /* CFF Top */
#define OpCode_BlueValues 6 /* CFF Private, CFF2 Private */
#define OpCode_OtherBlues 7 /* CFF Private, CFF2 Private */
#define OpCode_FamilyBlues 8 /* CFF Private, CFF2 Private */
#define OpCode_FamilyOtherBlues 9 /* CFF Private, CFF2 Private */
#define OpCode_StdHW 10 /* CFF Private, CFF2 Private */
#define OpCode_StdVW 11 /* CFF Private, CFF2 Private */
#define OpCode_escape 12 /* All. Shared with CS */
#define OpCode_UniqueID 13 /* CFF Top */
#define OpCode_XUID 14 /* CFF Top */
#define OpCode_charset 15 /* CFF Top (0) */
#define OpCode_Encoding 16 /* CFF Top (0) */
#define OpCode_CharStrings 17 /* CFF Top, CFF2 Top */
#define OpCode_Private 18 /* CFF Top, CFF2 FD */
#define OpCode_Subrs 19 /* CFF Private, CFF2 Private */
#define OpCode_defaultWidthX 20 /* CFF Private (0) */
#define OpCode_nominalWidthX 21 /* CFF Private (0) */
#define OpCode_vsindexdict 22 /* CFF2 Private/CS */
#define OpCode_blenddict 23 /* CFF2 Private/CS */
#define OpCode_vstore 24 /* CFF2 Top */
#define OpCode_reserved25 25
#define OpCode_reserved26 26
#define OpCode_reserved27 27
/* Numbers */
#define OpCode_shortint 28 /* 16-bit integer, All */
#define OpCode_longintdict 29 /* 32-bit integer, All */
#define OpCode_BCD 30 /* Real number, CFF2 Top/FD */
#define OpCode_reserved31 31
/* 1-byte integers */
#define OpCode_OneByteIntFirst 32 /* All. beginning of the range of first byte ints */
#define OpCode_OneByteIntLast 246 /* All. ending of the range of first byte int */
/* 2-byte integers */
#define OpCode_TwoBytePosInt0 247 /* All. first byte of two byte positive int (+108 to +1131) */
#define OpCode_TwoBytePosInt1 248
#define OpCode_TwoBytePosInt2 249
#define OpCode_TwoBytePosInt3 250
#define OpCode_TwoByteNegInt0 251 /* All. first byte of two byte negative int (-1131 to -108) */
#define OpCode_TwoByteNegInt1 252
#define OpCode_TwoByteNegInt2 253
#define OpCode_TwoByteNegInt3 254
/* Two byte escape operators 12, (0-41) */
#define OpCode_ESC_Base 256
#define Make_OpCode_ESC(byte2) ((op_code_t)(OpCode_ESC_Base + (byte2)))
inline op_code_t Unmake_OpCode_ESC (op_code_t op) { return (op_code_t)(op - OpCode_ESC_Base); }
inline bool Is_OpCode_ESC (op_code_t op) { return op >= OpCode_ESC_Base; }
inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2: 1; }
#define OpCode_Copyright Make_OpCode_ESC(0) /* CFF Top */
#define OpCode_isFixedPitch Make_OpCode_ESC(1) /* CFF Top (false) */
#define OpCode_ItalicAngle Make_OpCode_ESC(2) /* CFF Top (0) */
#define OpCode_UnderlinePosition Make_OpCode_ESC(3) /* CFF Top (-100) */
#define OpCode_UnderlineThickness Make_OpCode_ESC(4) /* CFF Top (50) */
#define OpCode_PaintType Make_OpCode_ESC(5) /* CFF Top (0) */
#define OpCode_CharstringType Make_OpCode_ESC(6) /* CFF Top (2) */
#define OpCode_FontMatrix Make_OpCode_ESC(7) /* CFF Top, CFF2 Top (.001 0 0 .001 0 0)*/
#define OpCode_StrokeWidth Make_OpCode_ESC(8) /* CFF Top (0) */
#define OpCode_BlueScale Make_OpCode_ESC(9) /* CFF Private, CFF2 Private (0.039625) */
#define OpCode_BlueShift Make_OpCode_ESC(10) /* CFF Private, CFF2 Private (7) */
#define OpCode_BlueFuzz Make_OpCode_ESC(11) /* CFF Private, CFF2 Private (1) */
#define OpCode_StemSnapH Make_OpCode_ESC(12) /* CFF Private, CFF2 Private */
#define OpCode_StemSnapV Make_OpCode_ESC(13) /* CFF Private, CFF2 Private */
#define OpCode_ForceBold Make_OpCode_ESC(14) /* CFF Private (false) */
#define OpCode_reservedESC15 Make_OpCode_ESC(15)
#define OpCode_reservedESC16 Make_OpCode_ESC(16)
#define OpCode_LanguageGroup Make_OpCode_ESC(17) /* CFF Private, CFF2 Private (0) */
#define OpCode_ExpansionFactor Make_OpCode_ESC(18) /* CFF Private, CFF2 Private (0.06) */
#define OpCode_initialRandomSeed Make_OpCode_ESC(19) /* CFF Private (0) */
#define OpCode_SyntheticBase Make_OpCode_ESC(20) /* CFF Top */
#define OpCode_PostScript Make_OpCode_ESC(21) /* CFF Top */
#define OpCode_BaseFontName Make_OpCode_ESC(22) /* CFF Top */
#define OpCode_BaseFontBlend Make_OpCode_ESC(23) /* CFF Top */
#define OpCode_reservedESC24 Make_OpCode_ESC(24)
#define OpCode_reservedESC25 Make_OpCode_ESC(25)
#define OpCode_reservedESC26 Make_OpCode_ESC(26)
#define OpCode_reservedESC27 Make_OpCode_ESC(27)
#define OpCode_reservedESC28 Make_OpCode_ESC(28)
#define OpCode_reservedESC29 Make_OpCode_ESC(29)
#define OpCode_ROS Make_OpCode_ESC(30) /* CFF Top_CID */
#define OpCode_CIDFontVersion Make_OpCode_ESC(31) /* CFF Top_CID (0) */
#define OpCode_CIDFontRevision Make_OpCode_ESC(32) /* CFF Top_CID (0) */
#define OpCode_CIDFontType Make_OpCode_ESC(33) /* CFF Top_CID (0) */
#define OpCode_CIDCount Make_OpCode_ESC(34) /* CFF Top_CID (8720) */
#define OpCode_UIDBase Make_OpCode_ESC(35) /* CFF Top_CID */
#define OpCode_FDArray Make_OpCode_ESC(36) /* CFF Top_CID, CFF2 Top */
#define OpCode_FDSelect Make_OpCode_ESC(37) /* CFF Top_CID, CFF2 Top */
#define OpCode_FontName Make_OpCode_ESC(38) /* CFF Top_CID */
/* === CharString operators === */
#define OpCode_hstem 1 /* CFF, CFF2 */
#define OpCode_Reserved2 2
#define OpCode_vstem 3 /* CFF, CFF2 */
#define OpCode_vmoveto 4 /* CFF, CFF2 */
#define OpCode_rlineto 5 /* CFF, CFF2 */
#define OpCode_hlineto 6 /* CFF, CFF2 */
#define OpCode_vlineto 7 /* CFF, CFF2 */
#define OpCode_rrcurveto 8 /* CFF, CFF2 */
#define OpCode_Reserved9 9
#define OpCode_callsubr 10 /* CFF, CFF2 */
#define OpCode_return 11 /* CFF */
//#define OpCode_escape 12 /* CFF, CFF2 */
#define OpCode_Reserved13 13
#define OpCode_endchar 14 /* CFF */
#define OpCode_vsindexcs 15 /* CFF2 */
#define OpCode_blendcs 16 /* CFF2 */
#define OpCode_Reserved17 17
#define OpCode_hstemhm 18 /* CFF, CFF2 */
#define OpCode_hintmask 19 /* CFF, CFF2 */
#define OpCode_cntrmask 20 /* CFF, CFF2 */
#define OpCode_rmoveto 21 /* CFF, CFF2 */
#define OpCode_hmoveto 22 /* CFF, CFF2 */
#define OpCode_vstemhm 23 /* CFF, CFF2 */
#define OpCode_rcurveline 24 /* CFF, CFF2 */
#define OpCode_rlinecurve 25 /* CFF, CFF2 */
#define OpCode_vvcurveto 26 /* CFF, CFF2 */
#define OpCode_hhcurveto 27 /* CFF, CFF2 */
//#define OpCode_shortint 28 /* CFF, CFF2 */
#define OpCode_callgsubr 29 /* CFF, CFF2 */
#define OpCode_vhcurveto 30 /* CFF, CFF2 */
#define OpCode_hvcurveto 31 /* CFF, CFF2 */
#define OpCode_fixedcs 255 /* 32-bit fixed */
/* Two byte escape operators 12, (0-41) */
#define OpCode_dotsection Make_OpCode_ESC(0) /* CFF (obsoleted) */
#define OpCode_ReservedESC1 Make_OpCode_ESC(1)
#define OpCode_ReservedESC2 Make_OpCode_ESC(2)
#define OpCode_and Make_OpCode_ESC(3) /* CFF */
#define OpCode_or Make_OpCode_ESC(4) /* CFF */
#define OpCode_not Make_OpCode_ESC(5) /* CFF */
#define OpCode_ReservedESC6 Make_OpCode_ESC(6)
#define OpCode_ReservedESC7 Make_OpCode_ESC(7)
#define OpCode_ReservedESC8 Make_OpCode_ESC(8)
#define OpCode_abs Make_OpCode_ESC(9) /* CFF */
#define OpCode_add Make_OpCode_ESC(10) /* CFF */
#define OpCode_sub Make_OpCode_ESC(11) /* CFF */
#define OpCode_div Make_OpCode_ESC(12) /* CFF */
#define OpCode_ReservedESC13 Make_OpCode_ESC(13)
#define OpCode_neg Make_OpCode_ESC(14) /* CFF */
#define OpCode_eq Make_OpCode_ESC(15) /* CFF */
#define OpCode_ReservedESC16 Make_OpCode_ESC(16)
#define OpCode_ReservedESC17 Make_OpCode_ESC(17)
#define OpCode_drop Make_OpCode_ESC(18) /* CFF */
#define OpCode_ReservedESC19 Make_OpCode_ESC(19)
#define OpCode_put Make_OpCode_ESC(20) /* CFF */
#define OpCode_get Make_OpCode_ESC(21) /* CFF */
#define OpCode_ifelse Make_OpCode_ESC(22) /* CFF */
#define OpCode_random Make_OpCode_ESC(23) /* CFF */
#define OpCode_mul Make_OpCode_ESC(24) /* CFF */
//#define OpCode_reservedESC25 Make_OpCode_ESC(25)
#define OpCode_sqrt Make_OpCode_ESC(26) /* CFF */
#define OpCode_dup Make_OpCode_ESC(27) /* CFF */
#define OpCode_exch Make_OpCode_ESC(28) /* CFF */
#define OpCode_index Make_OpCode_ESC(29) /* CFF */
#define OpCode_roll Make_OpCode_ESC(30) /* CFF */
#define OpCode_reservedESC31 Make_OpCode_ESC(31)
#define OpCode_reservedESC32 Make_OpCode_ESC(32)
#define OpCode_reservedESC33 Make_OpCode_ESC(33)
#define OpCode_hflex Make_OpCode_ESC(34) /* CFF, CFF2 */
#define OpCode_flex Make_OpCode_ESC(35) /* CFF, CFF2 */
#define OpCode_hflex1 Make_OpCode_ESC(36) /* CFF, CFF2 */
#define OpCode_flex1 Make_OpCode_ESC(37) /* CFF, CFF2 */
#define OpCode_Invalid 0xFFFFu
struct number_t
{
void init () { set_real (0.0); }
void fini () {}
void set_int (int v) { value = (double) v; }
int to_int () const { return (int) value; }
void set_fixed (int32_t v) { value = v / 65536.0; }
int32_t to_fixed () const { return (int32_t) (value * 65536.0); }
void set_real (double v) { value = v; }
double to_real () const { return value; }
int ceil () const { return (int) ::ceil (value); }
int floor () const { return (int) ::floor (value); }
bool in_int_range () const
{ return ((double) (int16_t) to_int () == value); }
bool operator > (const number_t &n) const
{ return value > n.to_real (); }
bool operator < (const number_t &n) const
{ return n > *this; }
bool operator >= (const number_t &n) const
{ return !(*this < n); }
bool operator <= (const number_t &n) const
{ return !(*this > n); }
const number_t &operator += (const number_t &n)
{
set_real (to_real () + n.to_real ());
return *this;
}
protected:
double value;
};
/* byte string */
struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
{
// encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
template <typename INTTYPE, int minVal, int maxVal>
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value)
{
TRACE_SERIALIZE (this);
if (unlikely ((value < minVal || value > maxVal)))
return_trace (false);
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
if (unlikely (p == nullptr)) return_trace (false);
*p = intOp;
INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
if (unlikely (ip == nullptr)) return_trace (false);
*ip = (unsigned int) value;
return_trace (true);
}
static bool serialize_int4 (hb_serialize_context_t *c, int value)
{ return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); }
static bool serialize_int2 (hb_serialize_context_t *c, int value)
{ return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); }
/* Defining null_size allows a Null object may be created. Should be safe because:
* A descendent struct Dict uses a Null pointer to indicate a missing table,
* checked before access.
* byte_str_t, a wrapper struct pairing a byte pointer along with its length, always
* checks the length before access. A Null pointer is used as the initial pointer
* along with zero length by the default ctor.
*/
DEFINE_SIZE_MIN(0);
};
/* Holder of a section of byte string within a CFFIndex entry */
struct byte_str_t : hb_ubytes_t
{
byte_str_t ()
: hb_ubytes_t () {}
byte_str_t (const UnsizedByteStr& s, unsigned int l)
: hb_ubytes_t ((const unsigned char*)&s, l) {}
byte_str_t (const unsigned char *s, unsigned int l)
: hb_ubytes_t (s, l) {}
byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */
: hb_ubytes_t (ub) {}
/* sub-string */
byte_str_t sub_str (unsigned int offset, unsigned int len_) const
{ return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); }
bool check_limit (unsigned int offset, unsigned int count) const
{ return (offset + count <= length); }
};
/* A byte string associated with the current offset and an error condition */
struct byte_str_ref_t
{
byte_str_ref_t ()
{ init (); }
void init ()
{
str = byte_str_t ();
offset = 0;
error = false;
}
void fini () {}
byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0)
: str (str_), offset (offset_), error (false) {}
void reset (const byte_str_t &str_, unsigned int offset_ = 0)
{
str = str_;
offset = offset_;
error = false;
}
const unsigned char& operator [] (int i) {
if (unlikely ((unsigned int)(offset + i) >= str.length))
{
set_error ();
return Null(unsigned char);
}
else
return str[offset + i];
}
/* Conversion to byte_str_t */
operator byte_str_t () const { return str.sub_str (offset, str.length - offset); }
byte_str_t sub_str (unsigned int offset_, unsigned int len_) const
{ return str.sub_str (offset_, len_); }
bool avail (unsigned int count=1) const
{
return (!in_error () && str.check_limit (offset, count));
}
void inc (unsigned int count=1)
{
if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
{
offset += count;
}
else
{
offset = str.length;
set_error ();
}
}
void set_error () { error = true; }
bool in_error () const { return error; }
byte_str_t str;
unsigned int offset; /* beginning of the sub-string within str */
protected:
bool error;
};
typedef hb_vector_t<byte_str_t> byte_str_array_t;
/* stack */
template <typename ELEM, int LIMIT>
struct stack_t
{
void init ()
{
error = false;
count = 0;
elements.init ();
elements.resize (kSizeLimit);
for (unsigned int i = 0; i < elements.length; i++)
elements[i].init ();
}
void fini ()
{
elements.fini_deep ();
}
ELEM& operator [] (unsigned int i)
{
if (unlikely (i >= count)) set_error ();
return elements[i];
}
void push (const ELEM &v)
{
if (likely (count < elements.length))
elements[count++] = v;
else
set_error ();
}
ELEM &push ()
{
if (likely (count < elements.length))
return elements[count++];
else
{
set_error ();
return Crap(ELEM);
}
}
ELEM& pop ()
{
if (likely (count > 0))
return elements[--count];
else
{
set_error ();
return Crap(ELEM);
}
}
void pop (unsigned int n)
{
if (likely (count >= n))
count -= n;
else
set_error ();
}
const ELEM& peek ()
{
if (likely (count > 0))
return elements[count-1];
else
{
set_error ();
return Null(ELEM);
}
}
void unpop ()
{
if (likely (count < elements.length))
count++;
else
set_error ();
}
void clear () { count = 0; }
bool in_error () const { return (error || elements.in_error ()); }
void set_error () { error = true; }
unsigned int get_count () const { return count; }
bool is_empty () const { return count == 0; }
static constexpr unsigned kSizeLimit = LIMIT;
protected:
bool error;
unsigned int count;
hb_vector_t<ELEM> elements;
};
/* argument stack */
template <typename ARG=number_t>
struct arg_stack_t : stack_t<ARG, 513>
{
void push_int (int v)
{
ARG &n = S::push ();
n.set_int (v);
}
void push_fixed (int32_t v)
{
ARG &n = S::push ();
n.set_fixed (v);
}
void push_real (double v)
{
ARG &n = S::push ();
n.set_real (v);
}
ARG& pop_num () { return this->pop (); }
int pop_int () { return this->pop ().to_int (); }
unsigned int pop_uint ()
{
int i = pop_int ();
if (unlikely (i < 0))
{
i = 0;
S::set_error ();
}
return (unsigned)i;
}
void push_longint_from_substr (byte_str_ref_t& str_ref)
{
push_int ((str_ref[0] << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3]));
str_ref.inc (4);
}
bool push_fixed_from_substr (byte_str_ref_t& str_ref)
{
if (unlikely (!str_ref.avail (4)))
return false;
push_fixed ((int32_t)*(const HBUINT32*)&str_ref[0]);
str_ref.inc (4);
return true;
}
hb_array_t<const ARG> get_subarray (unsigned int start) const
{
return S::elements.sub_array (start);
}
private:
typedef stack_t<ARG, 513> S;
};
/* an operator prefixed by its operands in a byte string */
struct op_str_t
{
void init () {}
void fini () {}
op_code_t op;
byte_str_t str;
};
/* base of OP_SERIALIZER */
struct op_serializer_t
{
protected:
bool copy_opstr (hb_serialize_context_t *c, const op_str_t& opstr) const
{
TRACE_SERIALIZE (this);
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
if (unlikely (d == nullptr)) return_trace (false);
memcpy (d, &opstr.str[0], opstr.str.length);
return_trace (true);
}
};
template <typename VAL>
struct parsed_values_t
{
void init ()
{
opStart = 0;
values.init ();
}
void fini () { values.fini_deep (); }
void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ())
{
VAL *val = values.push ();
val->op = op;
val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart);
opStart = str_ref.offset;
}
void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
{
VAL *val = values.push (v);
val->op = op;
val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart);
opStart = str_ref.offset;
}
bool has_op (op_code_t op) const
{
for (unsigned int i = 0; i < get_count (); i++)
if (get_value (i).op == op) return true;
return false;
}
unsigned get_count () const { return values.length; }
const VAL &get_value (unsigned int i) const { return values[i]; }
const VAL &operator [] (unsigned int i) const { return get_value (i); }
unsigned int opStart;
hb_vector_t<VAL> values;
};
template <typename ARG=number_t>
struct interp_env_t
{
void init (const byte_str_t &str_)
{
str_ref.reset (str_);
argStack.init ();
error = false;
}
void fini () { argStack.fini (); }
bool in_error () const
{ return error || str_ref.in_error () || argStack.in_error (); }
void set_error () { error = true; }
op_code_t fetch_op ()
{
op_code_t op = OpCode_Invalid;
if (unlikely (!str_ref.avail ()))
return OpCode_Invalid;
op = (op_code_t)(unsigned char)str_ref[0];
if (op == OpCode_escape) {
if (unlikely (!str_ref.avail ()))
return OpCode_Invalid;
op = Make_OpCode_ESC(str_ref[1]);
str_ref.inc ();
}
str_ref.inc ();
return op;
}
const ARG& eval_arg (unsigned int i)
{
return argStack[i];
}
ARG& pop_arg ()
{
return argStack.pop ();
}
void pop_n_args (unsigned int n)
{
argStack.pop (n);
}
void clear_args ()
{
pop_n_args (argStack.get_count ());
}
byte_str_ref_t str_ref;
arg_stack_t<ARG> argStack;
protected:
bool error;
};
typedef interp_env_t<> num_interp_env_t;
template <typename ARG=number_t>
struct opset_t
{
static void process_op (op_code_t op, interp_env_t<ARG>& env)
{
switch (op) {
case OpCode_shortint:
env.argStack.push_int ((int16_t)((env.str_ref[0] << 8) | env.str_ref[1]));
env.str_ref.inc (2);
break;
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.str_ref[0] + 108));
env.str_ref.inc ();
break;
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
env.str_ref.inc ();
break;
default:
/* 1-byte integer */
if (likely ((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast)))
{
env.argStack.push_int ((int)op - 139);
} else {
/* invalid unknown operator */
env.clear_args ();
env.set_error ();
}
break;
}
}
};
template <typename ENV>
struct interpreter_t {
~interpreter_t() { fini (); }
void fini () { env.fini (); }
ENV env;
};
} /* namespace CFF */
#endif /* HB_CFF_INTERP_COMMON_HH */

View File

@ -0,0 +1,905 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF_INTERP_CS_COMMON_HH
#define HB_CFF_INTERP_CS_COMMON_HH
#include "hb.hh"
#include "hb-cff-interp-common.hh"
namespace CFF {
using namespace OT;
enum cs_type_t {
CSType_CharString,
CSType_GlobalSubr,
CSType_LocalSubr
};
struct call_context_t
{
void init (const byte_str_ref_t substr_=byte_str_ref_t (), cs_type_t type_=CSType_CharString, unsigned int subr_num_=0)
{
str_ref = substr_;
type = type_;
subr_num = subr_num_;
}
void fini () {}
byte_str_ref_t str_ref;
cs_type_t type;
unsigned int subr_num;
};
/* call stack */
const unsigned int kMaxCallLimit = 10;
struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {};
template <typename SUBRS>
struct biased_subrs_t
{
void init (const SUBRS &subrs_)
{
subrs = &subrs_;
unsigned int nSubrs = get_count ();
if (nSubrs < 1240)
bias = 107;
else if (nSubrs < 33900)
bias = 1131;
else
bias = 32768;
}
void fini () {}
unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
unsigned int get_bias () const { return bias; }
byte_str_t operator [] (unsigned int index) const
{
if (unlikely ((subrs == nullptr) || index >= subrs->count))
return Null(byte_str_t);
else
return (*subrs)[index];
}
protected:
unsigned int bias;
const SUBRS *subrs;
};
struct point_t
{
void init ()
{
x.init ();
y.init ();
}
void set_int (int _x, int _y)
{
x.set_int (_x);
y.set_int (_y);
}
void move_x (const number_t &dx) { x += dx; }
void move_y (const number_t &dy) { y += dy; }
void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
void move (const point_t &d) { move_x (d.x); move_y (d.y); }
number_t x;
number_t y;
};
template <typename ARG, typename SUBRS>
struct cs_interp_env_t : interp_env_t<ARG>
{
void init (const byte_str_t &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
{
interp_env_t<ARG>::init (str);
context.init (str, CSType_CharString);
seen_moveto = true;
seen_hintmask = false;
hstem_count = 0;
vstem_count = 0;
hintmask_size = 0;
pt.init ();
callStack.init ();
globalSubrs.init (globalSubrs_);
localSubrs.init (localSubrs_);
}
void fini ()
{
interp_env_t<ARG>::fini ();
callStack.fini ();
globalSubrs.fini ();
localSubrs.fini ();
}
bool in_error () const
{
return callStack.in_error () || SUPER::in_error ();
}
bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
{
int n = SUPER::argStack.pop_int ();
n += biasedSubrs.get_bias ();
if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
return false;
subr_num = (unsigned int)n;
return true;
}
void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
{
unsigned int subr_num;
if (unlikely (!popSubrNum (biasedSubrs, subr_num)
|| callStack.get_count () >= kMaxCallLimit))
{
SUPER::set_error ();
return;
}
context.str_ref = SUPER::str_ref;
callStack.push (context);
context.init ( biasedSubrs[subr_num], type, subr_num);
SUPER::str_ref = context.str_ref;
}
void returnFromSubr ()
{
if (unlikely (SUPER::str_ref.in_error ()))
SUPER::set_error ();
context = callStack.pop ();
SUPER::str_ref = context.str_ref;
}
void determine_hintmask_size ()
{
if (!seen_hintmask)
{
vstem_count += SUPER::argStack.get_count() / 2;
hintmask_size = (hstem_count + vstem_count + 7) >> 3;
seen_hintmask = true;
}
}
void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
bool is_endchar () const { return endchar_flag; }
const number_t &get_x () const { return pt.x; }
const number_t &get_y () const { return pt.y; }
const point_t &get_pt () const { return pt; }
void moveto (const point_t &pt_ ) { pt = pt_; }
public:
call_context_t context;
bool endchar_flag;
bool seen_moveto;
bool seen_hintmask;
unsigned int hstem_count;
unsigned int vstem_count;
unsigned int hintmask_size;
call_stack_t callStack;
biased_subrs_t<SUBRS> globalSubrs;
biased_subrs_t<SUBRS> localSubrs;
private:
point_t pt;
typedef interp_env_t<ARG> SUPER;
};
template <typename ENV, typename PARAM>
struct path_procs_null_t
{
static void rmoveto (ENV &env, PARAM& param) {}
static void hmoveto (ENV &env, PARAM& param) {}
static void vmoveto (ENV &env, PARAM& param) {}
static void rlineto (ENV &env, PARAM& param) {}
static void hlineto (ENV &env, PARAM& param) {}
static void vlineto (ENV &env, PARAM& param) {}
static void rrcurveto (ENV &env, PARAM& param) {}
static void rcurveline (ENV &env, PARAM& param) {}
static void rlinecurve (ENV &env, PARAM& param) {}
static void vvcurveto (ENV &env, PARAM& param) {}
static void hhcurveto (ENV &env, PARAM& param) {}
static void vhcurveto (ENV &env, PARAM& param) {}
static void hvcurveto (ENV &env, PARAM& param) {}
static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
static void line (ENV &env, PARAM& param, const point_t &pt1) {}
static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
static void hflex (ENV &env, PARAM& param) {}
static void flex (ENV &env, PARAM& param) {}
static void hflex1 (ENV &env, PARAM& param) {}
static void flex1 (ENV &env, PARAM& param) {}
};
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM> >
struct cs_opset_t : opset_t<ARG>
{
static void process_op (op_code_t op, ENV &env, PARAM& param)
{
switch (op) {
case OpCode_return:
env.returnFromSubr ();
break;
case OpCode_endchar:
OPSET::check_width (op, env, param);
env.set_endchar (true);
OPSET::flush_args_and_op (op, env, param);
break;
case OpCode_fixedcs:
env.argStack.push_fixed_from_substr (env.str_ref);
break;
case OpCode_callsubr:
env.callSubr (env.localSubrs, CSType_LocalSubr);
break;
case OpCode_callgsubr:
env.callSubr (env.globalSubrs, CSType_GlobalSubr);
break;
case OpCode_hstem:
case OpCode_hstemhm:
OPSET::check_width (op, env, param);
OPSET::process_hstem (op, env, param);
break;
case OpCode_vstem:
case OpCode_vstemhm:
OPSET::check_width (op, env, param);
OPSET::process_vstem (op, env, param);
break;
case OpCode_hintmask:
case OpCode_cntrmask:
OPSET::check_width (op, env, param);
OPSET::process_hintmask (op, env, param);
break;
case OpCode_rmoveto:
OPSET::check_width (op, env, param);
PATH::rmoveto (env, param);
OPSET::process_post_move (op, env, param);
break;
case OpCode_hmoveto:
OPSET::check_width (op, env, param);
PATH::hmoveto (env, param);
OPSET::process_post_move (op, env, param);
break;
case OpCode_vmoveto:
OPSET::check_width (op, env, param);
PATH::vmoveto (env, param);
OPSET::process_post_move (op, env, param);
break;
case OpCode_rlineto:
PATH::rlineto (env, param);
process_post_path (op, env, param);
break;
case OpCode_hlineto:
PATH::hlineto (env, param);
process_post_path (op, env, param);
break;
case OpCode_vlineto:
PATH::vlineto (env, param);
process_post_path (op, env, param);
break;
case OpCode_rrcurveto:
PATH::rrcurveto (env, param);
process_post_path (op, env, param);
break;
case OpCode_rcurveline:
PATH::rcurveline (env, param);
process_post_path (op, env, param);
break;
case OpCode_rlinecurve:
PATH::rlinecurve (env, param);
process_post_path (op, env, param);
break;
case OpCode_vvcurveto:
PATH::vvcurveto (env, param);
process_post_path (op, env, param);
break;
case OpCode_hhcurveto:
PATH::hhcurveto (env, param);
process_post_path (op, env, param);
break;
case OpCode_vhcurveto:
PATH::vhcurveto (env, param);
process_post_path (op, env, param);
break;
case OpCode_hvcurveto:
PATH::hvcurveto (env, param);
process_post_path (op, env, param);
break;
case OpCode_hflex:
PATH::hflex (env, param);
OPSET::process_post_flex (op, env, param);
break;
case OpCode_flex:
PATH::flex (env, param);
OPSET::process_post_flex (op, env, param);
break;
case OpCode_hflex1:
PATH::hflex1 (env, param);
OPSET::process_post_flex (op, env, param);
break;
case OpCode_flex1:
PATH::flex1 (env, param);
OPSET::process_post_flex (op, env, param);
break;
default:
SUPER::process_op (op, env);
break;
}
}
static void process_hstem (op_code_t op, ENV &env, PARAM& param)
{
env.hstem_count += env.argStack.get_count () / 2;
OPSET::flush_args_and_op (op, env, param);
}
static void process_vstem (op_code_t op, ENV &env, PARAM& param)
{
env.vstem_count += env.argStack.get_count () / 2;
OPSET::flush_args_and_op (op, env, param);
}
static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
{
env.determine_hintmask_size ();
if (likely (env.str_ref.avail (env.hintmask_size)))
{
OPSET::flush_hintmask (op, env, param);
env.str_ref.inc (env.hintmask_size);
}
}
static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
{
OPSET::flush_args_and_op (op, env, param);
}
static void check_width (op_code_t op, ENV &env, PARAM& param)
{}
static void process_post_move (op_code_t op, ENV &env, PARAM& param)
{
if (!env.seen_moveto)
{
env.determine_hintmask_size ();
env.seen_moveto = true;
}
OPSET::flush_args_and_op (op, env, param);
}
static void process_post_path (op_code_t op, ENV &env, PARAM& param)
{
OPSET::flush_args_and_op (op, env, param);
}
static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
{
OPSET::flush_args (env, param);
OPSET::flush_op (op, env, param);
}
static void flush_args (ENV &env, PARAM& param)
{
env.pop_n_args (env.argStack.get_count ());
}
static void flush_op (op_code_t op, ENV &env, PARAM& param)
{
}
static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
{
OPSET::flush_args_and_op (op, env, param);
}
static bool is_number_op (op_code_t op)
{
switch (op)
{
case OpCode_shortint:
case OpCode_fixedcs:
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
return true;
default:
/* 1-byte integer */
return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
}
}
protected:
typedef opset_t<ARG> SUPER;
};
template <typename PATH, typename ENV, typename PARAM>
struct path_procs_t
{
static void rmoveto (ENV &env, PARAM& param)
{
point_t pt1 = env.get_pt ();
const number_t &dy = env.pop_arg ();
const number_t &dx = env.pop_arg ();
pt1.move (dx, dy);
PATH::moveto (env, param, pt1);
}
static void hmoveto (ENV &env, PARAM& param)
{
point_t pt1 = env.get_pt ();
pt1.move_x (env.pop_arg ());
PATH::moveto (env, param, pt1);
}
static void vmoveto (ENV &env, PARAM& param)
{
point_t pt1 = env.get_pt ();
pt1.move_y (env.pop_arg ());
PATH::moveto (env, param, pt1);
}
static void rlineto (ENV &env, PARAM& param)
{
for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
}
static void hlineto (ENV &env, PARAM& param)
{
point_t pt1;
unsigned int i = 0;
for (; i + 2 <= env.argStack.get_count (); i += 2)
{
pt1 = env.get_pt ();
pt1.move_x (env.eval_arg (i));
PATH::line (env, param, pt1);
pt1.move_y (env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
if (i < env.argStack.get_count ())
{
pt1 = env.get_pt ();
pt1.move_x (env.eval_arg (i));
PATH::line (env, param, pt1);
}
}
static void vlineto (ENV &env, PARAM& param)
{
point_t pt1;
unsigned int i = 0;
for (; i + 2 <= env.argStack.get_count (); i += 2)
{
pt1 = env.get_pt ();
pt1.move_y (env.eval_arg (i));
PATH::line (env, param, pt1);
pt1.move_x (env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
if (i < env.argStack.get_count ())
{
pt1 = env.get_pt ();
pt1.move_y (env.eval_arg (i));
PATH::line (env, param, pt1);
}
}
static void rrcurveto (ENV &env, PARAM& param)
{
for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
point_t pt3 = pt2;
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
static void rcurveline (ENV &env, PARAM& param)
{
unsigned int i = 0;
for (; i + 6 <= env.argStack.get_count (); i += 6)
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
point_t pt3 = pt2;
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
PATH::curve (env, param, pt1, pt2, pt3);
}
for (; i + 2 <= env.argStack.get_count (); i += 2)
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
}
static void rlinecurve (ENV &env, PARAM& param)
{
unsigned int i = 0;
unsigned int line_limit = (env.argStack.get_count () % 6);
for (; i + 2 <= line_limit; i += 2)
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
for (; i + 6 <= env.argStack.get_count (); i += 6)
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
point_t pt3 = pt2;
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
static void vvcurveto (ENV &env, PARAM& param)
{
unsigned int i = 0;
point_t pt1 = env.get_pt ();
if ((env.argStack.get_count () & 1) != 0)
pt1.move_x (env.eval_arg (i++));
for (; i + 4 <= env.argStack.get_count (); i += 4)
{
pt1.move_y (env.eval_arg (i));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
point_t pt3 = pt2;
pt3.move_y (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
}
}
static void hhcurveto (ENV &env, PARAM& param)
{
unsigned int i = 0;
point_t pt1 = env.get_pt ();
if ((env.argStack.get_count () & 1) != 0)
pt1.move_y (env.eval_arg (i++));
for (; i + 4 <= env.argStack.get_count (); i += 4)
{
pt1.move_x (env.eval_arg (i));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
point_t pt3 = pt2;
pt3.move_x (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
}
}
static void vhcurveto (ENV &env, PARAM& param)
{
point_t pt1, pt2, pt3;
unsigned int i = 0;
if ((env.argStack.get_count () % 8) >= 4)
{
point_t pt1 = env.get_pt ();
pt1.move_y (env.eval_arg (i));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
point_t pt3 = pt2;
pt3.move_x (env.eval_arg (i+3));
i += 4;
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
pt1.move_x (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_y (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_y (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_x (env.eval_arg (i+7));
}
if (i < env.argStack.get_count ())
pt3.move_y (env.eval_arg (i));
PATH::curve (env, param, pt1, pt2, pt3);
}
else
{
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
pt1 = env.get_pt ();
pt1.move_y (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_x (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_x (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_y (env.eval_arg (i+7));
if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
pt3.move_x (env.eval_arg (i+8));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
}
static void hvcurveto (ENV &env, PARAM& param)
{
point_t pt1, pt2, pt3;
unsigned int i = 0;
if ((env.argStack.get_count () % 8) >= 4)
{
point_t pt1 = env.get_pt ();
pt1.move_x (env.eval_arg (i));
point_t pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
point_t pt3 = pt2;
pt3.move_y (env.eval_arg (i+3));
i += 4;
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
pt1.move_y (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_x (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_x (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_y (env.eval_arg (i+7));
}
if (i < env.argStack.get_count ())
pt3.move_x (env.eval_arg (i));
PATH::curve (env, param, pt1, pt2, pt3);
}
else
{
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
pt1 = env.get_pt ();
pt1.move_x (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_y (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_y (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_x (env.eval_arg (i+7));
if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
pt3.move_y (env.eval_arg (i+8));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
}
/* default actions to be overridden */
static void moveto (ENV &env, PARAM& param, const point_t &pt)
{ env.moveto (pt); }
static void line (ENV &env, PARAM& param, const point_t &pt1)
{ PATH::moveto (env, param, pt1); }
static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{ PATH::moveto (env, param, pt3); }
static void hflex (ENV &env, PARAM& param)
{
if (likely (env.argStack.get_count () == 7))
{
point_t pt1 = env.get_pt ();
pt1.move_x (env.eval_arg (0));
point_t pt2 = pt1;
pt2.move (env.eval_arg (1), env.eval_arg (2));
point_t pt3 = pt2;
pt3.move_x (env.eval_arg (3));
point_t pt4 = pt3;
pt4.move_x (env.eval_arg (4));
point_t pt5 = pt4;
pt5.move_x (env.eval_arg (5));
pt5.y = pt1.y;
point_t pt6 = pt5;
pt6.move_x (env.eval_arg (6));
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
}
else
env.set_error ();
}
static void flex (ENV &env, PARAM& param)
{
if (likely (env.argStack.get_count () == 13))
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (0), env.eval_arg (1));
point_t pt2 = pt1;
pt2.move (env.eval_arg (2), env.eval_arg (3));
point_t pt3 = pt2;
pt3.move (env.eval_arg (4), env.eval_arg (5));
point_t pt4 = pt3;
pt4.move (env.eval_arg (6), env.eval_arg (7));
point_t pt5 = pt4;
pt5.move (env.eval_arg (8), env.eval_arg (9));
point_t pt6 = pt5;
pt6.move (env.eval_arg (10), env.eval_arg (11));
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
}
else
env.set_error ();
}
static void hflex1 (ENV &env, PARAM& param)
{
if (likely (env.argStack.get_count () == 9))
{
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (0), env.eval_arg (1));
point_t pt2 = pt1;
pt2.move (env.eval_arg (2), env.eval_arg (3));
point_t pt3 = pt2;
pt3.move_x (env.eval_arg (4));
point_t pt4 = pt3;
pt4.move_x (env.eval_arg (5));
point_t pt5 = pt4;
pt5.move (env.eval_arg (6), env.eval_arg (7));
point_t pt6 = pt5;
pt6.move_x (env.eval_arg (8));
pt6.y = env.get_pt ().y;
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
}
else
env.set_error ();
}
static void flex1 (ENV &env, PARAM& param)
{
if (likely (env.argStack.get_count () == 11))
{
point_t d;
d.init ();
for (unsigned int i = 0; i < 10; i += 2)
d.move (env.eval_arg (i), env.eval_arg (i+1));
point_t pt1 = env.get_pt ();
pt1.move (env.eval_arg (0), env.eval_arg (1));
point_t pt2 = pt1;
pt2.move (env.eval_arg (2), env.eval_arg (3));
point_t pt3 = pt2;
pt3.move (env.eval_arg (4), env.eval_arg (5));
point_t pt4 = pt3;
pt4.move (env.eval_arg (6), env.eval_arg (7));
point_t pt5 = pt4;
pt5.move (env.eval_arg (8), env.eval_arg (9));
point_t pt6 = pt5;
if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
{
pt6.move_x (env.eval_arg (10));
pt6.y = env.get_pt ().y;
}
else
{
pt6.x = env.get_pt ().x;
pt6.move_y (env.eval_arg (10));
}
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
}
else
env.set_error ();
}
protected:
static void curve2 (ENV &env, PARAM& param,
const point_t &pt1, const point_t &pt2, const point_t &pt3,
const point_t &pt4, const point_t &pt5, const point_t &pt6)
{
PATH::curve (env, param, pt1, pt2, pt3);
PATH::curve (env, param, pt4, pt5, pt6);
}
};
template <typename ENV, typename OPSET, typename PARAM>
struct cs_interpreter_t : interpreter_t<ENV>
{
bool interpret (PARAM& param)
{
SUPER::env.set_endchar (false);
for (;;) {
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
if (unlikely (SUPER::env.in_error ()))
return false;
if (SUPER::env.is_endchar ())
break;
}
return true;
}
private:
typedef interpreter_t<ENV> SUPER;
};
} /* namespace CFF */
#endif /* HB_CFF_INTERP_CS_COMMON_HH */

View File

@ -0,0 +1,294 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF_INTERP_DICT_COMMON_HH
#define HB_CFF_INTERP_DICT_COMMON_HH
#include "hb-cff-interp-common.hh"
#include <math.h>
#include <float.h>
namespace CFF {
using namespace OT;
/* an opstr and the parsed out dict value(s) */
struct dict_val_t : op_str_t
{
void init () { single_val.set_int (0); }
void fini () {}
number_t single_val;
};
typedef dict_val_t num_dict_val_t;
template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {};
template <typename OPSTR=op_str_t>
struct top_dict_values_t : dict_values_t<OPSTR>
{
void init ()
{
dict_values_t<OPSTR>::init ();
charStringsOffset = 0;
FDArrayOffset = 0;
}
void fini () { dict_values_t<OPSTR>::fini (); }
unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
{
switch (opstr.op)
{
case OpCode_CharStrings:
case OpCode_FDArray:
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
default:
return opstr.str.length;
}
}
unsigned int charStringsOffset;
unsigned int FDArrayOffset;
};
struct dict_opset_t : opset_t<number_t>
{
static void process_op (op_code_t op, interp_env_t<number_t>& env)
{
switch (op) {
case OpCode_longintdict: /* 5-byte integer */
env.argStack.push_longint_from_substr (env.str_ref);
break;
case OpCode_BCD: /* real number */
env.argStack.push_real (parse_bcd (env.str_ref));
break;
default:
opset_t<number_t>::process_op (op, env);
break;
}
}
static double parse_bcd (byte_str_ref_t& str_ref)
{
bool neg = false;
double int_part = 0;
uint64_t frac_part = 0;
uint32_t frac_count = 0;
bool exp_neg = false;
uint32_t exp_part = 0;
bool exp_overflow = false;
enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */
double value = 0.0;
unsigned char byte = 0;
for (uint32_t i = 0;; i++)
{
char d;
if ((i & 1) == 0)
{
if (!str_ref.avail ())
{
str_ref.set_error ();
return 0.0;
}
byte = str_ref[0];
str_ref.inc ();
d = byte >> 4;
}
else
d = byte & 0x0F;
switch (d)
{
case RESERVED:
str_ref.set_error ();
return value;
case END:
value = (double)(neg? -int_part: int_part);
if (frac_count > 0)
{
double frac = (frac_part / pow (10.0, (double)frac_count));
if (neg) frac = -frac;
value += frac;
}
if (unlikely (exp_overflow))
{
if (value == 0.0)
return value;
if (exp_neg)
return neg? -DBL_MIN: DBL_MIN;
else
return neg? -DBL_MAX: DBL_MAX;
}
if (exp_part != 0)
{
if (exp_neg)
value /= pow (10.0, (double)exp_part);
else
value *= pow (10.0, (double)exp_part);
}
return value;
case NEG:
if (i != 0)
{
str_ref.set_error ();
return 0.0;
}
neg = true;
break;
case DECIMAL:
if (part != INT_PART)
{
str_ref.set_error ();
return value;
}
part = FRAC_PART;
break;
case EXP_NEG:
exp_neg = true;
HB_FALLTHROUGH;
case EXP_POS:
if (part == EXP_PART)
{
str_ref.set_error ();
return value;
}
part = EXP_PART;
break;
default:
switch (part) {
default:
case INT_PART:
int_part = (int_part * 10) + d;
break;
case FRAC_PART:
if (likely (frac_part <= MAX_FRACT / 10))
{
frac_part = (frac_part * 10) + (unsigned)d;
frac_count++;
}
break;
case EXP_PART:
if (likely (exp_part * 10 + d <= MAX_EXP))
{
exp_part = (exp_part * 10) + d;
}
else
exp_overflow = true;
break;
}
}
}
return value;
}
static bool is_hint_op (op_code_t op)
{
switch (op)
{
case OpCode_BlueValues:
case OpCode_OtherBlues:
case OpCode_FamilyBlues:
case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH:
case OpCode_StemSnapV:
case OpCode_StdHW:
case OpCode_StdVW:
case OpCode_BlueScale:
case OpCode_BlueShift:
case OpCode_BlueFuzz:
case OpCode_ForceBold:
case OpCode_LanguageGroup:
case OpCode_ExpansionFactor:
return true;
default:
return false;
}
}
};
template <typename VAL=op_str_t>
struct top_dict_opset_t : dict_opset_t
{
static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval)
{
switch (op) {
case OpCode_CharStrings:
dictval.charStringsOffset = env.argStack.pop_uint ();
env.clear_args ();
break;
case OpCode_FDArray:
dictval.FDArrayOffset = env.argStack.pop_uint ();
env.clear_args ();
break;
case OpCode_FontMatrix:
env.clear_args ();
break;
default:
dict_opset_t::process_op (op, env);
break;
}
}
};
template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t>
struct dict_interpreter_t : interpreter_t<ENV>
{
bool interpret (PARAM& param)
{
param.init ();
while (SUPER::env.str_ref.avail ())
{
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
if (unlikely (SUPER::env.in_error ()))
return false;
}
return true;
}
private:
typedef interpreter_t<ENV> SUPER;
};
} /* namespace CFF */
#endif /* HB_CFF_INTERP_DICT_COMMON_HH */

161
src/hb-cff1-interp-cs.hh Normal file
View File

@ -0,0 +1,161 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF1_INTERP_CS_HH
#define HB_CFF1_INTERP_CS_HH
#include "hb.hh"
#include "hb-cff-interp-cs-common.hh"
namespace CFF {
using namespace OT;
typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t;
struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
{
template <typename ACC>
void init (const byte_str_t &str, ACC &acc, unsigned int fd)
{
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
processed_width = false;
has_width = false;
arg_start = 0;
in_seac = false;
}
void fini () { SUPER::fini (); }
void set_width (bool has_width_)
{
if (likely (!processed_width && (SUPER::argStack.get_count () > 0)))
{
if (has_width_)
{
width = SUPER::argStack[0];
has_width = true;
arg_start = 1;
}
}
processed_width = true;
}
void clear_args ()
{
arg_start = 0;
SUPER::clear_args ();
}
void set_in_seac (bool _in_seac) { in_seac = _in_seac; }
bool processed_width;
bool has_width;
unsigned int arg_start;
number_t width;
bool in_seac;
private:
typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
};
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM> >
struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
{
/* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
/* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */
static void process_op (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param)
{
switch (op) {
case OpCode_dotsection:
SUPER::flush_args_and_op (op, env, param);
break;
case OpCode_endchar:
OPSET::check_width (op, env, param);
if (env.argStack.get_count () >= 4)
{
OPSET::process_seac (env, param);
}
OPSET::flush_args_and_op (op, env, param);
env.set_endchar (true);
break;
default:
SUPER::process_op (op, env, param);
}
}
static void check_width (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param)
{
if (!env.processed_width)
{
bool has_width = false;
switch (op)
{
case OpCode_endchar:
case OpCode_hstem:
case OpCode_hstemhm:
case OpCode_vstem:
case OpCode_vstemhm:
case OpCode_hintmask:
case OpCode_cntrmask:
has_width = ((env.argStack.get_count () & 1) != 0);
break;
case OpCode_hmoveto:
case OpCode_vmoveto:
has_width = (env.argStack.get_count () > 1);
break;
case OpCode_rmoveto:
has_width = (env.argStack.get_count () > 2);
break;
default:
return;
}
env.set_width (has_width);
}
}
static void process_seac (cff1_cs_interp_env_t &env, PARAM& param)
{
}
static void flush_args (cff1_cs_interp_env_t &env, PARAM& param)
{
SUPER::flush_args (env, param);
env.clear_args (); /* pop off width */
}
private:
typedef cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH> SUPER;
};
template <typename OPSET, typename PARAM>
struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {};
} /* namespace CFF */
#endif /* HB_CFF1_INTERP_CS_HH */

271
src/hb-cff2-interp-cs.hh Normal file
View File

@ -0,0 +1,271 @@
/*
* Copyright © 2018 Adobe Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_CFF2_INTERP_CS_HH
#define HB_CFF2_INTERP_CS_HH
#include "hb.hh"
#include "hb-cff-interp-cs-common.hh"
namespace CFF {
using namespace OT;
struct blend_arg_t : number_t
{
void init ()
{
number_t::init ();
deltas.init ();
}
void fini ()
{
number_t::fini ();
deltas.fini_deep ();
}
void set_int (int v) { reset_blends (); number_t::set_int (v); }
void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
void set_real (double v) { reset_blends (); number_t::set_real (v); }
void set_blends (unsigned int numValues_, unsigned int valueIndex_,
unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
{
numValues = numValues_;
valueIndex = valueIndex_;
deltas.resize (numBlends);
for (unsigned int i = 0; i < numBlends; i++)
deltas[i] = blends_[i];
}
bool blending () const { return deltas.length > 0; }
void reset_blends ()
{
numValues = valueIndex = 0;
deltas.resize (0);
}
unsigned int numValues;
unsigned int valueIndex;
hb_vector_t<number_t> deltas;
};
typedef interp_env_t<blend_arg_t> BlendInterpEnv;
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
{
template <typename ACC>
void init (const byte_str_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
{
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
coords = coords_;
num_coords = num_coords_;
varStore = acc.varStore;
seen_blend = false;
seen_vsindex_ = false;
scalars.init ();
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
set_ivs (acc.privateDicts[fd].ivs);
}
void fini ()
{
scalars.fini ();
SUPER::fini ();
}
op_code_t fetch_op ()
{
if (this->str_ref.avail ())
return SUPER::fetch_op ();
/* make up return or endchar op */
if (this->callStack.is_empty ())
return OpCode_endchar;
else
return OpCode_return;
}
const blend_arg_t& eval_arg (unsigned int i)
{
blend_arg_t &arg = argStack[i];
blend_arg (arg);
return arg;
}
const blend_arg_t& pop_arg ()
{
blend_arg_t &arg = argStack.pop ();
blend_arg (arg);
return arg;
}
void process_blend ()
{
if (!seen_blend)
{
region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend)
{
scalars.resize (region_count);
varStore->varStore.get_scalars (get_ivs (),
(int *)coords, num_coords,
&scalars[0], region_count);
}
seen_blend = true;
}
}
void process_vsindex ()
{
unsigned int index = argStack.pop_uint ();
if (unlikely (seen_vsindex () || seen_blend))
{
set_error ();
}
else
{
set_ivs (index);
}
seen_vsindex_ = true;
}
unsigned int get_region_count () const { return region_count; }
void set_region_count (unsigned int region_count_) { region_count = region_count_; }
unsigned int get_ivs () const { return ivs; }
void set_ivs (unsigned int ivs_) { ivs = ivs_; }
bool seen_vsindex () const { return seen_vsindex_; }
protected:
void blend_arg (blend_arg_t &arg)
{
if (do_blend && arg.blending ())
{
if (likely (scalars.length == arg.deltas.length))
{
double v = arg.to_real ();
for (unsigned int i = 0; i < scalars.length; i++)
{
v += (double)scalars[i] * arg.deltas[i].to_real ();
}
arg.set_real (v);
arg.deltas.resize (0);
}
}
}
protected:
const int *coords;
unsigned int num_coords;
const CFF2VariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> scalars;
bool do_blend;
bool seen_vsindex_;
bool seen_blend;
typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
};
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM> >
struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
{
static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
{
switch (op) {
case OpCode_callsubr:
case OpCode_callgsubr:
/* a subroutine number shoudln't be a blended value */
if (unlikely (env.argStack.peek ().blending ()))
{
env.set_error ();
break;
}
SUPER::process_op (op, env, param);
break;
case OpCode_blendcs:
OPSET::process_blend (env, param);
break;
case OpCode_vsindexcs:
if (unlikely (env.argStack.peek ().blending ()))
{
env.set_error ();
break;
}
OPSET::process_vsindex (env, param);
break;
default:
SUPER::process_op (op, env, param);
}
}
static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
{
unsigned int n, k;
env.process_blend ();
k = env.get_region_count ();
n = env.argStack.pop_uint ();
/* copy the blend values into blend array of the default values */
unsigned int start = env.argStack.get_count () - ((k+1) * n);
/* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
if (unlikely (start > env.argStack.get_count ()))
{
env.set_error ();
return;
}
for (unsigned int i = 0; i < n; i++)
{
const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k));
env.argStack[start + i].set_blends (n, i, k, blends);
}
/* pop off blend values leaving default values now adorned with blend values */
env.argStack.pop (k * n);
}
static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param)
{
env.process_vsindex ();
env.clear_args ();
}
private:
typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER;
};
template <typename OPSET, typename PARAM>
struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
} /* namespace CFF */
#endif /* HB_CFF2_INTERP_CS_HH */

View File

@ -36,19 +36,48 @@
#endif
/**
* SECTION:hb-common
* @title: hb-common
* @short_description: Common data types
* @include: hb.h
*
* Common data types used across HarfBuzz are defined here.
**/
/* hb_options_t */
hb_atomic_int_t _hb_options;
void
_hb_options_init (void)
_hb_options_init ()
{
hb_options_union_t u;
u.i = 0;
u.opts.initialized = 1;
u.opts.initialized = true;
char *c = getenv ("HB_OPTIONS");
u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
const char *c = getenv ("HB_OPTIONS");
if (c)
{
while (*c)
{
const char *p = strchr (c, ':');
if (!p)
p = c + strlen (c);
#define OPTION(name, symbol) \
if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
OPTION ("aat", aat);
#undef OPTION
c = *p ? p + 1 : p;
}
}
/* This is idempotent and threadsafe. */
_hb_options.set_relaxed (u.i);
@ -175,7 +204,7 @@ static const char canon_map[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
'-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
@ -218,11 +247,10 @@ struct hb_language_item_t {
struct hb_language_item_t *next;
hb_language_t lang;
inline bool operator == (const char *s) const {
return lang_equal (lang, s);
}
bool operator == (const char *s) const
{ return lang_equal (lang, s); }
inline hb_language_item_t & operator = (const char *s) {
hb_language_item_t & operator = (const char *s) {
/* If a custom allocated is used calling strdup() pairs
badly with a call to the custom free() in fini() below.
Therefore don't call strdup(), implement its behavior.
@ -239,7 +267,7 @@ struct hb_language_item_t {
return *this;
}
void fini (void) { free ((void *) lang); }
void fini () { free ((void *) lang); }
};
@ -247,12 +275,12 @@ struct hb_language_item_t {
static hb_atomic_ptr_t <hb_language_item_t> langs;
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
static void
free_langs (void)
free_langs ()
{
retry:
hb_language_item_t *first_lang = langs.get ();
hb_language_item_t *first_lang = langs;
if (unlikely (!langs.cmpexch (first_lang, nullptr)))
goto retry;
@ -269,7 +297,7 @@ static hb_language_item_t *
lang_find_or_insert (const char *key)
{
retry:
hb_language_item_t *first_lang = langs.get ();
hb_language_item_t *first_lang = langs;
for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
if (*lang == key)
@ -294,7 +322,7 @@ retry:
goto retry;
}
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
if (!first_lang)
atexit (free_langs); /* First person registers atexit() callback. */
#endif
@ -306,14 +334,14 @@ retry:
/**
* hb_language_from_string:
* @str: (array length=len) (element-type uint8_t): a string representing
* ISO 639 language code
* a BCP 47 language tag
* @len: length of the @str, or -1 if it is %NULL-terminated.
*
* Converts @str representing an ISO 639 language code to the corresponding
* Converts @str representing a BCP 47 language tag to the corresponding
* #hb_language_t.
*
* Return value: (transfer none):
* The #hb_language_t corresponding to the ISO 639 language code.
* The #hb_language_t corresponding to the BCP 47 language tag.
*
* Since: 0.9.2
**/
@ -361,18 +389,25 @@ hb_language_to_string (hb_language_t language)
/**
* hb_language_get_default:
*
* Get default language from current locale.
*
* Note that the first time this function is called, it calls
* "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
* setlocale function is, in many implementations, NOT threadsafe. To avoid
* problems, call this function once before multiple threads can call it.
* This function is only used from hb_buffer_guess_segment_properties() by
* HarfBuzz itself.
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
hb_language_t
hb_language_get_default (void)
hb_language_get_default ()
{
static hb_atomic_ptr_t <hb_language_t> default_language;
hb_language_t language = default_language.get ();
hb_language_t language = default_language;
if (unlikely (language == HB_LANGUAGE_INVALID))
{
language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
@ -589,6 +624,19 @@ hb_user_data_array_t::get (hb_user_data_key_t *key)
/* hb_version */
/**
* SECTION:hb-version
* @title: hb-version
* @short_description: Information about the version of HarfBuzz in use
* @include: hb.h
*
* These functions and macros allow accessing version of the HarfBuzz
* library used at compile- as well as run-time, and to direct code
* conditionally based on those versions, again, at compile- or run-time.
**/
/**
* hb_version:
* @major: (out): Library major version component.
@ -619,7 +667,7 @@ hb_version (unsigned int *major,
* Since: 0.9.2
**/
const char *
hb_version_string (void)
hb_version_string ()
{
return HB_VERSION_STRING;
}
@ -683,7 +731,7 @@ parse_uint (const char **pp, const char *end, unsigned int *pv)
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
v = strtol (p, &pend, 10);
if (errno || p == pend)
return false;
@ -707,7 +755,7 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
v = strtol (p, &pend, 10);
if (errno || p == pend)
return false;
@ -731,43 +779,43 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
#ifdef USE_XLOCALE
#ifdef HB_USE_ATEXIT
static void free_static_C_locale (void);
#if HB_USE_ATEXIT
static void free_static_C_locale ();
#endif
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<HB_LOCALE_T>::value,
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T),
hb_C_locale_lazy_loader_t>
{
static inline HB_LOCALE_T create (void)
static HB_LOCALE_T create ()
{
HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
atexit (free_static_C_locale);
#endif
return C_locale;
}
static inline void destroy (HB_LOCALE_T p)
static void destroy (HB_LOCALE_T p)
{
HB_FREE_LOCALE (p);
}
static inline HB_LOCALE_T get_null (void)
static HB_LOCALE_T get_null ()
{
return nullptr;
}
} static_C_locale;
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
static
void free_static_C_locale (void)
void free_static_C_locale ()
{
static_C_locale.free_instance ();
}
#endif
static HB_LOCALE_T
get_C_locale (void)
get_C_locale ()
{
return static_C_locale.get_unconst ();
}
@ -809,9 +857,14 @@ parse_bool (const char **pp, const char *end, uint32_t *pv)
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
if (*pp - p == 2
&& TOLOWER (p[0]) == 'o'
&& TOLOWER (p[1]) == 'n')
*pv = 1;
else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
else if (*pp - p == 3
&& TOLOWER (p[0]) == 'o'
&& TOLOWER (p[1]) == 'f'
&& TOLOWER (p[2]) == 'f')
*pv = 0;
else
return false;
@ -885,7 +938,7 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
has_start = parse_uint (pp, end, &feature->start);
if (parse_char (pp, end, ':')) {
if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
parse_uint (pp, end, &feature->end);
} else {
if (has_start)
@ -926,7 +979,41 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
*
* Parses a string into a #hb_feature_t.
*
* TODO: document the syntax here.
* The format for specifying feature strings follows. All valid CSS
* font-feature-settings values other than 'normal' and the global values are
* also accepted, though not documented below. CSS string escapes are not
* supported.
*
* The range indices refer to the positions between Unicode characters. The
* position before the first character is always 0.
*
* The format is Python-esque. Here is how it all works:
*
* <informaltable pgwide='1' align='left' frame='none'>
* <tgroup cols='5'>
* <thead>
* <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
* </thead>
* <tbody>
* <row><entry>Setting value:</entry></row>
* <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry></entry> <entry>Turn feature off</entry></row>
* <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry></entry> <entry>Turn feature off</entry></row>
* <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry></entry> <entry>Choose 2nd alternate</entry></row>
* <row><entry>Setting index:</entry></row>
* <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry></entry> <entry>Turn feature on, partial</entry></row>
* <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row>
* <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row>
* <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
* <row><entry>Mixing it all:</entry></row>
* <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row>
* </tbody>
* </tgroup>
* </informaltable>
*
* Return value:
* %true if @str is successfully parsed, %false otherwise.
@ -1065,7 +1152,7 @@ hb_variation_to_string (hb_variation_t *variation,
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);

View File

@ -33,6 +33,10 @@
#ifndef HB_COMMON_H
#define HB_COMMON_H
#ifndef HB_EXTERN
#define HB_EXTERN extern
#endif
#ifndef HB_BEGIN_DECLS
# ifdef __cplusplus
# define HB_BEGIN_DECLS extern "C" {
@ -63,6 +67,23 @@ typedef unsigned __int64 uint64_t;
# include <stdint.h>
#endif
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define HB_DEPRECATED __attribute__((__deprecated__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
#define HB_DEPRECATED __declspec(deprecated)
#else
#define HB_DEPRECATED
#endif
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
#else
#define HB_DEPRECATED_FOR(f) HB_DEPRECATED
#endif
HB_BEGIN_DECLS
@ -86,8 +107,8 @@ typedef union _hb_var_int_t {
typedef uint32_t hb_tag_t;
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
#define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
#define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
@ -336,17 +357,27 @@ typedef enum
/*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'),
/*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'),
/*
* Since 2.4.0
*/
/*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'),
/*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'),
/*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'),
/*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'),
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. Include both a signed and unsigned max,
* since technically enums are int, and indeed, hb_script_t ends up being signed.
* without risking undefined behavior. We have two, for historical reasons.
* HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
* to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
*
* See this thread for technicalities:
*
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
} hb_script_t;
@ -382,13 +413,13 @@ typedef void (*hb_destroy_func_t) (void *user_data);
/**
* HB_FEATURE_GLOBAL_START
*
* Since: REPLACEME
* Since: 2.0.0
*/
#define HB_FEATURE_GLOBAL_START 0
/**
* HB_FEATURE_GLOBAL_END
*
* Since: REPLACEME
* Since: 2.0.0
*/
#define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
@ -425,6 +456,50 @@ HB_EXTERN void
hb_variation_to_string (hb_variation_t *variation,
char *buf, unsigned int size);
/**
* hb_color_t:
*
* Data type for holding color values.
*
* Since: 2.1.0
*/
typedef uint32_t hb_color_t;
#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
/**
* hb_color_get_alpha:
*
*
*
* Since: 2.1.0
*/
#define hb_color_get_alpha(color) ((color) & 0xFF)
/**
* hb_color_get_red:
*
*
*
* Since: 2.1.0
*/
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
/**
* hb_color_get_green:
*
*
*
* Since: 2.1.0
*/
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
/**
* hb_color_get_blue:
*
*
*
* Since: 2.1.0
*/
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
HB_END_DECLS

View File

@ -26,14 +26,23 @@
* Google Author(s): Behdad Esfahbod
*/
#define HB_SHAPER coretext
#include "hb.hh"
#include "hb-shaper-impl.hh"
#include "hb-coretext.h"
#include "hb-aat-layout.hh"
#include <math.h>
/**
* SECTION:hb-coretext
* @title: hb-coretext
* @short_description: CoreText integration
* @include: hb-coretext.h
*
* Functions for using HarfBuzz with the CoreText fonts.
**/
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
@ -90,13 +99,8 @@ _hb_cg_font_release (void *data)
}
HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) <= .5
)
static CTFontDescriptorRef
get_last_resort_font_desc (void)
get_last_resort_font_desc ()
{
// TODO Handle allocation failures?
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
@ -167,7 +171,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
# define kCTFontUIFontSystem kCTFontSystemFontType
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
#endif
@ -210,7 +214,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
}
CFURLRef original_url = nullptr;
#if TARGET_OS_MAC && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
@ -240,7 +244,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
#if TARGET_OS_MAC && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
@ -301,8 +305,7 @@ hb_coretext_face_create (CGFontRef cg_font)
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face)
{
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
return (CGFontRef) HB_SHAPER_DATA_GET (face);
return (CGFontRef) (const void *) face->data.coretext;
}
@ -310,8 +313,9 @@ hb_coretext_font_data_t *
_hb_coretext_shaper_font_data_create (hb_font_t *font)
{
hb_face_t *face = font->face;
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
const hb_coretext_face_data_t *face_data = face->data.coretext;
if (unlikely (!face_data)) return nullptr;
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
@ -330,6 +334,38 @@ _hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
CFRelease ((CTFontRef) data);
}
static const hb_coretext_font_data_t *
hb_coretext_font_data_sync (hb_font_t *font)
{
retry:
const hb_coretext_font_data_t *data = font->data.coretext;
if (unlikely (!data)) return nullptr;
if (fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) > .5)
{
/* XXX-MT-bug
* Note that evaluating condition above can be dangerous if another thread
* got here first and destructed data. That's, as always, bad use pattern.
* If you modify the font (change font size), other threads must not be
* using it at the same time. However, since this check is delayed to
* when one actually tries to shape something, this is a XXX race condition
* (and the only one we have that I know of) right now. Ie. you modify the
* font size in one thread, then (supposedly safely) try to use it from two
* or more threads and BOOM! I'm not sure how to fix this. We want RCU.
*/
/* Drop and recreate. */
/* If someone dropped it in the mean time, throw it away and don't touch it.
* Otherwise, destruct it. */
if (likely (font->data.coretext.cmpexch (const_cast<hb_coretext_font_data_t *> (data), nullptr)))
_hb_coretext_shaper_font_data_destroy (const_cast<hb_coretext_font_data_t *> (data));
else
goto retry;
}
return font->data.coretext;
}
/*
* Since: 1.7.2
*/
@ -342,13 +378,13 @@ hb_coretext_font_create (CTFontRef ct_font)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_inert (font)))
if (unlikely (hb_object_is_immutable (font)))
return font;
hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
/* Let there be dragons here... */
HB_SHAPER_DATA (HB_SHAPER, font).set_relaxed ((hb_coretext_font_data_t *) CFRetain (ct_font));
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
return font;
}
@ -356,31 +392,8 @@ hb_coretext_font_create (CTFontRef ct_font)
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
return (CTFontRef) HB_SHAPER_DATA_GET (font);
}
/*
* shaper shape_plan data
*/
struct hb_coretext_shape_plan_data_t {};
hb_coretext_shape_plan_data_t *
_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shape_plan_data_t *data HB_UNUSED)
{
const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font);
return data ? (CTFontRef) data : nullptr;
}
@ -397,7 +410,7 @@ struct active_feature_t {
feature_record_t rec;
unsigned int order;
static int cmp (const void *pa, const void *pb) {
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
const active_feature_t *a = (const active_feature_t *) pa;
const active_feature_t *b = (const active_feature_t *) pb;
return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
@ -415,7 +428,7 @@ struct feature_event_t {
bool start;
active_feature_t feature;
static int cmp (const void *pa, const void *pb) {
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
const feature_event_t *a = (const feature_event_t *) pa;
const feature_event_t *b = (const feature_event_t *) pb;
return a->index < b->index ? -1 : a->index > b->index ? 1 :
@ -431,185 +444,6 @@ struct range_record_t {
};
/* The following enum members are added in OS X 10.8. */
#define kAltHalfWidthTextSelector 6
#define kAltProportionalTextSelector 5
#define kAlternateHorizKanaOffSelector 1
#define kAlternateHorizKanaOnSelector 0
#define kAlternateKanaType 34
#define kAlternateVertKanaOffSelector 3
#define kAlternateVertKanaOnSelector 2
#define kCaseSensitiveLayoutOffSelector 1
#define kCaseSensitiveLayoutOnSelector 0
#define kCaseSensitiveLayoutType 33
#define kCaseSensitiveSpacingOffSelector 3
#define kCaseSensitiveSpacingOnSelector 2
#define kContextualAlternatesOffSelector 1
#define kContextualAlternatesOnSelector 0
#define kContextualAlternatesType 36
#define kContextualLigaturesOffSelector 19
#define kContextualLigaturesOnSelector 18
#define kContextualSwashAlternatesOffSelector 5
#define kContextualSwashAlternatesOnSelector 4
#define kDefaultLowerCaseSelector 0
#define kDefaultUpperCaseSelector 0
#define kHistoricalLigaturesOffSelector 21
#define kHistoricalLigaturesOnSelector 20
#define kHojoCharactersSelector 12
#define kJIS2004CharactersSelector 11
#define kLowerCasePetiteCapsSelector 2
#define kLowerCaseSmallCapsSelector 1
#define kLowerCaseType 37
#define kMathematicalGreekOffSelector 11
#define kMathematicalGreekOnSelector 10
#define kNLCCharactersSelector 13
#define kQuarterWidthTextSelector 4
#define kScientificInferiorsSelector 4
#define kStylisticAltEightOffSelector 17
#define kStylisticAltEightOnSelector 16
#define kStylisticAltEighteenOffSelector 37
#define kStylisticAltEighteenOnSelector 36
#define kStylisticAltElevenOffSelector 23
#define kStylisticAltElevenOnSelector 22
#define kStylisticAltFifteenOffSelector 31
#define kStylisticAltFifteenOnSelector 30
#define kStylisticAltFiveOffSelector 11
#define kStylisticAltFiveOnSelector 10
#define kStylisticAltFourOffSelector 9
#define kStylisticAltFourOnSelector 8
#define kStylisticAltFourteenOffSelector 29
#define kStylisticAltFourteenOnSelector 28
#define kStylisticAltNineOffSelector 19
#define kStylisticAltNineOnSelector 18
#define kStylisticAltNineteenOffSelector 39
#define kStylisticAltNineteenOnSelector 38
#define kStylisticAltOneOffSelector 3
#define kStylisticAltOneOnSelector 2
#define kStylisticAltSevenOffSelector 15
#define kStylisticAltSevenOnSelector 14
#define kStylisticAltSeventeenOffSelector 35
#define kStylisticAltSeventeenOnSelector 34
#define kStylisticAltSixOffSelector 13
#define kStylisticAltSixOnSelector 12
#define kStylisticAltSixteenOffSelector 33
#define kStylisticAltSixteenOnSelector 32
#define kStylisticAltTenOffSelector 21
#define kStylisticAltTenOnSelector 20
#define kStylisticAltThirteenOffSelector 27
#define kStylisticAltThirteenOnSelector 26
#define kStylisticAltThreeOffSelector 7
#define kStylisticAltThreeOnSelector 6
#define kStylisticAltTwelveOffSelector 25
#define kStylisticAltTwelveOnSelector 24
#define kStylisticAltTwentyOffSelector 41
#define kStylisticAltTwentyOnSelector 40
#define kStylisticAltTwoOffSelector 5
#define kStylisticAltTwoOnSelector 4
#define kStylisticAlternativesType 35
#define kSwashAlternatesOffSelector 3
#define kSwashAlternatesOnSelector 2
#define kThirdWidthTextSelector 3
#define kTraditionalNamesCharactersSelector 14
#define kUpperCasePetiteCapsSelector 2
#define kUpperCaseSmallCapsSelector 1
#define kUpperCaseType 38
/* Table data courtesy of Apple. */
static const struct feature_mapping_t
{
hb_tag_t otFeatureTag;
uint16_t aatFeatureType;
uint16_t selectorToEnable;
uint16_t selectorToDisable;
} feature_mappings[] =
{
{ 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector },
{ 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector },
{ 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector },
{ 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector },
{ 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector },
{ 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector },
{ 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector },
{ 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector },
{ 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 },
{ 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector },
{ 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 },
{ 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 },
{ 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector },
{ 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, },
{ 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector },
{ 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector },
{ 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 },
{ 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 },
{ 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector },
{ 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 },
{ 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 },
{ 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 },
{ 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 },
{ 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector },
{ 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 },
{ 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector },
{ 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 },
{ 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 },
{ 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector },
{ 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 },
{ 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector },
{ 'pkna', kTextSpacingType, kProportionalTextSelector, 7 },
{ 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 },
{ 'pwid', kTextSpacingType, kProportionalTextSelector, 7 },
{ 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 },
{ 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector },
{ 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector },
{ 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector },
{ 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 },
{ 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector },
{ 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector },
{ 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector },
{ 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector },
{ 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector },
{ 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector },
{ 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector },
{ 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector },
{ 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector },
{ 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector },
{ 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector },
{ 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector },
{ 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector },
{ 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector },
{ 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector },
{ 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector },
{ 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector },
{ 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector },
{ 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector },
{ 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector },
{ 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector },
{ 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector },
{ 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector },
{ 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector },
{ 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 },
{ 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 },
{ 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 },
{ 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 },
{ 'unic', kLetterCaseType, 14, 15 },
{ 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 },
{ 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector },
{ 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 },
{ 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector },
{ 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 },
{ 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector },
{ 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector },
};
static int
_hb_feature_mapping_cmp (const void *key_, const void *entry_)
{
hb_tag_t key = * (unsigned int *) key_;
const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
return key < entry->otFeatureTag ? -1 :
key > entry->otFeatureTag ? 1 :
0;
}
hb_bool_t
_hb_coretext_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
@ -618,15 +452,15 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
unsigned int num_features)
{
hb_face_t *face = font->face;
CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font);
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font);
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
/* Attach marks to their bases, to match the 'ot' shaper.
* Adapted from hb-ot-shape:hb_form_clusters().
* Adapted from a very old version of hb-ot-shape:hb_form_clusters().
* Note that this only makes us be closer to the 'ot' shaper,
* but by no means the same. For example, if there's
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
@ -642,8 +476,8 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
buffer->merge_clusters (i - 1, i + 1);
}
hb_auto_t<hb_vector_t<feature_record_t> > feature_records;
hb_auto_t<hb_vector_t<range_record_t> > range_records;
hb_vector_t<feature_record_t> feature_records;
hb_vector_t<range_record_t> range_records;
/*
* Set up features.
@ -652,14 +486,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
if (num_features)
{
/* Sort features by start/end events. */
hb_auto_t<hb_vector_t<feature_event_t> > feature_events;
hb_vector_t<feature_event_t> feature_events;
for (unsigned int i = 0; i < num_features; i++)
{
const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
feature_mappings,
ARRAY_LENGTH (feature_mappings),
sizeof (feature_mappings[0]),
_hb_feature_mapping_cmp);
const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
if (!mapping)
continue;
@ -695,9 +525,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
}
/* Scan events and save features for each range. */
hb_auto_t<hb_vector_t<active_feature_t> > active_features;
hb_vector_t<active_feature_t> active_features;
unsigned int last_index = 0;
for (unsigned int i = 0; i < feature_events.len; i++)
for (unsigned int i = 0; i < feature_events.length; i++)
{
feature_event_t *event = &feature_events[i];
@ -706,13 +536,13 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
/* Save a snapshot of active features and the range. */
range_record_t *range = range_records.push ();
if (active_features.len)
if (active_features.length)
{
CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
/* TODO sort and resolve conflicting features? */
/* active_features.qsort (); */
for (unsigned int j = 0; j < active_features.len; j++)
for (unsigned int j = 0; j < active_features.length; j++)
{
CFStringRef keys[] = {
kCTFontFeatureTypeIdentifierKey,
@ -768,7 +598,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
} else {
active_feature_t *feature = active_features.find (&event->feature);
if (feature)
active_features.remove (feature - active_features.arrayZ);
active_features.remove (feature - active_features.arrayZ ());
}
}
}
@ -825,7 +655,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CFStringRef string_ref = nullptr;
CTLineRef line = nullptr;
if (0)
if (false)
{
resize_and_retry:
DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
@ -881,7 +711,7 @@ resize_and_retry:
/* What's the iOS equivalent of this check?
* The symbols was introduced in iOS 7.0.
* At any rate, our fallback is safe and works fine. */
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090
# define kCTLanguageAttributeName CFSTR ("NSLanguage")
#endif
CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
@ -900,7 +730,7 @@ resize_and_retry:
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
kCTFontAttributeName, ct_font);
if (num_features && range_records.len)
if (num_features && range_records.length)
{
unsigned int start = 0;
range_record_t *last_range = &range_records[0];
@ -953,7 +783,7 @@ resize_and_retry:
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
#endif
CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
@ -1049,7 +879,7 @@ resize_and_retry:
* Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
*/
bool matched = false;
for (unsigned int i = 0; i < range_records.len; i++)
for (unsigned int i = 0; i < range_records.length; i++)
if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
{
matched = true;
@ -1236,10 +1066,10 @@ resize_and_retry:
*
* https://crbug.com/419769
*/
if (0)
if (false)
{
/* Make sure all runs had the expected direction. */
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
}
@ -1312,102 +1142,9 @@ fail:
if (line)
CFRelease (line);
for (unsigned int i = 0; i < range_records.len; i++)
for (unsigned int i = 0; i < range_records.length; i++)
if (range_records[i].font)
CFRelease (range_records[i].font);
return ret;
}
/*
* AAT shaper
*/
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
/*
* shaper face data
*/
struct hb_coretext_aat_face_data_t {};
hb_coretext_aat_face_data_t *
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
{
static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
{
hb_blob_t *blob = face->reference_table (tags[i]);
if (hb_blob_get_length (blob))
{
hb_blob_destroy (blob);
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
}
hb_blob_destroy (blob);
}
return nullptr;
}
void
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
{
}
/*
* shaper font data
*/
struct hb_coretext_aat_font_data_t {};
hb_coretext_aat_font_data_t *
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
{
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
}
void
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
{
}
/*
* shaper shape_plan data
*/
struct hb_coretext_aat_shape_plan_data_t {};
hb_coretext_aat_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_aat_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shape_plan_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/
hb_bool_t
_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
}

View File

@ -29,7 +29,7 @@
#include "hb.hh"
#include "hb-atomic.hh"
#include "hb-dsalgs.hh"
#include "hb-algs.hh"
#ifndef HB_DEBUG
@ -43,9 +43,10 @@
struct hb_options_t
{
unsigned int unused : 1; /* In-case sign bit is here. */
unsigned int initialized : 1;
unsigned int uniscribe_bug_compatible : 1;
bool unused : 1; /* In-case sign bit is here. */
bool initialized : 1;
bool uniscribe_bug_compatible : 1;
bool aat : 1;
};
union hb_options_union_t {
@ -55,13 +56,16 @@ union hb_options_union_t {
static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
HB_INTERNAL void
_hb_options_init (void);
_hb_options_init ();
extern HB_INTERNAL hb_atomic_int_t _hb_options;
static inline hb_options_t
hb_options (void)
hb_options ()
{
#if defined(HB_NO_OPTIONS)
return hb_options_t ();
#endif
/* Make a local copy, so we can access bitfield threadsafely. */
hb_options_union_t u;
u.i = _hb_options.get_relaxed ();
@ -172,7 +176,7 @@ _hb_debug_msg_va (const char *what,
fprintf (stderr, "\n");
}
template <> inline void
template <> inline void HB_PRINTF_FUNC(7, 0)
_hb_debug_msg_va<0> (const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
@ -191,7 +195,7 @@ _hb_debug_msg (const char *what,
int level_dir,
const char *message,
...) HB_PRINTF_FUNC(7, 8);
template <int max_level> static inline void
template <int max_level> static inline void HB_PRINTF_FUNC(7, 8)
_hb_debug_msg (const char *what,
const void *obj,
const char *func,
@ -215,7 +219,7 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
...) HB_PRINTF_FUNC(7, 8);
template <> inline void
template <> inline void HB_PRINTF_FUNC(7, 8)
_hb_debug_msg<0> (const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
@ -283,7 +287,7 @@ struct hb_auto_trace_t
_hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
va_end (ap);
}
inline ~hb_auto_trace_t (void)
~hb_auto_trace_t ()
{
_hb_warn_no_return<ret_t> (returned);
if (!returned) {
@ -292,14 +296,16 @@ struct hb_auto_trace_t
if (plevel) --*plevel;
}
inline ret_t ret (ret_t v, unsigned int line = 0)
ret_t ret (ret_t v,
const char *func = "",
unsigned int line = 0)
{
if (unlikely (returned)) {
fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
return v;
}
_hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
"return %s (line %d)",
hb_printer_t<ret_t>().print (v), line);
if (plevel) --*plevel;
@ -324,17 +330,21 @@ struct hb_auto_trace_t<0, ret_t>
const char *message,
...) HB_PRINTF_FUNC(6, 7) {}
inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
ret_t ret (ret_t v,
const char *func HB_UNUSED = nullptr,
unsigned int line HB_UNUSED = 0) { return v; }
};
/* For disabled tracing; optimize out everything.
* https://github.com/harfbuzz/harfbuzz/pull/605 */
template <typename ret_t>
struct hb_no_trace_t {
inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
ret_t ret (ret_t v,
const char *func HB_UNUSED = "",
unsigned int line HB_UNUSED = 0) { return v; }
};
#define return_trace(RET) return trace.ret (RET, __LINE__)
#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
/*
@ -394,30 +404,6 @@ struct hb_no_trace_t {
#define TRACE_APPLY(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif
#if HB_DEBUG_CLOSURE
#define TRACE_CLOSURE(this) \
hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
" ")
#else
#define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
#endif
#ifndef HB_DEBUG_COLLECT_GLYPHS
#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
#endif
#if HB_DEBUG_COLLECT_GLYPHS
#define TRACE_COLLECT_GLYPHS(this) \
hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
" ")
#else
#define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
#endif
#ifndef HB_DEBUG_SANITIZE
#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
#endif
@ -454,27 +440,12 @@ struct hb_no_trace_t {
#define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_WOULD_APPLY
#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
#endif
#if HB_DEBUG_WOULD_APPLY
#define TRACE_WOULD_APPLY(this) \
hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
"%d glyphs", c->len);
#else
#define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_DISPATCH
#define HB_DEBUG_DISPATCH ( \
HB_DEBUG_APPLY + \
HB_DEBUG_CLOSURE + \
HB_DEBUG_COLLECT_GLYPHS + \
HB_DEBUG_SANITIZE + \
HB_DEBUG_SERIALIZE + \
HB_DEBUG_SUBSET + \
HB_DEBUG_WOULD_APPLY + \
HB_DEBUG_SUBSET + \
0)
#endif
#if HB_DEBUG_DISPATCH

View File

@ -36,10 +36,23 @@
#include "hb-font.h"
#include "hb-set.h"
/**
* SECTION:hb-deprecated
* @title: hb-deprecated
* @short_description: Deprecated API
* @include: hb.h
*
* These API have been deprecated in favor of newer API, or because they
* were deemed unnecessary.
**/
HB_BEGIN_DECLS
#ifndef HB_DISABLE_DEPRECATED
#define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS
#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
@ -50,14 +63,162 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t *glyph,
void *user_data);
HB_EXTERN void
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN void
HB_EXTERN HB_DEPRECATED void
hb_set_invert (hb_set_t *set);
/**
* hb_unicode_eastasian_width_func_t:
*
* Deprecated: 2.0.0
*/
typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode,
void *user_data);
/**
* hb_unicode_funcs_set_eastasian_width_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN HB_DEPRECATED void
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_eastasian_width_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_unicode_eastasian_width:
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN HB_DEPRECATED unsigned int
hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t unicode);
/**
* hb_unicode_decompose_compatibility_func_t:
* @ufuncs: a Unicode function structure
* @u: codepoint to decompose
* @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
* @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
*
* Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
* The complete length of the decomposition will be returned.
*
* If @u has no compatibility decomposition, zero should be returned.
*
* The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
* compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations
* of this function type must ensure that they do not write past the provided array.
*
* Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available.
*
* Deprecated: 2.0.0
*/
typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t u,
hb_codepoint_t *decomposed,
void *user_data);
/**
* HB_UNICODE_MAX_DECOMPOSITION_LEN:
*
* See Unicode 6.1 for details on the maximum decomposition length.
*
* Deprecated: 2.0.0
*/
#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
/**
* hb_unicode_funcs_set_decompose_compatibility_func:
* @ufuncs: a Unicode function structure
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN HB_DEPRECATED void
hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
hb_unicode_decompose_compatibility_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN HB_DEPRECATED unsigned int
hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t u,
hb_codepoint_t *decomposed);
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN void
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
#endif
HB_END_DECLS

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2015-2018 Ebrahim Byagowi
* Copyright © 2015-2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
@ -23,7 +23,6 @@
*/
#include "hb.hh"
#define HB_SHAPER directwrite
#include "hb-shaper-impl.hh"
#include <DWrite_1.h>
@ -31,18 +30,14 @@
#include "hb-directwrite.h"
HB_SHAPER_DATA_ENSURE_DEFINE (directwrite, face)
HB_SHAPER_DATA_ENSURE_DEFINE (directwrite, font)
/*
* hb-directwrite uses new/delete syntatically but as we let users
* to override malloc/free, we will redefine new/delete so users
* won't need to do that by their own.
*/
void* operator new (size_t size) { return malloc (size); }
void* operator new [] (size_t size) { return malloc (size); }
void operator delete (void* pointer) { free (pointer); }
void* operator new (size_t size) { return malloc (size); }
void* operator new [] (size_t size) { return malloc (size); }
void operator delete (void* pointer) { free (pointer); }
void operator delete [] (void* pointer) { free (pointer); }
@ -59,23 +54,25 @@ private:
IDWriteFontFileStream *mFontFileStream;
public:
DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream)
{
mFontFileStream = fontFileStream;
}
{ mFontFileStream = fontFileStream; }
// IUnknown interface
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD_ (ULONG, Release) () { return 1; }
// IDWriteFontFileLoader methods
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey (void const* fontFileReferenceKey,
uint32_t fontFileReferenceKeySize,
OUT IDWriteFontFileStream** fontFileStream)
virtual HRESULT STDMETHODCALLTYPE
CreateStreamFromKey (void const* fontFileReferenceKey,
uint32_t fontFileReferenceKeySize,
OUT IDWriteFontFileStream** fontFileStream)
{
*fontFileStream = mFontFileStream;
return S_OK;
}
virtual ~DWriteFontFileLoader() {}
};
class DWriteFontFileStream : public IDWriteFontFileStream
@ -91,19 +88,20 @@ public:
}
// IUnknown interface
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD_ (ULONG, Release) () { return 1; }
// IDWriteFontFileStream methods
virtual HRESULT STDMETHODCALLTYPE ReadFileFragment (void const** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
OUT void** fragmentContext)
virtual HRESULT STDMETHODCALLTYPE
ReadFileFragment (void const** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
OUT void** fragmentContext)
{
// We are required to do bounds checking.
if (fileOffset + fragmentSize > mSize)
return E_FAIL;
if (fileOffset + fragmentSize > mSize) return E_FAIL;
// truncate the 64 bit fileOffset to size_t sized index into mData
size_t index = static_cast<size_t> (fileOffset);
@ -114,18 +112,20 @@ public:
return S_OK;
}
virtual void STDMETHODCALLTYPE ReleaseFileFragment (void* fragmentContext) { }
virtual void STDMETHODCALLTYPE
ReleaseFileFragment (void* fragmentContext) {}
virtual HRESULT STDMETHODCALLTYPE GetFileSize (OUT UINT64* fileSize)
virtual HRESULT STDMETHODCALLTYPE
GetFileSize (OUT UINT64* fileSize)
{
*fileSize = mSize;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime (OUT UINT64* lastWriteTime)
{
return E_NOTIMPL;
}
virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
virtual ~DWriteFontFileStream() {}
};
@ -137,8 +137,8 @@ struct hb_directwrite_face_data_t
{
IDWriteFactory *dwriteFactory;
IDWriteFontFile *fontFile;
IDWriteFontFileStream *fontFileStream;
IDWriteFontFileLoader *fontFileLoader;
DWriteFontFileStream *fontFileStream;
DWriteFontFileLoader *fontFileLoader;
IDWriteFontFace *fontFace;
hb_blob_t *faceBlob;
};
@ -152,17 +152,14 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory
);
DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
HRESULT hr;
hb_blob_t *blob = hb_face_reference_blob (face);
DWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
(uint8_t *) hb_blob_get_data (blob, nullptr),
hb_blob_get_length (blob));
DWriteFontFileStream *fontFileStream;
fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
hb_blob_get_length (blob));
DWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
@ -170,7 +167,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
IDWriteFontFile *fontFile;
uint64_t fontFileKey = 0;
hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
fontFileLoader, &fontFile);
fontFileLoader, &fontFile);
#define FAIL(...) \
HB_STMT_START { \
@ -193,7 +190,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
IDWriteFontFace *fontFace;
dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
data->dwriteFactory = dwriteFactory;
data->fontFile = fontFile;
@ -233,15 +230,11 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
* shaper font data
*/
struct hb_directwrite_font_data_t
{
};
struct hb_directwrite_font_data_t {};
hb_directwrite_font_data_t *
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
{
if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t;
if (unlikely (!data))
return nullptr;
@ -256,35 +249,14 @@ _hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
}
/*
* shaper shape_plan data
*/
struct hb_directwrite_shape_plan_data_t {};
hb_directwrite_shape_plan_data_t *
_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_directwrite_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shape_plan_data_t *data HB_UNUSED)
{
}
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
// but now is relicensed to MIT for HarfBuzz use
class TextAnalysis
: public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
{
public:
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
{ return S_OK; }
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
IFACEMETHOD_ (ULONG, Release) () { return 1; }
@ -301,7 +273,7 @@ public:
uint8_t mBidiLevel;
bool mIsSideways;
inline bool ContainsTextPosition (uint32_t aTextPosition) const
bool ContainsTextPosition (uint32_t aTextPosition) const
{
return aTextPosition >= mTextStart &&
aTextPosition < mTextStart + mTextLength;
@ -311,16 +283,10 @@ public:
};
public:
TextAnalysis (const wchar_t* text,
uint32_t textLength,
const wchar_t* localeName,
DWRITE_READING_DIRECTION readingDirection)
: mText (text)
, mTextLength (textLength)
, mLocaleName (localeName)
, mReadingDirection (readingDirection)
, mCurrentRun (nullptr) { };
TextAnalysis (const wchar_t* text, uint32_t textLength,
const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
: mTextLength (textLength), mText (text), mLocaleName (localeName),
mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
~TextAnalysis ()
{
// delete runs, except mRunHead which is part of the TextAnalysis object
@ -332,8 +298,8 @@ public:
}
}
STDMETHODIMP GenerateResults (IDWriteTextAnalyzer* textAnalyzer,
Run **runHead)
STDMETHODIMP
GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
{
// Analyzes the text using the script analyzer and returns
// the result as a series of runs.
@ -358,9 +324,10 @@ public:
// IDWriteTextAnalysisSource implementation
IFACEMETHODIMP GetTextAtPosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
IFACEMETHODIMP
GetTextAtPosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition >= mTextLength)
{
@ -376,9 +343,10 @@ public:
return S_OK;
}
IFACEMETHODIMP GetTextBeforePosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
IFACEMETHODIMP
GetTextBeforePosition (uint32_t textPosition,
OUT wchar_t const** textString,
OUT uint32_t* textLength)
{
if (textPosition == 0 || textPosition > mTextLength)
{
@ -396,19 +364,16 @@ public:
}
IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
GetParagraphReadingDirection () { return mReadingDirection; }
GetParagraphReadingDirection () { return mReadingDirection; }
IFACEMETHODIMP GetLocaleName (uint32_t textPosition,
uint32_t* textLength,
wchar_t const** localeName)
{
return S_OK;
}
IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
wchar_t const** localeName)
{ return S_OK; }
IFACEMETHODIMP
GetNumberSubstitution (uint32_t textPosition,
OUT uint32_t* textLength,
OUT IDWriteNumberSubstitution** numberSubstitution)
GetNumberSubstitution (uint32_t textPosition,
OUT uint32_t* textLength,
OUT IDWriteNumberSubstitution** numberSubstitution)
{
// We do not support number substitution.
*numberSubstitution = nullptr;
@ -420,9 +385,8 @@ public:
// IDWriteTextAnalysisSink implementation
IFACEMETHODIMP
SetScriptAnalysis (uint32_t textPosition,
uint32_t textLength,
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
{
SetCurrentRun (textPosition);
SplitCurrentRun (textPosition);
@ -436,19 +400,19 @@ public:
}
IFACEMETHODIMP
SetLineBreakpoints (uint32_t textPosition,
uint32_t textLength,
const DWRITE_LINE_BREAKPOINT* lineBreakpoints) { return S_OK; }
SetLineBreakpoints (uint32_t textPosition,
uint32_t textLength,
const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
{ return S_OK; }
IFACEMETHODIMP SetBidiLevel (uint32_t textPosition,
uint32_t textLength,
uint8_t explicitLevel,
uint8_t resolvedLevel) { return S_OK; }
IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
uint8_t explicitLevel, uint8_t resolvedLevel)
{ return S_OK; }
IFACEMETHODIMP
SetNumberSubstitution (uint32_t textPosition,
uint32_t textLength,
IDWriteNumberSubstitution* numberSubstitution) { return S_OK; }
SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
IDWriteNumberSubstitution* numberSubstitution)
{ return S_OK; }
protected:
Run *FetchNextRun (IN OUT uint32_t* textLength)
@ -548,15 +512,14 @@ static inline uint32_t hb_uint32_swap (const uint32_t v)
static hb_bool_t
_hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float lineWidth)
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float lineWidth)
{
hb_face_t *face = font->face;
hb_directwrite_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
hb_directwrite_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
const hb_directwrite_face_data_t *face_data = face->data.directwrite;
IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
IDWriteFontFace *fontFace = face_data->fontFace;
@ -608,9 +571,10 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
DWRITE_READING_DIRECTION readingDirection;
readingDirection = buffer->props.direction ?
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
/*
* There's an internal 16-bit limit on some things inside the analyzer,
@ -639,10 +603,8 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
const wchar_t localeName[20] = {0};
if (buffer->props.language != nullptr)
{
mbstowcs ((wchar_t*) localeName,
hb_language_to_string (buffer->props.language), 20);
}
hb_language_to_string (buffer->props.language), 20);
// TODO: it does work but doesn't care about ranges
DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
@ -653,27 +615,29 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
for (unsigned int i = 0; i < num_features; ++i)
{
typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
hb_uint32_swap (features[i].tag);
hb_uint32_swap (features[i].tag);
typographic_features.features[i].parameter = features[i].value;
}
}
const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures =
(const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures;
dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
const uint32_t featureRangeLengths[] = { textLength };
//
uint16_t* clusterMap = new uint16_t[textLength];
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties =
new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
uint16_t* clusterMap;
clusterMap = new uint16_t[textLength];
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
retry_getglyphs:
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties =
new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures,
featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
glyphProperties, &glyphCount);
isRightToLeft, &runHead->mScript, localeName,
nullptr, &dwFeatures, featureRangeLengths, 1,
maxGlyphCount, clusterMap, textProperties,
glyphIndices, glyphProperties, &glyphCount);
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
{
@ -693,30 +657,28 @@ retry_getglyphs:
/* The -2 in the following is to compensate for possible
* alignment needed after the WORD array. sizeof (WORD) == 2. */
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
/ (sizeof (WORD) +
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof (int) +
sizeof (DWRITE_GLYPH_OFFSET) +
sizeof (uint32_t));
/ (sizeof (WORD) +
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof (int) +
sizeof (DWRITE_GLYPH_OFFSET) +
sizeof (uint32_t));
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#undef ALLOCATE_ARRAY
int fontEmSize = font->face->get_upem ();
if (fontEmSize < 0)
fontEmSize = -fontEmSize;
if (fontEmSize < 0) fontEmSize = -fontEmSize;
if (fontEmSize < 0)
fontEmSize = -fontEmSize;
if (fontEmSize < 0) fontEmSize = -fontEmSize;
double x_mult = (double) font->x_scale / fontEmSize;
double y_mult = (double) font->y_scale / fontEmSize;
hr = analyzer->GetGlyphPlacements (textString,
clusterMap, textProperties, textLength, glyphIndices,
glyphProperties, glyphCount, fontFace, fontEmSize,
false, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties,
textLength, glyphIndices, glyphProperties,
glyphCount, fontFace, fontEmSize,
false, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
if (FAILED (hr))
FAIL ("Analyzer failed to get glyph placements.");
@ -726,12 +688,12 @@ retry_getglyphs:
if (analyzer1 && lineWidth)
{
DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount];
hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
runHead->mScript, textLength, glyphCount, textString, clusterMap,
glyphProperties, justificationOpportunities);
hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, runHead->mScript,
textLength, glyphCount, textString,
clusterMap, glyphProperties,
justificationOpportunities);
if (FAILED (hr))
FAIL ("Analyzer failed to get justification opportunities.");
@ -739,15 +701,14 @@ retry_getglyphs:
float* justifiedGlyphAdvances = new float[maxGlyphCount];
DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount];
hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
glyphAdvances, glyphOffsets, justifiedGlyphAdvances,
justifiedGlyphOffsets);
if (FAILED (hr))
FAIL ("Analyzer failed to get justified glyph advances.");
if (FAILED (hr)) FAIL ("Analyzer failed to get justify glyph advances.");
DWRITE_SCRIPT_PROPERTIES scriptProperties;
hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
if (FAILED (hr))
FAIL ("Analyzer failed to get script properties.");
if (FAILED (hr)) FAIL ("Analyzer failed to get script properties.");
uint32_t justificationCharacter = scriptProperties.justificationCharacter;
// if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
@ -757,14 +718,15 @@ retry_getglyphs:
retry_getjustifiedglyphs:
uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount];
float* modifiedGlyphAdvances = new float[maxGlyphCount];
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets =
new DWRITE_GLYPH_OFFSET[maxGlyphCount];
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
uint32_t actualGlyphsCount;
hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
modifiedGlyphAdvances, modifiedGlyphOffsets);
textLength, glyphCount, maxGlyphCount,
clusterMap, glyphIndices, glyphAdvances,
justifiedGlyphAdvances, justifiedGlyphOffsets,
glyphProperties, &actualGlyphsCount,
modifiedClusterMap, modifiedGlyphIndices,
modifiedGlyphAdvances, modifiedGlyphOffsets);
if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
{
@ -804,7 +766,6 @@ retry_getglyphs:
}
delete [] justificationOpportunities;
}
/* Ok, we've got everything we need, now compose output buffer,
@ -812,7 +773,7 @@ retry_getglyphs:
/* Calculate visual-clusters. That's what we ship. */
for (unsigned int i = 0; i < glyphCount; i++)
vis_clusters[i] = -1;
vis_clusters[i] = (uint32_t) -1;
for (unsigned int i = 0; i < buffer->len; i++)
{
uint32_t *p =
@ -820,7 +781,7 @@ retry_getglyphs:
*p = MIN (*p, buffer->info[i].cluster);
}
for (unsigned int i = 1; i < glyphCount; i++)
if (vis_clusters[i] == -1)
if (vis_clusters[i] == (uint32_t) -1)
vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
@ -854,13 +815,11 @@ retry_getglyphs:
/* TODO vertical */
pos->x_advance = x_mult * (int32_t) info->mask;
pos->x_offset =
x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
pos->x_offset = x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
pos->y_offset = y_mult * info->var2.i32;
}
if (isRightToLeft)
hb_buffer_reverse (buffer);
if (isRightToLeft) hb_buffer_reverse (buffer);
delete [] clusterMap;
delete [] glyphIndices;
@ -878,33 +837,120 @@ retry_getglyphs:
hb_bool_t
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_directwrite_shape_full (shape_plan, font, buffer,
features, num_features, 0);
features, num_features, 0);
}
/*
* Public [experimental] API
*/
/**
* hb_directwrite_shape_experimental_width:
* Experimental API to test DirectWrite's justification algorithm.
*
* It inserts Kashida at wrong order so don't use the API ever.
*
* It doesn't work with cygwin/msys due to header bugs so one
* should use MSVC toolchain in order to use it for now.
*
* @font:
* @buffer:
* @features:
* @num_features:
* @width:
*
* Since: 1.4.2
**/
hb_bool_t
hb_directwrite_shape_experimental_width (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float width)
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float width)
{
static const char *shapers = "directwrite";
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
&buffer->props, features, num_features, &shapers);
hb_shape_plan_t *shape_plan;
shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
features, num_features, &shapers);
hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
features, num_features, width);
features, num_features, width);
buffer->unsafe_to_break_all ();
return res;
}
struct _hb_directwrite_font_table_context {
IDWriteFontFace *face;
void *table_context;
};
static void
_hb_directwrite_table_data_release (void *data)
{
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
context->face->ReleaseFontTable (context->table_context);
delete context;
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
const void *data;
uint32_t length;
void *table_context;
BOOL exists;
if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
&length, &table_context, &exists)))
return nullptr;
if (!data || !exists || !length)
{
dw_face->ReleaseFontTable (table_context);
return nullptr;
}
_hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
context->face = dw_face;
context->table_context = table_context;
return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
context, _hb_directwrite_table_data_release);
}
static void
_hb_directwrite_font_release (void *data)
{
if (data)
((IDWriteFontFace *) data)->Release ();
}
/**
* hb_directwrite_face_create:
* @font_face:
*
* Since: 2.4.0
**/
hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *font_face)
{
if (font_face)
font_face->AddRef ();
return hb_face_create_for_tables (reference_table, font_face,
_hb_directwrite_font_release);
}
/**
* hb_directwrite_face_get_font_face:
* @face:
*
* Since: REPLACEME
**/
IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face)
{
return face->data.directwrite->fontFace;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright © 2015 Ebrahim Byagowi
* Copyright © 2015-2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
@ -34,6 +34,12 @@ hb_directwrite_shape_experimental_width (hb_font_t *font, hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features, float width);
HB_EXTERN hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *font_face);
HB_EXTERN IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face);
HB_END_DECLS
#endif /* HB_DIRECTWRITE_H */

50
src/hb-dispatch.hh Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
* Copyright © 2012,2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_DISPATCH_HH
#define HB_DISPATCH_HH
#include "hb.hh"
/*
* Dispatch
*/
template <typename Context, typename Return, unsigned int MaxDebugDepth>
struct hb_dispatch_context_t
{
static constexpr unsigned max_debug_depth = MaxDebugDepth;
typedef Return return_t;
template <typename T, typename F>
bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
};
#endif /* HB_DISPATCH_HH */

View File

@ -35,6 +35,19 @@
#include "hb-ot-cmap-table.hh"
/**
* SECTION:hb-face
* @title: hb-face
* @short_description: Font face objects
* @include: hb.h
*
* Font face is objects represent a single face in a font family.
* More exactly, a font face represents a single face in a binary font file.
* Font faces are typically built from a binary blob and a face index.
* Font faces are used to create fonts.
**/
/**
* hb_face_count:
* @blob: a blob.
@ -69,23 +82,15 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
{
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
nullptr, /* reference_table_func */
nullptr, /* user_data */
nullptr, /* destroy */
0, /* index */
1000, /* upem */
0, /* num_glyphs */
HB_ATOMIC_INT_INIT (1000), /* upem */
HB_ATOMIC_INT_INIT (0), /* num_glyphs */
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
},
HB_ATOMIC_PTR_INIT (nullptr), /* shape_plans */
/* Zero for the rest is fine. */
};
@ -118,8 +123,10 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
face->user_data = user_data;
face->destroy = destroy;
face->upem = 0;
face->num_glyphs = (unsigned int) -1;
face->num_glyphs.set_relaxed (-1);
face->data.init0 (face);
face->table.init0 (face);
return face;
}
@ -217,7 +224,7 @@ hb_face_create (hb_blob_t *blob,
* Since: 0.9.2
**/
hb_face_t *
hb_face_get_empty (void)
hb_face_get_empty ()
{
return const_cast<hb_face_t *> (&Null(hb_face_t));
}
@ -252,7 +259,7 @@ hb_face_destroy (hb_face_t *face)
{
if (!hb_object_destroy (face)) return;
for (hb_face_t::plan_node_t *node = face->shape_plans.get (); node; )
for (hb_face_t::plan_node_t *node = face->shape_plans; node; )
{
hb_face_t::plan_node_t *next = node->next;
hb_shape_plan_destroy (node->shape_plan);
@ -260,9 +267,8 @@ hb_face_destroy (hb_face_t *face)
node = next;
}
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
face->data.fini ();
face->table.fini ();
if (face->destroy)
face->destroy (face->user_data);
@ -323,12 +329,10 @@ hb_face_get_user_data (const hb_face_t *face,
void
hb_face_make_immutable (hb_face_t *face)
{
if (unlikely (hb_object_is_inert (face)))
return;
if (face->immutable)
if (hb_object_is_immutable (face))
return;
face->immutable = true;
hb_object_make_immutable (face);
}
/**
@ -344,7 +348,7 @@ hb_face_make_immutable (hb_face_t *face)
hb_bool_t
hb_face_is_immutable (const hb_face_t *face)
{
return face->immutable;
return hb_object_is_immutable (face);
}
@ -395,7 +399,7 @@ void
hb_face_set_index (hb_face_t *face,
unsigned int index)
{
if (face->immutable)
if (hb_object_is_immutable (face))
return;
face->index = index;
@ -430,10 +434,10 @@ void
hb_face_set_upem (hb_face_t *face,
unsigned int upem)
{
if (face->immutable)
if (hb_object_is_immutable (face))
return;
face->upem = upem;
face->upem.set_relaxed (upem);
}
/**
@ -465,10 +469,10 @@ void
hb_face_set_glyph_count (hb_face_t *face,
unsigned int glyph_count)
{
if (face->immutable)
if (hb_object_is_immutable (face))
return;
face->num_glyphs = glyph_count;
face->num_glyphs.set_relaxed (glyph_count);
}
/**
@ -538,8 +542,7 @@ void
hb_face_collect_unicodes (hb_face_t *face,
hb_set_t *out)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
hb_ot_face_data (face)->cmap->collect_unicodes (out);
face->table.cmap->collect_unicodes (out);
}
/**
@ -555,8 +558,7 @@ void
hb_face_collect_variation_selectors (hb_face_t *face,
hb_set_t *out)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
hb_ot_face_data (face)->cmap->collect_variation_selectors (out);
face->table.cmap->collect_variation_selectors (out);
}
/**
@ -573,8 +575,7 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
hb_codepoint_t variation_selector,
hb_set_t *out)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;
hb_ot_face_data (face)->cmap->collect_variation_unicodes (variation_selector, out);
face->table.cmap->collect_variation_unicodes (variation_selector, out);
}
@ -587,10 +588,10 @@ struct hb_face_builder_data_t
{
struct table_entry_t
{
inline int cmp (const hb_tag_t *t) const
int cmp (hb_tag_t t) const
{
if (*t < tag) return -1;
if (*t > tag) return -1;
if (t < tag) return -1;
if (t > tag) return -1;
return 0;
}
@ -598,11 +599,11 @@ struct hb_face_builder_data_t
hb_blob_t *blob;
};
hb_vector_t<table_entry_t, 32> tables;
hb_vector_t<table_entry_t> tables;
};
static hb_face_builder_data_t *
_hb_face_builder_data_create (void)
_hb_face_builder_data_create ()
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
if (unlikely (!data))
@ -618,7 +619,7 @@ _hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (unsigned int i = 0; i < data->tables.len; i++)
for (unsigned int i = 0; i < data->tables.length; i++)
hb_blob_destroy (data->tables[i].blob);
data->tables.fini ();
@ -630,29 +631,24 @@ static hb_blob_t *
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
{
unsigned int table_count = data->tables.len;
unsigned int table_count = data->tables.length;
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables.arrayZ[i].blob));
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
char *buf = (char *) malloc (face_length);
if (unlikely (!buf))
return nullptr;
hb_serialize_context_t c (buf, face_length);
c.propagate_error (data->tables);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
bool ret = f->serialize_single (&c,
sfnt_tag,
tags_supplier,
blobs_supplier,
table_count);
bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
c.end_serialize ();
@ -666,7 +662,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
}
static hb_blob_t *
_hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data)
_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
@ -688,12 +684,12 @@ _hb_face_builder_reference_table (hb_face_t *face, hb_tag_t tag, void *user_data
* After tables are added to the face, it can be compiled to a binary
* font file by calling hb_face_reference_blob().
*
* Return value: (transfer full) New face.
* Return value: (transfer full): New face.
*
* Since: 1.9.0
**/
hb_face_t *
hb_face_builder_create (void)
hb_face_builder_create ()
{
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
if (unlikely (!data)) return hb_face_get_empty ();

View File

@ -33,28 +33,31 @@
#include "hb-shaper.hh"
#include "hb-shape-plan.hh"
#include "hb-ot-face.hh"
/*
* hb_face_t
*/
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, face);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
struct hb_face_t
{
hb_object_header_t header;
ASSERT_POD ();
hb_bool_t immutable;
hb_reference_table_func_t reference_table_func;
void *user_data;
hb_destroy_func_t destroy;
unsigned int index; /* Face index in a collection, zero-based. */
mutable unsigned int upem; /* Units-per-EM. */
mutable unsigned int num_glyphs; /* Number of glyphs. */
mutable hb_atomic_int_t upem; /* Units-per-EM. */
mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
struct hb_shaper_data_t shaper_data; /* Various shaper data. */
hb_shaper_object_dataset_t<hb_face_t> data;/* Various shaper data. */
hb_ot_face_t table; /* All the face's tables. */
/* Cache */
struct plan_node_t
@ -64,7 +67,7 @@ struct hb_face_t
};
hb_atomic_ptr_t<plan_node_t> shape_plans;
inline hb_blob_t *reference_table (hb_tag_t tag) const
hb_blob_t *reference_table (hb_tag_t tag) const
{
hb_blob_t *blob;
@ -78,31 +81,29 @@ struct hb_face_t
return blob;
}
inline HB_PURE_FUNC unsigned int get_upem (void) const
HB_PURE_FUNC unsigned int get_upem () const
{
if (unlikely (!upem))
load_upem ();
return upem;
unsigned int ret = upem.get_relaxed ();
if (unlikely (!ret))
{
return load_upem ();
}
return ret;
}
inline unsigned int get_num_glyphs (void) const
unsigned int get_num_glyphs () const
{
if (unlikely (num_glyphs == (unsigned int) -1))
load_num_glyphs ();
return num_glyphs;
unsigned int ret = num_glyphs.get_relaxed ();
if (unlikely (ret == (unsigned int) -1))
return load_num_glyphs ();
return ret;
}
private:
HB_INTERNAL void load_upem (void) const;
HB_INTERNAL void load_num_glyphs (void) const;
HB_INTERNAL unsigned int load_upem () const;
HB_INTERNAL unsigned int load_num_glyphs () const;
};
DECLARE_NULL_INSTANCE (hb_face_t);
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#endif /* HB_FACE_HH */

View File

@ -24,14 +24,9 @@
* Google Author(s): Behdad Esfahbod
*/
#define HB_SHAPER fallback
#include "hb-shaper-impl.hh"
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font)
/*
* shaper face data
*/
@ -68,28 +63,6 @@ _hb_fallback_shaper_font_data_destroy (hb_fallback_font_data_t *data HB_UNUSED)
}
/*
* shaper shape_plan data
*/
struct hb_fallback_shape_plan_data_t {};
hb_fallback_shape_plan_data_t *
_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_fallback_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
void
_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shape_plan_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/

View File

@ -31,6 +31,21 @@
#include "hb-font.hh"
#include "hb-machinery.hh"
#include "hb-ot.h"
/**
* SECTION:hb-font
* @title: hb-font
* @short_description: Font objects
* @include: hb.h
*
* Font objects represent a font face at a certain size and other
* parameters (pixels per EM, points per EM, variation settings.)
* Fonts are created from font faces, and are used as input to
* hb_shape() among other things.
**/
/*
* hb_font_funcs_t
@ -39,23 +54,23 @@
static hb_bool_t
hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
memset (metrics, 0, sizeof (*metrics));
memset (extents, 0, sizeof (*extents));
return false;
}
static hb_bool_t
hb_font_get_font_h_extents_default (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_font_h_extents (metrics);
hb_bool_t ret = font->parent->get_font_h_extents (extents);
if (ret) {
metrics->ascender = font->parent_scale_y_distance (metrics->ascender);
metrics->descender = font->parent_scale_y_distance (metrics->descender);
metrics->line_gap = font->parent_scale_y_distance (metrics->line_gap);
extents->ascender = font->parent_scale_y_distance (extents->ascender);
extents->descender = font->parent_scale_y_distance (extents->descender);
extents->line_gap = font->parent_scale_y_distance (extents->line_gap);
}
return ret;
}
@ -63,23 +78,23 @@ hb_font_get_font_h_extents_default (hb_font_t *font,
static hb_bool_t
hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
memset (metrics, 0, sizeof (*metrics));
memset (extents, 0, sizeof (*extents));
return false;
}
static hb_bool_t
hb_font_get_font_v_extents_default (hb_font_t *font,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
hb_font_extents_t *extents,
void *user_data HB_UNUSED)
{
hb_bool_t ret = font->parent->get_font_v_extents (metrics);
hb_bool_t ret = font->parent->get_font_v_extents (extents);
if (ret) {
metrics->ascender = font->parent_scale_x_distance (metrics->ascender);
metrics->descender = font->parent_scale_x_distance (metrics->descender);
metrics->line_gap = font->parent_scale_x_distance (metrics->line_gap);
extents->ascender = font->parent_scale_x_distance (extents->ascender);
extents->descender = font->parent_scale_x_distance (extents->descender);
extents->line_gap = font->parent_scale_x_distance (extents->line_gap);
}
return ret;
}
@ -87,7 +102,7 @@ hb_font_get_font_v_extents_default (hb_font_t *font,
static hb_bool_t
hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t unicode,
hb_codepoint_t unicode HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
@ -101,14 +116,47 @@ hb_font_get_nominal_glyph_default (hb_font_t *font,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
if (font->has_nominal_glyphs_func_set ())
{
return font->get_nominal_glyphs (1, &unicode, 0, glyph, 0);
}
return font->parent->get_nominal_glyph (unicode, glyph);
}
#define hb_font_get_nominal_glyphs_nil hb_font_get_nominal_glyphs_default
static unsigned int
hb_font_get_nominal_glyphs_default (hb_font_t *font,
void *font_data HB_UNUSED,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
if (font->has_nominal_glyph_func_set ())
{
for (unsigned int i = 0; i < count; i++)
{
if (!font->get_nominal_glyph (*first_unicode, first_glyph))
return i;
first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
}
return count;
}
return font->parent->get_nominal_glyphs (count,
first_unicode, unicode_stride,
first_glyph, glyph_stride);
}
static hb_bool_t
hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t unicode,
hb_codepoint_t variation_selector,
hb_codepoint_t unicode HB_UNUSED,
hb_codepoint_t variation_selector HB_UNUSED,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
@ -141,6 +189,12 @@ hb_font_get_glyph_h_advance_default (hb_font_t *font,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
if (font->has_glyph_h_advances_func_set ())
{
hb_position_t ret;
font->get_glyph_h_advances (1, &glyph, 0, &ret, 0);
return ret;
}
return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
}
@ -159,6 +213,12 @@ hb_font_get_glyph_v_advance_default (hb_font_t *font,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
if (font->has_glyph_v_advances_func_set ())
{
hb_position_t ret;
font->get_glyph_v_advances (1, &glyph, 0, &ret, 0);
return ret;
}
return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
}
@ -167,19 +227,19 @@ static void
hb_font_get_glyph_h_advances_default (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned int count,
hb_codepoint_t *first_glyph,
const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride,
void *user_data HB_UNUSED)
{
if (font->has_glyph_h_advance_func ())
if (font->has_glyph_h_advance_func_set ())
{
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->get_glyph_h_advance (*first_glyph);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
return;
}
@ -190,7 +250,7 @@ hb_font_get_glyph_h_advances_default (hb_font_t* font,
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->parent_scale_x_distance (*first_advance);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
@ -199,19 +259,19 @@ static void
hb_font_get_glyph_v_advances_default (hb_font_t* font,
void* font_data HB_UNUSED,
unsigned int count,
hb_codepoint_t *first_glyph,
const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride,
void *user_data HB_UNUSED)
{
if (font->has_glyph_v_advance_func ())
if (font->has_glyph_v_advance_func_set ())
{
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->get_glyph_v_advance (*first_glyph);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
return;
}
@ -222,14 +282,14 @@ hb_font_get_glyph_v_advances_default (hb_font_t* font,
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->parent_scale_y_distance (*first_advance);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
static hb_bool_t
hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_codepoint_t glyph HB_UNUSED,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
@ -254,7 +314,7 @@ hb_font_get_glyph_h_origin_default (hb_font_t *font,
static hb_bool_t
hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_codepoint_t glyph HB_UNUSED,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
@ -279,8 +339,8 @@ hb_font_get_glyph_v_origin_default (hb_font_t *font,
static hb_position_t
hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
hb_codepoint_t left_glyph HB_UNUSED,
hb_codepoint_t right_glyph HB_UNUSED,
void *user_data HB_UNUSED)
{
return 0;
@ -298,8 +358,8 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font,
static hb_position_t
hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t top_glyph,
hb_codepoint_t bottom_glyph,
hb_codepoint_t top_glyph HB_UNUSED,
hb_codepoint_t bottom_glyph HB_UNUSED,
void *user_data HB_UNUSED)
{
return 0;
@ -317,7 +377,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font,
static hb_bool_t
hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_codepoint_t glyph HB_UNUSED,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
@ -342,8 +402,8 @@ hb_font_get_glyph_extents_default (hb_font_t *font,
static hb_bool_t
hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
unsigned int point_index,
hb_codepoint_t glyph HB_UNUSED,
unsigned int point_index HB_UNUSED,
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
@ -369,7 +429,7 @@ hb_font_get_glyph_contour_point_default (hb_font_t *font,
static hb_bool_t
hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_codepoint_t glyph,
hb_codepoint_t glyph HB_UNUSED,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
@ -389,7 +449,8 @@ hb_font_get_glyph_name_default (hb_font_t *font,
static hb_bool_t
hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
const char *name, int len, /* -1 means nul-terminated */
const char *name HB_UNUSED,
int len HB_UNUSED, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
@ -410,8 +471,6 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
{
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@ -434,8 +493,6 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
static const hb_font_funcs_t _hb_font_funcs_default = {
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
@ -466,7 +523,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = {
* Since: 0.9.2
**/
hb_font_funcs_t *
hb_font_funcs_create (void)
hb_font_funcs_create ()
{
hb_font_funcs_t *ffuncs;
@ -488,7 +545,7 @@ hb_font_funcs_create (void)
* Since: 0.9.2
**/
hb_font_funcs_t *
hb_font_funcs_get_empty (void)
hb_font_funcs_get_empty ()
{
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_default);
}
@ -584,12 +641,10 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
void
hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
{
if (unlikely (hb_object_is_inert (ffuncs)))
return;
if (ffuncs->immutable)
if (hb_object_is_immutable (ffuncs))
return;
ffuncs->immutable = true;
hb_object_make_immutable (ffuncs);
}
/**
@ -605,7 +660,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
hb_bool_t
hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs)
{
return ffuncs->immutable;
return hb_object_is_immutable (ffuncs);
}
@ -617,7 +672,7 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
void *user_data, \
hb_destroy_func_t destroy) \
{ \
if (ffuncs->immutable) { \
if (hb_object_is_immutable (ffuncs)) { \
if (destroy) \
destroy (user_data); \
return; \
@ -640,10 +695,16 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
bool
hb_font_t::has_func_set (unsigned int i)
{
return this->klass->get.array[i] != _hb_font_funcs_default.get.array[i];
}
bool
hb_font_t::has_func (unsigned int i)
{
return (this->klass->get.array[i] != _hb_font_funcs_default.get.array[i]) ||
return has_func_set (i) ||
(parent && parent != &_hb_Null_hb_font_t && parent->has_func (i));
}
@ -795,8 +856,8 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
**/
void
hb_font_get_glyph_h_advances (hb_font_t* font,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@ -813,8 +874,8 @@ hb_font_get_glyph_h_advances (hb_font_t* font,
**/
void
hb_font_get_glyph_v_advances (hb_font_t* font,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@ -875,6 +936,7 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
* Return value:
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
@ -894,6 +956,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
* Return value:
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
@ -993,7 +1056,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
* hb_font_get_extents_for_direction:
* @font: a font.
* @direction:
* @extents:
* @extents: (out):
*
*
*
@ -1038,8 +1101,8 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
HB_EXTERN void
hb_font_get_glyph_advances_for_direction (hb_font_t* font,
hb_direction_t direction,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
@ -1122,6 +1185,7 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@ -1229,8 +1293,6 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
{
HB_OBJECT_HEADER_STATIC,
true, /* immutable */
nullptr, /* parent */
const_cast<hb_face_t *> (&_hb_Null_hb_face_t),
@ -1244,18 +1306,32 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
0, /* num_coords */
nullptr, /* coords */
const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t), /* klass */
nullptr, /* user_data */
nullptr, /* destroy */
const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t),
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID),
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
}
/* Zero for the rest is fine. */
};
static hb_font_t *
_hb_font_create (hb_face_t *face)
{
hb_font_t *font;
if (unlikely (!face))
face = hb_face_get_empty ();
if (!(font = hb_object_create<hb_font_t> ()))
return hb_font_get_empty ();
hb_face_make_immutable (face);
font->parent = hb_font_get_empty ();
font->face = hb_face_reference (face);
font->klass = hb_font_funcs_get_empty ();
font->data.init0 (font);
font->x_scale = font->y_scale = hb_face_get_upem (face);
return font;
}
/**
* hb_font_create: (Xconstructor)
* @face: a face.
@ -1269,19 +1345,12 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
hb_font_t *
hb_font_create (hb_face_t *face)
{
hb_font_t *font;
hb_font_t *font = _hb_font_create (face);
if (unlikely (!face))
face = hb_face_get_empty ();
if (!(font = hb_object_create<hb_font_t> ()))
return hb_font_get_empty ();
hb_face_make_immutable (face);
font->parent = hb_font_get_empty ();
font->face = hb_face_reference (face);
font->klass = hb_font_funcs_get_empty ();
font->x_scale = font->y_scale = hb_face_get_upem (face);
#if !defined(HB_NO_OT_FONT)
/* Install our in-house, very lightweight, funcs. */
hb_ot_font_set_funcs (font);
#endif
return font;
}
@ -1302,9 +1371,9 @@ hb_font_create_sub_font (hb_font_t *parent)
if (unlikely (!parent))
parent = hb_font_get_empty ();
hb_font_t *font = hb_font_create (parent->face);
hb_font_t *font = _hb_font_create (parent->face);
if (unlikely (hb_object_is_inert (font)))
if (unlikely (hb_object_is_immutable (font)))
return font;
font->parent = hb_font_reference (parent);
@ -1341,7 +1410,7 @@ hb_font_create_sub_font (hb_font_t *parent)
* Since: 0.9.2
**/
hb_font_t *
hb_font_get_empty (void)
hb_font_get_empty ()
{
return const_cast<hb_font_t *> (&Null(hb_font_t));
}
@ -1375,9 +1444,7 @@ hb_font_destroy (hb_font_t *font)
{
if (!hb_object_destroy (font)) return;
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
font->data.fini ();
if (font->destroy)
font->destroy (font->user_data);
@ -1444,15 +1511,13 @@ hb_font_get_user_data (hb_font_t *font,
void
hb_font_make_immutable (hb_font_t *font)
{
if (unlikely (hb_object_is_inert (font)))
return;
if (font->immutable)
if (hb_object_is_immutable (font))
return;
if (font->parent)
hb_font_make_immutable (font->parent);
font->immutable = true;
hb_object_make_immutable (font);
}
/**
@ -1468,7 +1533,7 @@ hb_font_make_immutable (hb_font_t *font)
hb_bool_t
hb_font_is_immutable (hb_font_t *font)
{
return font->immutable;
return hb_object_is_immutable (font);
}
/**
@ -1484,7 +1549,7 @@ void
hb_font_set_parent (hb_font_t *font,
hb_font_t *parent)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
if (!parent)
@ -1526,7 +1591,7 @@ void
hb_font_set_face (hb_font_t *font,
hb_face_t *face)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
if (unlikely (!face))
@ -1573,7 +1638,8 @@ hb_font_set_funcs (hb_font_t *font,
void *font_data,
hb_destroy_func_t destroy)
{
if (font->immutable) {
if (hb_object_is_immutable (font))
{
if (destroy)
destroy (font_data);
return;
@ -1608,7 +1674,8 @@ hb_font_set_funcs_data (hb_font_t *font,
hb_destroy_func_t destroy)
{
/* Destroy user_data? */
if (font->immutable) {
if (hb_object_is_immutable (font))
{
if (destroy)
destroy (font_data);
return;
@ -1637,7 +1704,7 @@ hb_font_set_scale (hb_font_t *font,
int x_scale,
int y_scale)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
font->x_scale = x_scale;
@ -1678,7 +1745,7 @@ hb_font_set_ppem (hb_font_t *font,
unsigned int x_ppem,
unsigned int y_ppem)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
font->x_ppem = x_ppem;
@ -1718,7 +1785,7 @@ hb_font_get_ppem (hb_font_t *font,
void
hb_font_set_ptem (hb_font_t *font, float ptem)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
font->ptem = ptem;
@ -1765,7 +1832,7 @@ hb_font_set_variations (hb_font_t *font,
const hb_variation_t *variations,
unsigned int variations_length)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
if (!variations_length)
@ -1796,7 +1863,7 @@ hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
@ -1817,7 +1884,7 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
const int *coords, /* 2.14 normalized */
unsigned int coords_length)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
@ -1849,8 +1916,6 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
}
#ifndef HB_DISABLE_DEPRECATED
/*
* Deprecated get_glyph_func():
*/
@ -1973,5 +2038,3 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
trampoline,
trampoline_destroy);
}
#endif /* HB_DISABLE_DEPRECATED */

View File

@ -110,7 +110,7 @@ typedef struct hb_glyph_extents_t
/* func types */
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
hb_font_extents_t *metrics,
hb_font_extents_t *extents,
void *user_data);
typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
@ -125,6 +125,14 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *
hb_codepoint_t *glyph,
void *user_data);
typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data);
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@ -133,8 +141,8 @@ typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
@ -149,12 +157,6 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@ -226,6 +228,22 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_nominal_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_nominal_glyphs_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 2.0.0
**/
HB_EXTERN void
hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs,
hb_font_get_nominal_glyphs_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_variation_glyph_func:
* @ffuncs: font functions.
@ -338,38 +356,6 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_extents_func:
* @ffuncs: font functions.
@ -461,15 +447,15 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
HB_EXTERN void
hb_font_get_glyph_h_advances (hb_font_t* font,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
HB_EXTERN void
hb_font_get_glyph_v_advances (hb_font_t* font,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
@ -483,13 +469,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
@ -531,8 +510,8 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
HB_EXTERN void
hb_font_get_glyph_advances_for_direction (hb_font_t* font,
hb_direction_t direction,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride);
@ -552,12 +531,6 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,

View File

@ -43,6 +43,7 @@
HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \
HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
@ -61,9 +62,6 @@
struct hb_font_funcs_t
{
hb_object_header_t header;
ASSERT_POD ();
hb_bool_t immutable;
struct {
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
@ -88,7 +86,7 @@ struct hb_font_funcs_t
#define HB_FONT_FUNC_IMPLEMENT(name) +1
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
]) (void);
]) ();
} get;
};
DECLARE_NULL_INSTANCE (hb_font_funcs_t);
@ -98,12 +96,13 @@ DECLARE_NULL_INSTANCE (hb_font_funcs_t);
* hb_font_t
*/
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, font);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
struct hb_font_t
{
hb_object_header_t header;
ASSERT_POD ();
hb_bool_t immutable;
hb_font_t *parent;
hb_face_t *face;
@ -124,44 +123,46 @@ struct hb_font_t
void *user_data;
hb_destroy_func_t destroy;
struct hb_shaper_data_t shaper_data;
hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */
/* Convert from font-space to user-space */
inline int dir_scale (hb_direction_t direction)
int dir_scale (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
inline float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
inline float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_scale (v, dir_scale (direction)); }
/* Convert from parent-font user-space to our user-space */
inline hb_position_t parent_scale_x_distance (hb_position_t v) {
hb_position_t parent_scale_x_distance (hb_position_t v)
{
if (unlikely (parent && parent->x_scale != x_scale))
return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
return v;
}
inline hb_position_t parent_scale_y_distance (hb_position_t v) {
hb_position_t parent_scale_y_distance (hb_position_t v)
{
if (unlikely (parent && parent->y_scale != y_scale))
return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
return v;
}
inline hb_position_t parent_scale_x_position (hb_position_t v) {
return parent_scale_x_distance (v);
}
inline hb_position_t parent_scale_y_position (hb_position_t v) {
return parent_scale_y_distance (v);
}
hb_position_t parent_scale_x_position (hb_position_t v)
{ return parent_scale_x_distance (v); }
hb_position_t parent_scale_y_position (hb_position_t v)
{ return parent_scale_y_distance (v); }
inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
void parent_scale_distance (hb_position_t *x, hb_position_t *y)
{
*x = parent_scale_x_distance (*x);
*y = parent_scale_y_distance (*y);
}
inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
void parent_scale_position (hb_position_t *x, hb_position_t *y)
{
*x = parent_scale_x_position (*x);
*y = parent_scale_y_position (*y);
}
@ -170,27 +171,35 @@ struct hb_font_t
/* Public getters */
HB_INTERNAL bool has_func (unsigned int i);
HB_INTERNAL bool has_func_set (unsigned int i);
/* has_* ... */
#define HB_FONT_FUNC_IMPLEMENT(name) \
bool \
has_##name##_func (void) \
has_##name##_func () \
{ \
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
return has_func (i); \
} \
bool \
has_##name##_func_set () \
{ \
hb_font_funcs_t *funcs = this->klass; \
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
return has_func_set (i); \
}
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_h_extents (this, user_data,
extents,
klass->user_data.font_h_extents);
}
inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
return klass->get.f.font_v_extents (this, user_data,
@ -198,13 +207,13 @@ struct hb_font_t
klass->user_data.font_v_extents);
}
inline bool has_glyph (hb_codepoint_t unicode)
bool has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return get_nominal_glyph (unicode, &glyph);
}
inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
hb_codepoint_t *glyph)
{
*glyph = 0;
@ -212,9 +221,21 @@ struct hb_font_t
unicode, glyph,
klass->user_data.nominal_glyph);
}
unsigned int get_nominal_glyphs (unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride)
{
return klass->get.f.nominal_glyphs (this, user_data,
count,
first_unicode, unicode_stride,
first_glyph, glyph_stride,
klass->user_data.nominal_glyphs);
}
inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
{
*glyph = 0;
return klass->get.f.variation_glyph (this, user_data,
@ -222,25 +243,25 @@ struct hb_font_t
klass->user_data.variation_glyph);
}
inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
{
return klass->get.f.glyph_h_advance (this, user_data,
glyph,
klass->user_data.glyph_h_advance);
}
inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
{
return klass->get.f.glyph_v_advance (this, user_data,
glyph,
klass->user_data.glyph_v_advance);
}
inline void get_glyph_h_advances (unsigned int count,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
void get_glyph_h_advances (unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
{
return klass->get.f.glyph_h_advances (this, user_data,
count,
@ -249,11 +270,11 @@ struct hb_font_t
klass->user_data.glyph_h_advances);
}
inline void get_glyph_v_advances (unsigned int count,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
void get_glyph_v_advances (unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
hb_position_t *first_advance,
unsigned int advance_stride)
{
return klass->get.f.glyph_v_advances (this, user_data,
count,
@ -262,7 +283,7 @@ struct hb_font_t
klass->user_data.glyph_v_advances);
}
inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
@ -271,8 +292,8 @@ struct hb_font_t
klass->user_data.glyph_h_origin);
}
inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
return klass->get.f.glyph_v_origin (this, user_data,
@ -280,21 +301,23 @@ struct hb_font_t
klass->user_data.glyph_v_origin);
}
inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph)
{
return klass->get.f.glyph_h_kerning (this, user_data,
left_glyph, right_glyph,
klass->user_data.glyph_h_kerning);
}
inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
hb_codepoint_t bottom_glyph)
{
return klass->get.f.glyph_v_kerning (this, user_data,
top_glyph, bottom_glyph,
klass->user_data.glyph_v_kerning);
}
inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents)
{
memset (extents, 0, sizeof (*extents));
@ -304,7 +327,7 @@ struct hb_font_t
klass->user_data.glyph_extents);
}
inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
@ -314,8 +337,8 @@ struct hb_font_t
klass->user_data.glyph_contour_point);
}
inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
char *name, unsigned int size)
hb_bool_t get_glyph_name (hb_codepoint_t glyph,
char *name, unsigned int size)
{
if (size) *name = '\0';
return klass->get.f.glyph_name (this, user_data,
@ -324,8 +347,8 @@ struct hb_font_t
klass->user_data.glyph_name);
}
inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph)
hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph)
{
*glyph = 0;
if (len == -1) len = strlen (name);
@ -338,7 +361,7 @@ struct hb_font_t
/* A bit higher-level, and with fallback */
inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
void get_h_extents_with_fallback (hb_font_extents_t *extents)
{
if (!get_font_h_extents (extents))
{
@ -347,7 +370,7 @@ struct hb_font_t
extents->line_gap = 0;
}
}
inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
void get_v_extents_with_fallback (hb_font_extents_t *extents)
{
if (!get_font_v_extents (extents))
{
@ -357,8 +380,8 @@ struct hb_font_t
}
}
inline void get_extents_for_direction (hb_direction_t direction,
hb_font_extents_t *extents)
void get_extents_for_direction (hb_direction_t direction,
hb_font_extents_t *extents)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
get_h_extents_with_fallback (extents);
@ -366,9 +389,9 @@ struct hb_font_t
get_v_extents_with_fallback (extents);
}
inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
void get_glyph_advance_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
*x = *y = 0;
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
@ -376,12 +399,12 @@ struct hb_font_t
else
*y = get_glyph_v_advance (glyph);
}
inline void get_glyph_advances_for_direction (hb_direction_t direction,
unsigned count,
hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
void get_glyph_advances_for_direction (hb_direction_t direction,
unsigned int count,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
@ -389,8 +412,8 @@ struct hb_font_t
get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
}
inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = get_glyph_h_advance (glyph) / 2;
@ -400,8 +423,8 @@ struct hb_font_t
*y = extents.ascender;
}
inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
if (!get_glyph_h_origin (glyph, x, y) &&
get_glyph_v_origin (glyph, x, y))
@ -411,8 +434,8 @@ struct hb_font_t
*x -= dx; *y -= dy;
}
}
inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
if (!get_glyph_v_origin (glyph, x, y) &&
get_glyph_h_origin (glyph, x, y))
@ -423,9 +446,9 @@ struct hb_font_t
}
}
inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
void get_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
get_glyph_h_origin_with_fallback (glyph, x, y);
@ -433,8 +456,8 @@ struct hb_font_t
get_glyph_v_origin_with_fallback (glyph, x, y);
}
inline void add_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void add_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
@ -443,8 +466,8 @@ struct hb_font_t
*x += origin_x;
*y += origin_y;
}
inline void add_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void add_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
@ -453,9 +476,9 @@ struct hb_font_t
*x += origin_x;
*y += origin_y;
}
inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
void add_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
@ -465,8 +488,8 @@ struct hb_font_t
*y += origin_y;
}
inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void subtract_glyph_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
@ -475,8 +498,8 @@ struct hb_font_t
*x -= origin_x;
*y -= origin_y;
}
inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
void subtract_glyph_v_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
@ -485,9 +508,9 @@ struct hb_font_t
*x -= origin_x;
*y -= origin_y;
}
inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
hb_position_t origin_x, origin_y;
@ -497,22 +520,22 @@ struct hb_font_t
*y -= origin_y;
}
inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
*x = get_glyph_h_kerning (first_glyph, second_glyph);
*y = 0;
*x = get_glyph_h_kerning (first_glyph, second_glyph);
} else {
*x = 0;
*y = get_glyph_v_kerning (first_glyph, second_glyph);
}
}
inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
hb_direction_t direction,
hb_glyph_extents_t *extents)
hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
hb_direction_t direction,
hb_glyph_extents_t *extents)
{
hb_bool_t ret = get_glyph_extents (glyph, extents);
@ -522,9 +545,9 @@ struct hb_font_t
return ret;
}
inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y)
{
hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
@ -535,7 +558,7 @@ struct hb_font_t
}
/* Generates gidDDD if glyph has no name. */
inline void
void
glyph_to_string (hb_codepoint_t glyph,
char *s, unsigned int size)
{
@ -546,7 +569,7 @@ struct hb_font_t
}
/* Parses gidDDD and uniUUUU strings automatically. */
inline hb_bool_t
hb_bool_t
glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph)
{
@ -576,29 +599,19 @@ struct hb_font_t
return false;
}
inline hb_position_t em_scale (int16_t v, int scale)
hb_position_t em_scale (int16_t v, int scale)
{
int upem = face->get_upem ();
int64_t scaled = v * (int64_t) scale;
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
return (hb_position_t) (scaled / upem);
}
inline hb_position_t em_scalef (float v, int scale)
{
return (hb_position_t) round (v * scale / face->get_upem ());
}
inline float em_fscale (int16_t v, int scale)
{
return (float) v * scale / face->get_upem ();
}
hb_position_t em_scalef (float v, int scale)
{ return (hb_position_t) round (v * scale / face->get_upem ()); }
float em_fscale (int16_t v, int scale)
{ return (float) v * scale / face->get_upem (); }
};
DECLARE_NULL_INSTANCE (hb_font_t);
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
#include "hb-shaper-list.hh"
#undef HB_SHAPER_IMPLEMENT
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
#endif /* HB_FONT_HH */

View File

@ -40,31 +40,38 @@
#include FT_TRUETYPE_TABLES_H
/**
* SECTION:hb-ft
* @title: hb-ft
* @short_description: FreeType integration
* @include: hb-ft.h
*
* Functions for using HarfBuzz with the FreeType library to provide face and
* font data.
**/
/* TODO:
*
* In general, this file does a fine job of what it's supposed to do.
* There are, however, things that need more work:
*
* - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
* Have not investigated.
*
* - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
* would work fine. However, we also abuse this API for performing in font-space,
* but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
* for that, such that no rounding etc happens. As such, we don't set ppem, and
* pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
* ourselves, like we do in uniscribe, etc.
* ourselves.
*
* - We don't handle / allow for emboldening / obliqueing.
*
* - In the future, we should add constructors to create fonts in font space?
*
* - FT_Load_Glyph() is extremely costly. Do something about it?
*/
struct hb_ft_font_t
{
mutable hb_mutex_t lock;
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
@ -82,13 +89,14 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
if (unlikely (!ft_font))
return nullptr;
ft_font->lock.init ();
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
ft_font->cached_x_scale.set (0);
ft_font->cached_x_scale.set_relaxed (0);
ft_font->advance_cache.init ();
return ft_font;
@ -110,6 +118,8 @@ _hb_ft_font_destroy (void *data)
if (ft_font->unref)
_hb_ft_face_destroy (ft_font->ft_face);
ft_font->lock.fini ();
free (ft_font);
}
@ -125,7 +135,7 @@ _hb_ft_font_destroy (void *data)
void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
{
if (font->immutable)
if (hb_object_is_immutable (font))
return;
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
@ -177,6 +187,7 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
if (unlikely (!g))
@ -200,6 +211,32 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
return true;
}
static unsigned int
hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
void *font_data,
unsigned int count,
const hb_codepoint_t *first_unicode,
unsigned int unicode_stride,
hb_codepoint_t *first_glyph,
unsigned int glyph_stride,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
unsigned int done;
for (done = 0;
done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
done++)
{
first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
}
/* We don't need to do ft_font->symbol dance here, since HB calls the singular
* nominal_glyph() for what we don't handle here. */
return done;
}
static hb_bool_t
hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *font_data,
@ -209,6 +246,7 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
if (unlikely (!g))
@ -218,34 +256,17 @@ hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
return true;
}
static hb_position_t
hb_ft_get_glyph_h_advance (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
return 0;
if (font->x_scale < 0)
v = -v;
return (v + (1<<9)) >> 10;
}
static void
hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
unsigned count,
hb_codepoint_t *first_glyph,
const hb_codepoint_t *first_glyph,
unsigned glyph_stride,
hb_position_t *first_advance,
unsigned advance_stride,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
int load_flags = ft_font->load_flags;
int mult = font->x_scale < 0 ? -1 : +1;
@ -271,8 +292,8 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
*first_advance = (v * mult + (1<<9)) >> 10;
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
@ -283,6 +304,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
@ -305,6 +327,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
@ -323,23 +346,6 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
return true;
}
static hb_position_t
hb_ft_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Vector kerningv;
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
return 0;
return kerningv.x;
}
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font,
void *font_data,
@ -348,6 +354,7 @@ hb_ft_get_glyph_extents (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
@ -380,6 +387,7 @@ hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
@ -405,8 +413,10 @@ hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
if (ret && (size && !*name))
ret = false;
@ -421,6 +431,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (len < 0)
@ -453,10 +464,11 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
metrics->ascender = ft_face->size->metrics.ascender;
metrics->descender = ft_face->size->metrics.descender;
metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
if (font->y_scale < 0)
{
metrics->ascender = -metrics->ascender;
@ -466,27 +478,25 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true;
}
#ifdef HB_USE_ATEXIT
static void free_static_ft_funcs (void);
#if HB_USE_ATEXIT
static void free_static_ft_funcs ();
#endif
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
{
static inline hb_font_funcs_t *create (void)
static hb_font_funcs_t *create ()
{
hb_font_funcs_t *funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@ -494,7 +504,7 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_make_immutable (funcs);
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
atexit (free_static_ft_funcs);
#endif
@ -502,16 +512,16 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
}
} static_ft_funcs;
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
static
void free_static_ft_funcs (void)
void free_static_ft_funcs ()
{
static_ft_funcs.free_instance ();
}
#endif
static hb_font_funcs_t *
_hb_ft_get_font_funcs (void)
_hb_ft_get_font_funcs ()
{
return static_ft_funcs.get_unconst ();
}
@ -734,45 +744,45 @@ hb_ft_font_create_referenced (FT_Face ft_face)
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
#ifdef HB_USE_ATEXIT
static void free_static_ft_library (void);
#if HB_USE_ATEXIT
static void free_static_ft_library ();
#endif
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_ptr_t<FT_Library>::value,
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
hb_ft_library_lazy_loader_t>
{
static inline FT_Library create (void)
static FT_Library create ()
{
FT_Library l;
if (FT_Init_FreeType (&l))
return nullptr;
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
atexit (free_static_ft_library);
#endif
return l;
}
static inline void destroy (FT_Library l)
static void destroy (FT_Library l)
{
FT_Done_FreeType (l);
}
static inline FT_Library get_null (void)
static FT_Library get_null ()
{
return nullptr;
}
} static_ft_library;
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
static
void free_static_ft_library (void)
void free_static_ft_library ()
{
static_ft_library.free_instance ();
}
#endif
static FT_Library
get_ft_library (void)
get_ft_library ()
{
return static_ft_library.get_unconst ();
}

View File

@ -30,10 +30,19 @@
#include "hb-glib.h"
#include "hb-unicode.hh"
#include "hb-machinery.hh"
/**
* SECTION:hb-glib
* @title: hb-glib
* @short_description: GLib integration
* @include: hb-glib.h
*
* Functions for using HarfBuzz with the GLib library to provide Unicode data.
**/
#if !GLIB_CHECK_VERSION(2,29,14)
static const hb_script_t
glib_script_to_script[] =
@ -202,14 +211,6 @@ hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
}
static unsigned int
hb_glib_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
void *user_data HB_UNUSED)
{
return g_unichar_iswide (unicode) ? 2 : 1;
}
static hb_unicode_general_category_t
hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t unicode,
@ -334,56 +335,27 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return ret;
}
static unsigned int
hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
hb_codepoint_t u,
hb_codepoint_t *decomposed,
void *user_data HB_UNUSED)
{
#if GLIB_CHECK_VERSION(2,29,12)
return g_unichar_fully_decompose (u, true, decomposed, HB_UNICODE_MAX_DECOMPOSITION_LEN);
#endif
/* If the user doesn't have GLib >= 2.29.12 we have to perform
* a round trip to UTF-8 and the associated memory management dance. */
gchar utf8[6];
gchar *utf8_decomposed, *c;
gsize utf8_len, utf8_decomposed_len, i;
/* Convert @u to UTF-8 and normalise it in NFKD mode. This performs the compatibility decomposition. */
utf8_len = g_unichar_to_utf8 (u, utf8);
utf8_decomposed = g_utf8_normalize (utf8, utf8_len, G_NORMALIZE_NFKD);
utf8_decomposed_len = g_utf8_strlen (utf8_decomposed, -1);
assert (utf8_decomposed_len <= HB_UNICODE_MAX_DECOMPOSITION_LEN);
for (i = 0, c = utf8_decomposed; i < utf8_decomposed_len; i++, c = g_utf8_next_char (c))
*decomposed++ = g_utf8_get_char (c);
g_free (utf8_decomposed);
return utf8_decomposed_len;
}
#ifdef HB_USE_ATEXIT
static void free_static_glib_funcs (void);
#if HB_USE_ATEXIT
static void free_static_glib_funcs ();
#endif
static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
{
static inline hb_unicode_funcs_t *create (void)
static hb_unicode_funcs_t *create ()
{
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
#define HB_UNICODE_FUNC_IMPLEMENT(name) \
hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_UNICODE_FUNC_IMPLEMENT
hb_unicode_funcs_set_combining_class_func (funcs, hb_glib_unicode_combining_class, nullptr, nullptr);
hb_unicode_funcs_set_general_category_func (funcs, hb_glib_unicode_general_category, nullptr, nullptr);
hb_unicode_funcs_set_mirroring_func (funcs, hb_glib_unicode_mirroring, nullptr, nullptr);
hb_unicode_funcs_set_script_func (funcs, hb_glib_unicode_script, nullptr, nullptr);
hb_unicode_funcs_set_compose_func (funcs, hb_glib_unicode_compose, nullptr, nullptr);
hb_unicode_funcs_set_decompose_func (funcs, hb_glib_unicode_decompose, nullptr, nullptr);
hb_unicode_funcs_make_immutable (funcs);
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
atexit (free_static_glib_funcs);
#endif
@ -391,16 +363,16 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
}
} static_glib_funcs;
#ifdef HB_USE_ATEXIT
#if HB_USE_ATEXIT
static
void free_static_glib_funcs (void)
void free_static_glib_funcs ()
{
static_glib_funcs.free_instance ();
}
#endif
hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void)
hb_glib_get_unicode_funcs ()
{
return static_glib_funcs.get_unconst ();
}

View File

@ -46,7 +46,7 @@
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
@enum_name@_get_type ()
{
static gsize type_id = 0;

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