Merge branch 'master' of https://github.com/harfbuzz/harfbuzz
This commit is contained in:
commit
ad12603664
17
.ci/build-freetype.sh
Normal file
17
.ci/build-freetype.sh
Normal 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
|
@ -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
38
.clang-format
Normal 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
7
.codecov.yml
Normal file
@ -0,0 +1,7 @@
|
||||
comment: off
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
@ -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
|
||||
|
41
.travis.yml
41
.travis.yml
@ -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
16
AUTHORS
@ -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
|
||||
|
2
BUILD.md
2
BUILD.md
@ -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:
|
||||
|
179
CMakeLists.txt
179
CMakeLists.txt
@ -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)
|
||||
|
@ -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
261
NEWS
@ -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
17
README
@ -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
|
18
README.md
Normal file
18
README.md
Normal 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
|
@ -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
|
||||
|
@ -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.
|
||||
|
17
RELEASING.md
17
RELEASING.md
@ -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
12
TODO
@ -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?
|
||||
|
||||
|
18
appveyor.yml
18
appveyor.yml
@ -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
21
azure-pipelines.yml
Normal 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
|
22
configure.ac
22
configure.ac
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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—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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 "merge".
|
||||
This merged cluster takes for its cluster number the minimum of all
|
||||
the cluster numbers of the clusters that went in. In this case, we
|
||||
get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC,D,E
|
||||
0,1 ,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now let's assume that the <literal>BC</literal> glyph decomposes
|
||||
into three components, and <literal>D</literal> also decomposes into
|
||||
two. The components each inherit the cluster value of their parent:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2,D0,D1,E
|
||||
0,1 ,1 ,1 ,3 ,3 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now if <literal>BC2</literal> and <literal>D0</literal> ligate, then
|
||||
their clusters (numbers 1 and 3) merge into
|
||||
<literal>min(1,3) = 1</literal>:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2D0,D1,E
|
||||
0,1 ,1 ,1 ,1 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
At this point, cluster 1 means: the character sequence
|
||||
<literal>BCD</literal> is represented by glyphs
|
||||
<literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
|
||||
further.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="reordering-in-levels-0-and-1">
|
||||
<title>Reordering in levels 0 and 1</title>
|
||||
<para>
|
||||
Another common operation in the more complex shapers is when things
|
||||
reorder. In those cases, to maintain monotone clusters, HB merges
|
||||
the clusters of everything in the reordering sequence. For example,
|
||||
let's again start with the character sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
If <literal>D</literal> is reordered before <literal>B</literal>,
|
||||
then the <literal>B</literal>, <literal>C</literal>, and
|
||||
<literal>D</literal> clusters merge, and we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,1,1,1,4
|
||||
</programlisting>
|
||||
<para>
|
||||
This is clearly not ideal, but it is the only sensible way to
|
||||
maintain monotone indices and retain the true relationship between
|
||||
glyphs and characters.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="the-distinction-between-levels-0-and-1">
|
||||
<title>The distinction between levels 0 and 1</title>
|
||||
<para>
|
||||
So, the above is pretty much what cluster levels 0 and 1 do. The
|
||||
only difference between the two is this: in level 0, at the very
|
||||
beginning of the shaping process, we also merge clusters between
|
||||
base characters and all Unicode marks (combining or not) following
|
||||
them. E.g.:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,1 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
will become:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,0 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
This is the default behavior. We do it because Windows did it and
|
||||
old HarfBuzz did it, so this remained the default. But this behavior
|
||||
makes it impossible to color diacritic marks differently from their
|
||||
base characters. That's why in level 1 we do not perform this
|
||||
initial merging step.
|
||||
</para>
|
||||
<para>
|
||||
For clients, level 0 is more convenient if they rely on HarfBuzz
|
||||
clusters for cursor positioning. But that's wrong anyway: cursor
|
||||
positions should be determined based on Unicode grapheme boundaries,
|
||||
NOT shaping clusters. As such, level 1 clusters are preferred.
|
||||
</para>
|
||||
<para>
|
||||
One last note about levels 0 and 1. We currently don't allow a
|
||||
<literal>MultipleSubst</literal> lookup to replace a glyph with zero
|
||||
glyphs (i.e., to delete a glyph). But in some other situations,
|
||||
glyphs can be deleted. In those cases, if the glyph being deleted is
|
||||
the last glyph of its cluster, we make sure to merge the cluster
|
||||
with a neighboring cluster.
|
||||
</para>
|
||||
<para>
|
||||
This is, primarily, to make sure that the starting cluster of the
|
||||
text always has the cluster index pointing to the start of the text
|
||||
for the run; more than one client currently relies on this
|
||||
guarantee.
|
||||
</para>
|
||||
<para>
|
||||
Incidentally, Apple's CoreText does something else to maintain the
|
||||
same promise: it inserts a glyph with id 65535 at the beginning of
|
||||
the glyph string if the glyph corresponding to the first character
|
||||
in the run was deleted. HarfBuzz might do something similar in the
|
||||
future.
|
||||
</para>
|
||||
</sect1>
|
||||
<sect1 id="level-2">
|
||||
<title>Level 2</title>
|
||||
<para>
|
||||
Level 2 is a different beast from levels 0 and 1. It is simple to
|
||||
describe, but hard to make sense of. It simply doesn't do any
|
||||
cluster merging whatsoever. When things ligate or otherwise multiple
|
||||
glyphs turn into one, the cluster value of the first glyph is
|
||||
retained.
|
||||
</para>
|
||||
<para>
|
||||
Here are a few examples of why processing cluster values produced at
|
||||
this level might be tricky:
|
||||
</para>
|
||||
<sect2 id="ligatures-with-combining-marks">
|
||||
<title>Ligatures with combining marks</title>
|
||||
<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 — such as a ligature or conjunct form
|
||||
— and require the shaper to ensure that the cluster is not
|
||||
broken during the shaping process.
|
||||
</para>
|
||||
<para>
|
||||
A cluster is distinct from a <emphasis>grapheme</emphasis>,
|
||||
which is the smallest unit of meaning in a writing system or
|
||||
script.
|
||||
</para>
|
||||
<para>
|
||||
The definitions of the two terms are similar. However, clusters
|
||||
are only relevant for script shaping and glyph layout. In
|
||||
contrast, graphemes are a property of the underlying script, and
|
||||
are of interest when client programs implement orthographic
|
||||
or linguistic functionality.
|
||||
</para>
|
||||
<para>
|
||||
For example, two individual letters are often two separate
|
||||
graphemes. When two letters form a ligature, however, they
|
||||
combine into a single glyph. They are then part of the same
|
||||
cluster and are treated as a unit by the shaping engine —
|
||||
even though the two original, underlying letters remain separate
|
||||
graphemes.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz is concerned with clusters, <emphasis>not</emphasis>
|
||||
with graphemes — although client programs using HarfBuzz
|
||||
may still care about graphemes for other reasons from time to time.
|
||||
</para>
|
||||
<para>
|
||||
During the shaping process, there are several shaping operations
|
||||
that may merge adjacent characters (for example, when two code
|
||||
points form a ligature or a conjunct form and are replaced by a
|
||||
single glyph) or split one character into several (for example,
|
||||
when decomposing a code point through the
|
||||
<literal>ccmp</literal> feature). Operations like these alter
|
||||
clusters; HarfBuzz tracks the changes to ensure that no clusters
|
||||
get lost or broken during shaping.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz records cluster information independently from how
|
||||
shaping operations affect the individual glyphs returned in an
|
||||
output buffer. Consequently, a client program using HarfBuzz can
|
||||
utilize the cluster information to implement features such as:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Correctly positioning the cursor within a shaped text run,
|
||||
even when characters have formed ligatures, composed or
|
||||
decomposed, reordered, or undergone other shaping operations.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Correctly highlighting a text selection that includes some,
|
||||
but not all, of the characters in a word.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Applying text attributes (such as color or underlining) to
|
||||
part, but not all, of a word.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Generating output document formats (such as PDF) with
|
||||
embedded text that can be fully extracted.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Determining the mapping between input characters and output
|
||||
glyphs, such as which glyphs are ligatures.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Performing line-breaking, justification, and other
|
||||
line-level or paragraph-level operations that must be done
|
||||
after shaping is complete, but which require examining
|
||||
character-level properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="working-with-harfbuzz-clusters">
|
||||
<title>Working with HarfBuzz clusters</title>
|
||||
<para>
|
||||
When you add text to a HarfBuzz buffer, each code point must be
|
||||
assigned a <emphasis>cluster value</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
This cluster value is an arbitrary number; HarfBuzz uses it only
|
||||
to distinguish between clusters. Many client programs will use
|
||||
the index of each code point in the input text stream as the
|
||||
cluster value. This is for the sake of convenience; the actual
|
||||
value does not matter.
|
||||
</para>
|
||||
<para>
|
||||
Some of the shaping operations performed by HarfBuzz —
|
||||
such as reordering, composition, decomposition, and substitution
|
||||
— may alter the cluster values of some characters. The
|
||||
final cluster values in the buffer at the end of the shaping
|
||||
process will indicate to client programs which subsequences of
|
||||
glyphs represent a cluster and, therefore, must not be
|
||||
separated.
|
||||
</para>
|
||||
<para>
|
||||
In addition, client programs can query the final cluster values
|
||||
to discern other potentially important information about the
|
||||
glyphs in the output buffer (such as whether or not a ligature
|
||||
was formed).
|
||||
</para>
|
||||
<para>
|
||||
For example, if the initial sequence of cluster values was:
|
||||
</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
|
||||
"merge". This merged cluster takes for its cluster
|
||||
value the minimum of all the cluster values of the clusters that
|
||||
went in to the ligature. In this case, we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC,D,E
|
||||
0,1 ,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
because 1 is the minimum of the set {1,2}, which were the
|
||||
cluster values of <literal>B</literal> and
|
||||
<literal>C</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Next, let us say that the <literal>BC</literal> ligature glyph
|
||||
decomposes into three components, and <literal>D</literal> also
|
||||
decomposes into two components. Whenever a cluster decomposes,
|
||||
its components each inherit the cluster value of their parent:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2,D0,D1,E
|
||||
0,1 ,1 ,1 ,3 ,3 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Next, if <literal>BC2</literal> and <literal>D0</literal> form a
|
||||
ligature, then their clusters (cluster values 1 and 3) merge into
|
||||
<literal>min(1,3) = 1</literal>:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2D0,D1,E
|
||||
0,1 ,1 ,1 ,1 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Note that the entirety of cluster 3 merges into cluster 1, not
|
||||
just the <literal>D0</literal> glyph. This reflects the fact
|
||||
that the cluster <emphasis>must</emphasis> be treated as an
|
||||
indivisible unit.
|
||||
</para>
|
||||
<para>
|
||||
At this point, cluster 1 means: the character sequence
|
||||
<literal>BCD</literal> is represented by glyphs
|
||||
<literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
|
||||
further.
|
||||
</para>
|
||||
</section>
|
||||
<section id="reordering-in-levels-0-and-1">
|
||||
<title>Reordering in levels 0 and 1</title>
|
||||
<para>
|
||||
Another common operation in 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 — 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 —
|
||||
including marks and modifiers — 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>
|
||||
|
@ -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>
|
||||
|
307
docs/usermanual-getting-started.xml
Normal file
307
docs/usermanual-getting-started.xml
Normal 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 <hb.h>
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, -1, 0, -1);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Set the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font, using FreeType for now.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb-ft.h>
|
||||
FT_New_Face(ft_library, font_path, index, &face);
|
||||
FT_Set_Char_Size(face, 0, 1000, 0, 0);
|
||||
hb_font_t *font = hb_ft_font_create(face);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="4">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
for (i = 0; i < glyph_count; ++i) {
|
||||
glyphid = glyph_info[i].codepoint;
|
||||
x_offset = glyph_pos[i].x_offset / 64.0;
|
||||
y_offset = glyph_pos[i].y_offset / 64.0;
|
||||
x_advance = glyph_pos[i].x_advance / 64.0;
|
||||
y_advance = glyph_pos[i].y_advance / 64.0;
|
||||
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
|
||||
cursor_x += x_advance;
|
||||
cursor_y += y_advance;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(hb_ft_font);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
This example shows enough to get us started using HarfBuzz. In
|
||||
the sections that follow, we will use the remainder of
|
||||
HarfBuzz's API to refine and extend the example and improve its
|
||||
text-shaping capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -1,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>
|
||||
|
@ -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 <hb.h>
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Guess the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_guess_segment_properties(buf);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font, using FreeType for now.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb-ft.h>
|
||||
FT_New_Face(ft_library, font_path, index, &face)
|
||||
hb_font_t *font = hb_ft_font_create(face);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="4">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
for (i = 0; i < glyph_count; ++i) {
|
||||
glyphid = glyph_info[i].codepoint;
|
||||
x_offset = glyph_pos[i].x_offset / 64.0;
|
||||
y_offset = glyph_pos[i].y_offset / 64.0;
|
||||
x_advance = glyph_pos[i].x_advance / 64.0;
|
||||
y_advance = glyph_pos[i].y_advance / 64.0;
|
||||
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
|
||||
cursor_x += x_advance;
|
||||
cursor_y += y_advance;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(hb_ft_font);
|
||||
</programlisting>
|
||||
<section id="what-harfbuzz-doesnt-do">
|
||||
<title>What HarfBuzz doesn't do</title>
|
||||
<para>
|
||||
The code above will take a UTF8 string, shape it, and give you the
|
||||
information required to lay it out correctly on a single
|
||||
horizontal (or vertical) line using the font provided. That is the
|
||||
extent of HarfBuzz's responsibility.
|
||||
</para>
|
||||
<para>
|
||||
If you are implementing a text layout engine you may have other
|
||||
responsibilities, that HarfBuzz will not help you with:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with bidirectionality. If you want to
|
||||
lay out text with mixed Hebrew and English, you will need to
|
||||
ensure that the buffer provided to HarfBuzz has those
|
||||
characters in the correct layout order. This will be different
|
||||
from the logical order in which the Unicode text is stored. In
|
||||
other words, the user will hit the keys in the following
|
||||
sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A B C [space] ג ב א [space] D E F
|
||||
</programlisting>
|
||||
<para>
|
||||
but will expect to see in the output:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC אבג DEF
|
||||
</programlisting>
|
||||
<para>
|
||||
This reordering is called <emphasis>bidi processing</emphasis>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to reorder a string from logical order into presentation order.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as ICU and fribidi can do
|
||||
this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
Similarly if you change font, font size, script, language or
|
||||
direction within your string, you will need to shape each run
|
||||
independently and then output them independently. HarfBuzz
|
||||
expects to shape a run of characters sharing the same
|
||||
properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation or
|
||||
justification. As mentioned above, it lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line. If you
|
||||
want to layout text in paragraphs, you will probably want to send
|
||||
each word of your text to HarfBuzz to determine its shaped width
|
||||
after glyph substitutions, then work out how many words will fit
|
||||
on a line, and then finally output each word of the line separated
|
||||
by a space of the correct size to fully justify the paragraph.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need - what you then do with the glyphs that your font
|
||||
returns is up to you. The example we saw above enough to get us
|
||||
started using HarfBuzz. Now we are going to use the remainder of
|
||||
HarfBuzz's API to refine that example and improve our text shaping
|
||||
capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -1,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–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>
|
||||
|
@ -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>
|
||||
|
375
docs/usermanual-shaping-concepts.xml
Normal file
375
docs/usermanual-shaping-concepts.xml
Normal 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—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>
|
@ -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
|
||||
"a" as glyph ID 1. To pull the right glyph out of
|
||||
the font in order to display it, you need to consult a table
|
||||
within the font (the "cmap" table) which maps
|
||||
Unicode codepoints to glyph IDs. Text shaping turns codepoints
|
||||
into glyph IDs.
|
||||
OpenType fonts contain a set of glyphs (that is, shapes
|
||||
to represent the letters, numbers, punctuation marks, and
|
||||
all other symbols), which are indexed by a <literal>glyph ID</literal>.
|
||||
</para>
|
||||
<para>
|
||||
A particular glyph ID within the font does not necessarily
|
||||
correlate to a predictable Unicode codepoint. For instance,
|
||||
some fonts have the letter "a" as glyph ID 1, but
|
||||
many others do not. In order to retrieve the right glyph
|
||||
from the font to display "a", you need to consult
|
||||
the table inside the font (the <literal>cmap</literal>
|
||||
table) that maps Unicode codepoints to glyph IDs. In other
|
||||
words, <emphasis>text shaping turns codepoints into glyph
|
||||
IDs</emphasis>.
|
||||
</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 "fi". Whether you should
|
||||
render text as <literal>fi</literal> or "fi" does not
|
||||
depend on the input text, but on the capabilities of the font
|
||||
and the level of ligature application you wish to perform.
|
||||
Text shaping involves querying the font's ligature tables and
|
||||
determining what substitutions should be made.
|
||||
characters that are rendered as a single unit. For instance,
|
||||
it is common for the "f, i" letter
|
||||
sequence to appear in print as the single ligature glyph
|
||||
"fi".
|
||||
</para>
|
||||
<para>
|
||||
Whether you should render an "f, i" sequence
|
||||
as <literal>fi</literal> or as "fi" does not
|
||||
depend on the input text. Instead, it depends on the whether
|
||||
or not the font includes an "fi" glyph and on the
|
||||
level of ligature application you wish to perform. The font
|
||||
and the amount of ligature application used are under your
|
||||
control. In other words, <emphasis>text shaping involves
|
||||
querying the font's ligature tables and determining what
|
||||
substitutions should be made</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
While ligatures like "fi" are typographic
|
||||
refinements, some languages <emphasis>require</emphasis> such
|
||||
While ligatures like "fi" 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 "TTA" (ட) letter is
|
||||
followed by "U" (உ), the combination should appear
|
||||
as the single glyph "டு". The sequence of Unicode
|
||||
characters "டஉ" needs to be rendered as a single
|
||||
glyph from the font - text shaping chooses the correct glyph
|
||||
from the sequence of characters provided.
|
||||
</para>
|
||||
<para>
|
||||
For example, in Tamil, when the letter "TTA" (ட)
|
||||
letter is followed by "U" (உ), the pair
|
||||
must be replaced by the single glyph "டு". The
|
||||
sequence of Unicode characters "டஉ" needs to be
|
||||
substituted with a single "டு" glyph from the
|
||||
font.
|
||||
</para>
|
||||
<para>
|
||||
But "டு" does not have a Unicode codepoint. To
|
||||
find this glyph, you need to consult the table inside
|
||||
the font (the <literal>GSUB</literal> table) that contains
|
||||
substitution information. In other words, <emphasis>text shaping
|
||||
chooses the correct glyph for a sequence of characters
|
||||
provided</emphasis>.
|
||||
</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
|
||||
"zhe" (ж) with a breve accent, like so: ӂ. Some
|
||||
fonts will contain this character as an individual glyph,
|
||||
whereas other fonts will not contain a zhe-with-breve glyph
|
||||
but expect the rendering engine to form the character by
|
||||
overlaying the two glyphs ж and ˘. Where you should draw the
|
||||
combining breve depends on the height of the preceding glyph.
|
||||
Again, for Arabic, the correct positioning of vowel marks
|
||||
depends on the height of the character on which you are
|
||||
placing the mark. Text shaping tells you whether you have a
|
||||
precomposed glyph within your font or if you need to compose a
|
||||
glyph yourself out of combining marks, and if so, where to
|
||||
position those marks.
|
||||
Other languages involve marks and accents that need to be
|
||||
rendered in specific positions relative a base character. For
|
||||
instance, the Moldovan language includes the Cyrillic letter
|
||||
"zhe" (ж) with a breve accent, like so: "ӂ".
|
||||
</para>
|
||||
<para>
|
||||
Some fonts will provide this character as a single
|
||||
zhe-with-breve glyph, but other fonts will not and, instead,
|
||||
will expect the rendering engine to form the character by
|
||||
superimposing the separate "ж" and "˘"
|
||||
glyphs.
|
||||
</para>
|
||||
<para>
|
||||
But exactly where you should draw the breve depends on the
|
||||
height and width of the preceding zhe glyph. To find the
|
||||
right position, you need to consult the table inside
|
||||
the font (the <literal>GPOS</literal> table) that contains
|
||||
positioning information.
|
||||
In other words, <emphasis>text shaping tells you whether you
|
||||
have a precomposed glyph within your font or if you need to
|
||||
compose a glyph yourself out of combining marks—and,
|
||||
if so, where to position those marks.</emphasis>
|
||||
</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>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to process a string of mixed directionality.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as <ulink
|
||||
url="http://icu-project.org/">ICU</ulink> and <ulink
|
||||
url="http://fribidi.org/">fribidi</ulink> can do this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, then you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, if you change the font, font size, script,
|
||||
language, or direction within your string, then you will
|
||||
need to shape each run independently and output them
|
||||
independently. HarfBuzz expects to shape a run of characters
|
||||
that all share the same properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation, or
|
||||
justification. As mentioned above, HarfBuzz lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout-engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need—what you then do with the glyphs that your font
|
||||
returns is up to you.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-is-it-called-harfbuzz">
|
||||
<title>Why is it called HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz began its life as text shaping code within the FreeType
|
||||
project, (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations) but was then
|
||||
abstracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, and named HarfBuzz. Originally, it was a shaping
|
||||
engine for OpenType fonts - "HarfBuzz" is the Persian
|
||||
for "open type".
|
||||
HarfBuzz began its life as text-shaping code within the FreeType
|
||||
project (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations), but was then
|
||||
extracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, who named it HarfBuzz. Originally, it was a
|
||||
shaping engine for OpenType fonts—"HarfBuzz" is
|
||||
the Persian for "open type".
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
</chapter>
|
||||
|
97
src/HBIndicVowelConstraints.txt
Normal file
97
src/HBIndicVowelConstraints.txt
Normal 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
|
127
src/Makefile.am
127
src/Makefile.am
@ -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= \
|
||||
|
@ -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 = \
|
||||
|
@ -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/[.].*//'`
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -27,7 +27,7 @@
|
||||
#include "hb-ot-shape-complex-indic.hh"
|
||||
|
||||
int
|
||||
main (void)
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "hb-ot-shape-complex-myanmar.hh"
|
||||
|
||||
int
|
||||
main (void)
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "hb-ot-shape-complex-use.hh"
|
||||
|
||||
int
|
||||
main (void)
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
|
@ -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
67
src/gen-emoji-table.py
Executable 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 == */")
|
@ -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 ()
|
||||
|
@ -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
1126
src/gen-tag-table.py
Executable file
File diff suppressed because it is too large
Load Diff
@ -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
223
src/gen-vowel-constraints.py
Executable 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
126
src/hb-aat-fdsc-table.hh
Normal 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 */
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
417
src/hb-aat-layout-just-table.hh
Normal file
417
src/hb-aat-layout-just-table.hh
Normal 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
93
src/hb-aat-layout-lcar-table.hh
Normal file
93
src/hb-aat-layout-lcar-table.hh
Normal 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
@ -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 */
|
||||
|
@ -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
486
src/hb-aat-layout.h
Normal 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 */
|
@ -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 */
|
||||
|
@ -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
68
src/hb-aat-map.cc
Normal 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
91
src/hb-aat-map.hh
Normal 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 */
|
@ -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 */
|
@ -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
312
src/hb-array.hh
Normal 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 */
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 ();
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
213
src/hb-buffer.cc
213
src/hb-buffer.cc
@ -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
|
||||
**/
|
||||
|
@ -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);
|
||||
|
164
src/hb-buffer.hh
164
src/hb-buffer.hh
@ -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;
|
||||
|
@ -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
725
src/hb-cff-interp-common.hh
Normal 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 */
|
905
src/hb-cff-interp-cs-common.hh
Normal file
905
src/hb-cff-interp-cs-common.hh
Normal 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 */
|
294
src/hb-cff-interp-dict-common.hh
Normal file
294
src/hb-cff-interp-dict-common.hh
Normal 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
161
src/hb-cff1-interp-cs.hh
Normal 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
271
src/hb-cff2-interp-cs.hh
Normal 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 */
|
163
src/hb-common.cc
163
src/hb-common.cc
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
50
src/hb-dispatch.hh
Normal 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 */
|
100
src/hb-face.cc
100
src/hb-face.cc
@ -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 ();
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
*/
|
||||
|
273
src/hb-font.cc
273
src/hb-font.cc
@ -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 */
|
||||
|
@ -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,
|
||||
|
251
src/hb-font.hh
251
src/hb-font.hh
@ -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 */
|
||||
|
150
src/hb-ft.cc
150
src/hb-ft.cc
@ -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 ();
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user