Merge branch 'master' into usermanual-integration
This commit is contained in:
commit
a11db0b9d4
|
@ -4,10 +4,10 @@ jobs:
|
|||
|
||||
macos-10.12.6-aat-fonts:
|
||||
macos:
|
||||
xcode: "9.2.0"
|
||||
xcode: "9.0.1"
|
||||
steps:
|
||||
- checkout
|
||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
|
||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo python3
|
||||
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
|
||||
- run: make -j4
|
||||
- run: make check || .ci/fail.sh
|
||||
|
@ -22,30 +22,42 @@ jobs:
|
|||
- run: make -j4
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
macos-10.14.3-aat-fonts:
|
||||
macos-10.14.4-aat-fonts:
|
||||
macos:
|
||||
xcode: "10.2.0"
|
||||
xcode: "11.1.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo 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: export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" && ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-coretext --with-graphite2
|
||||
- run: make -j4
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
distcheck:
|
||||
docker:
|
||||
- image: ubuntu:17.10
|
||||
macos-10.15.3-aat-fonts:
|
||||
macos:
|
||||
xcode: "11.4.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c graphite2 meson
|
||||
- run: export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" && ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-coretext --with-graphite2
|
||||
- run: make -j4
|
||||
- run: make check || .ci/fail.sh
|
||||
- run: make clean && meson build -Damalgam=true && ninja -Cbuild test
|
||||
|
||||
distcheck:
|
||||
docker:
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools libfontconfig1-dev libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip meson cmake
|
||||
- run: pip install fonttools
|
||||
- run: ./autogen.sh
|
||||
- run: make -j32
|
||||
- run: make distcheck || .ci/fail.sh
|
||||
- run: rm -rf harfbuzz-*
|
||||
- run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
|
||||
- run: rm harfbuzz-* && make distdir
|
||||
- run: cd harfbuzz-* && meson build && ninja -Cbuild test
|
||||
- run: cd harfbuzz-* && cmake -Bcmakebuild -H. && cmake --build cmakebuild
|
||||
|
||||
alpine-O3-NOMMAP:
|
||||
alpine-O3-Os-NOMMAP:
|
||||
docker:
|
||||
- image: alpine
|
||||
steps:
|
||||
|
@ -55,6 +67,10 @@ jobs:
|
|||
- run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
|
||||
- run: make -j32
|
||||
- run: make check || .ci/fail.sh
|
||||
- run: make clean
|
||||
- run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh
|
||||
- run: make -j32
|
||||
- run: make check || .ci/fail.sh
|
||||
|
||||
archlinux-py3-all:
|
||||
docker:
|
||||
|
@ -69,34 +85,30 @@ jobs:
|
|||
- 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:
|
||||
clang-O3-O0-and-nobuildsystem:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang wget autoconf automake libtool pkg-config ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j32 && cd ..
|
||||
- run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make -j32
|
||||
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
|
||||
- run: make check || .ci/fail.sh
|
||||
- run: make clean
|
||||
- run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make -j32
|
||||
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
|
||||
- run: make check || .ci/fail.sh
|
||||
- run: make clean
|
||||
- run: make -Csrc CPPFLAGS="-DHB_TINY -DHB_NO_OT_FONT" libharfbuzz-subset.la && make clean
|
||||
- run: clang -c src/harfbuzz.cc -DHB_NO_MT
|
||||
# -Werror -Werror=deprecated-this-capture can be added but it will confuse contributors so let's skip for now
|
||||
- run: clang -c src/hb-*.cc -DHB_NO_MT -std=c++2a -fno-exceptions
|
||||
|
||||
gcc-valgrind:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
|
@ -106,35 +118,35 @@ jobs:
|
|||
- 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
|
||||
- run: HB_TEST_SHAPE_FUZZER_TIMEOUT=3 HB_TEST_SUBSET_FUZZER_TIMEOUT=30 RUN_VALGRIND=1 make check && make -Ctest/api check-valgrind || .ci/fail.sh
|
||||
# informational for now
|
||||
- run: make -Ctest/api check-symbols || true
|
||||
|
||||
clang-everything:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true; apt install -y wget gnupg
|
||||
- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: echo "deb http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
|
||||
- run: CFLAGS="-Weverything -Wno-reserved-id-macro -Wno-conversion -Wno-padded -Wno-sign-conversion -Wno-cast-qual -Wno-documentation -Wno-documentation-unknown-command -DHB_WITH_WIN1256" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template -DHB_WITH_WIN1256" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
|
||||
- run: make -j32 CPPFLAGS="-Werror"
|
||||
- run: make check CPPFLAGS="-Werror" || .ci/fail.sh
|
||||
|
||||
clang-asan:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true; apt install -y wget gnupg
|
||||
- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: echo "deb http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config gtk-doc-tools ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
|
@ -144,13 +156,13 @@ jobs:
|
|||
|
||||
clang-msan:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true; apt install -y wget gnupg
|
||||
- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: echo "deb http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang lld binutils libtool autoconf automake gtk-doc-tools gettext make pkg-config ragel libcairo2-dev libicu-dev libmount-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
|
@ -158,72 +170,72 @@ jobs:
|
|||
- run: wget https://ftp.gnome.org/pub/gnome/sources/glib/2.58/glib-2.58.1.tar.xz && tar xf glib-2.58.1.tar.xz && cd glib-2.58.1 && ./autogen.sh --with-pcre CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory" CFLAGS="-fsanitize=memory" CXXFLAGS="-fsanitize=memory" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
|
||||
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure CPPFLAGS="-fsanitize=memory" LDFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ && make -j32 && make install && cd ..
|
||||
- run: CPPFLAGS="-fsanitize=memory -fsanitize-memory-track-origins" LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --without-icu
|
||||
- run: make -j32 && MSAN_OPTIONS=exitcode=42 make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
- run: make -j32 && MSAN_OPTIONS=exitcode=42 HB_TEST_SUBSET_FUZZER_TIMEOUT=18 make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
|
||||
clang-tsan:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true; apt install -y wget gnupg
|
||||
- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: echo "deb http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=thread -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: CPPFLAGS="-fsanitize=thread" LDFLAGS="-fsanitize=thread -O3" CFLAGS="-fsanitize=thread -O3" CXXFLAGS="-fsanitize=thread -O3" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make -j32
|
||||
- run: make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
- run: HB_TEST_SUBSET_FUZZER_TIMEOUT=40 make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
|
||||
clang-ubsan:
|
||||
docker:
|
||||
- image: ubuntu:18.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true; apt install -y wget gnupg
|
||||
- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
- run: echo "deb http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/cosmic/ llvm-toolchain-cosmic main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: echo "deb http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdev.list
|
||||
- run: echo "deb-src http://apt.llvm.org/eoan/ llvm-toolchain-eoan main" > /etc/apt/sources.list.d/llvmdevsrc.list
|
||||
- run: apt update || true
|
||||
- run: apt install -y clang lld binutils libtool autoconf automake make pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: CPPFLAGS="-fsanitize=undefined" LDFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: CPPFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined" LDFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined -O1 -g -fno-omit-frame-pointer" CFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" CXXFLAGS="-fsanitize=undefined -O1 -g -fno-omit-frame-pointer" LD=ld.lld CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
|
||||
- run: make -j32
|
||||
- run: make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
- run: UBSAN_OPTIONS=print_stacktrace=1 make check || .ci/fail.sh | asan_symbolize | c++filt
|
||||
|
||||
fedora-O0-debug-outoftreebuild:
|
||||
fedora-O0-debug-outoftreebuild-mingw:
|
||||
docker:
|
||||
- image: fedora
|
||||
steps:
|
||||
- checkout
|
||||
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python || true
|
||||
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
|
||||
- run: mkdir build && cd build && ../configure && make && (make check || ../.ci/fail.sh)
|
||||
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which diffutils glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || true
|
||||
- run: NOCONFIGURE=1 ./autogen.sh
|
||||
- run: mkdir build && cd build && CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ../configure --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 && make -j32 && (HB_TEST_SUBSET_FUZZER_TIMEOUT=15 make check || ../.ci/fail.sh)
|
||||
- run: pip install pefile
|
||||
- run: mkdir winbuild32 && cd winbuild32 && ../mingw32.sh && make -j32 && make dist-win && cp harfbuzz-*-win32.zip harfbuzz-win32.zip
|
||||
- run: mkdir winbuild64 && cd winbuild64 && ../mingw64.sh && make -j32 && make dist-win && cp harfbuzz-*-win64.zip harfbuzz-win64.zip
|
||||
- store_artifacts:
|
||||
path: winbuild32/harfbuzz-win32.zip
|
||||
destination: harfbuzz-win32.zip
|
||||
- store_artifacts:
|
||||
path: winbuild64/harfbuzz-win64.zip
|
||||
destination: harfbuzz-win64.zip
|
||||
|
||||
cmake-gcc:
|
||||
meson-gcc:
|
||||
docker:
|
||||
- image: ubuntu:17.10
|
||||
- image: ubuntu:19.10
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y ninja-build binutils cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: apt update && apt install -y ninja-build binutils meson gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
|
||||
- run: pip install fonttools
|
||||
- run: cmake -DHB_CHECK=ON -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
- run: CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
|
||||
- run: ninja -Cbuild install
|
||||
|
||||
cmake-oracledeveloperstudio:
|
||||
docker:
|
||||
- image: fedora
|
||||
steps:
|
||||
- checkout
|
||||
- run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
|
||||
- run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
|
||||
- run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
|
||||
- run: make -Cbuild -j32
|
||||
- run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
|
||||
- run: make -Cbuild install
|
||||
- run: meson build && ninja -Cbuild test && rm -rf build
|
||||
# test amalgam build
|
||||
- run: meson build -Damalgam=true && ninja -Cbuild && rm -rf build
|
||||
# test meson's own unity feature also
|
||||
- run: meson build --unity on && ninja -Cbuild && rm -rf build
|
||||
# test experimental APIs
|
||||
- run: meson build -Dexperimental-api=true && ninja -Cbuild test && rm -rf build
|
||||
|
||||
crosscompile-notest-djgpp:
|
||||
docker:
|
||||
|
@ -235,65 +247,16 @@ jobs:
|
|||
- run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp
|
||||
- run: make -j32
|
||||
|
||||
crosscompile-notest-freebsd9:
|
||||
docker:
|
||||
- image: donbowman/freebsd-cross-build
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update && apt install -y pkg-config ragel
|
||||
- run: ./autogen.sh --prefix=/freebsd --host=x86_64-pc-freebsd9
|
||||
- run: make -j32
|
||||
|
||||
crosscompile-notest-psvita:
|
||||
docker:
|
||||
- image: dockcross/base
|
||||
steps:
|
||||
- checkout
|
||||
- run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh
|
||||
- run: echo "#""!""/bin/true" > /usr/bin/ragel && chmod +x /usr/bin/ragel
|
||||
- run: echo '#!/bin/true' > /usr/bin/ragel && chmod +x /usr/bin/ragel
|
||||
- run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
|
||||
- run: make -j32
|
||||
|
||||
crosscompile-cmake-notest-android-arm:
|
||||
docker:
|
||||
- image: dockcross/android-arm
|
||||
steps:
|
||||
- checkout
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
crosscompile-cmake-notest-browser-asmjs:
|
||||
docker:
|
||||
- image: dockcross/browser-asmjs
|
||||
steps:
|
||||
- checkout
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
crosscompile-cmake-notest-linux-arm64:
|
||||
docker:
|
||||
- image: dockcross/linux-arm64
|
||||
steps:
|
||||
- checkout
|
||||
- run: cmake -Bbuild -H. -GNinja
|
||||
- run: ninja -Cbuild
|
||||
|
||||
crosscompile-cmake-notest-linux-mips:
|
||||
docker:
|
||||
- image: dockcross/linux-mips
|
||||
steps:
|
||||
- checkout
|
||||
- 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:
|
||||
|
@ -301,38 +264,28 @@ workflows:
|
|||
# macOS
|
||||
- macos-10.12.6-aat-fonts
|
||||
- macos-10.13.6-aat-fonts
|
||||
- macos-10.14.3-aat-fonts
|
||||
- macos-10.14.4-aat-fonts
|
||||
- macos-10.15.3-aat-fonts
|
||||
|
||||
# both autotools and cmake
|
||||
- distcheck
|
||||
|
||||
# autotools based builds
|
||||
- alpine-O3-NOMMAP
|
||||
- alpine-O3-Os-NOMMAP
|
||||
- archlinux-py3-all
|
||||
#- void-notest
|
||||
- gcc-valgrind
|
||||
- clang-O3-O0
|
||||
- clang-O3-O0-and-nobuildsystem
|
||||
- clang-everything
|
||||
- clang-asan
|
||||
- clang-msan
|
||||
- clang-tsan
|
||||
- clang-ubsan
|
||||
- fedora-O0-debug-outoftreebuild
|
||||
- fedora-O0-debug-outoftreebuild-mingw
|
||||
|
||||
# cmake based builds
|
||||
- cmake-gcc
|
||||
#- cmake-oracledeveloperstudio
|
||||
- meson-gcc
|
||||
|
||||
# crosscompiles
|
||||
# they can't be test thus are without tests
|
||||
## autotools
|
||||
- crosscompile-notest-djgpp
|
||||
- crosscompile-notest-freebsd9
|
||||
- crosscompile-notest-psvita
|
||||
|
||||
## cmake
|
||||
- crosscompile-cmake-notest-android-arm
|
||||
- crosscompile-cmake-notest-browser-asmjs
|
||||
- crosscompile-cmake-notest-linux-arm64
|
||||
- crosscompile-cmake-notest-linux-mips
|
||||
#- crosscompile-cmake-notest-windows-x64
|
||||
|
|
|
@ -6,10 +6,10 @@ trim_trailing_whitespace = true
|
|||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{c,cc,h,hh}]
|
||||
[*.{c,cc,h,hh,rl}]
|
||||
tab_width = 8
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
indent_style = tab # should be space
|
||||
|
||||
[*.{py,sh}]
|
||||
indent_style = tab
|
||||
|
@ -17,5 +17,7 @@ indent_style = tab
|
|||
[{Makefile.am,Makefile.sources,configure.ac}]
|
||||
tab_width = 8
|
||||
|
||||
[{CMakeLists.txt,*.cmake}]
|
||||
[{meson.build,meson_options.txt}]
|
||||
tab_width = 8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
|
3
AUTHORS
3
AUTHORS
|
@ -1,11 +1,14 @@
|
|||
Behdad Esfahbod
|
||||
David Corbett
|
||||
David Turner
|
||||
Ebrahim Byagowi
|
||||
Garret Rieger
|
||||
Jonathan Kew
|
||||
Khaled Hosny
|
||||
Lars Knoll
|
||||
Martin Hosken
|
||||
Owen Taylor
|
||||
Roderick Sheeter
|
||||
Roozbeh Pournader
|
||||
Simon Hausmann
|
||||
Werner Lemberg
|
||||
|
|
7
BUILD.md
7
BUILD.md
|
@ -7,11 +7,8 @@ whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
|
|||
|
||||
sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel
|
||||
|
||||
on Windows, consider using [vcpkg](https://github.com/Microsoft/vcpkg),
|
||||
provided by Microsoft, for building HarfBuzz and other open-source libraries
|
||||
but if you need to build harfbuzz from source, put ragel binary on your
|
||||
PATH and follow appveyor CI's cmake
|
||||
[build steps](https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml).
|
||||
on Windows, consider using [vcpkg](https://github.com/Microsoft/vcpkg)
|
||||
or `meson build && ninja -Cbuild`.
|
||||
|
||||
on macOS, using MacPorts:
|
||||
|
||||
|
|
204
CMakeLists.txt
204
CMakeLists.txt
|
@ -1,7 +1,7 @@
|
|||
cmake_minimum_required(VERSION 2.8.0)
|
||||
project(harfbuzz)
|
||||
|
||||
enable_testing()
|
||||
message("HarfBuzz has a Meson port also and tries to migrate all the other build systems to it, please consider using it.")
|
||||
|
||||
## Limit framework build to Xcode generator
|
||||
if (BUILD_FRAMEWORK)
|
||||
|
@ -35,7 +35,6 @@ endif ()
|
|||
## HarfBuzz build configurations
|
||||
option(HB_HAVE_FREETYPE "Enable freetype interop helpers" OFF)
|
||||
option(HB_HAVE_GRAPHITE2 "Enable Graphite2 complementary shaper" OFF)
|
||||
option(HB_BUILTIN_UCDN "Use HarfBuzz provided UCDN" ON)
|
||||
option(HB_HAVE_GLIB "Enable glib unicode functions" OFF)
|
||||
option(HB_HAVE_ICU "Enable icu unicode functions" OFF)
|
||||
if (APPLE)
|
||||
|
@ -44,6 +43,7 @@ if (APPLE)
|
|||
endif ()
|
||||
if (WIN32)
|
||||
option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend on Windows" OFF)
|
||||
option(HB_HAVE_GDI "Enable GDI integration helpers on Windows" OFF)
|
||||
option(HB_HAVE_DIRECTWRITE "Enable DirectWrite shaper backend on Windows" OFF)
|
||||
endif ()
|
||||
option(HB_BUILD_UTILS "Build harfbuzz utils, needs cairo, freetype, and glib properly be installed" OFF)
|
||||
|
@ -53,7 +53,6 @@ if (HB_BUILD_UTILS)
|
|||
endif ()
|
||||
|
||||
option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON)
|
||||
option(HB_BUILD_TESTS "Build harfbuzz tests" ON)
|
||||
|
||||
option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
|
||||
if (HB_HAVE_GOBJECT)
|
||||
|
@ -66,32 +65,11 @@ if (HB_HAVE_INTROSPECTION)
|
|||
set (HB_HAVE_GLIB ON)
|
||||
endif ()
|
||||
|
||||
option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and enable all options)")
|
||||
if (HB_CHECK)
|
||||
set (BUILD_SHARED_LIBS ON)
|
||||
set (HB_BUILD_UTILS ON)
|
||||
set (HB_BUILTIN_UCDN ON)
|
||||
set (HB_HAVE_ICU)
|
||||
set (HB_HAVE_GLIB ON)
|
||||
#set (HB_HAVE_GOBJECT ON)
|
||||
#set (HB_HAVE_INTROSPECTION ON)
|
||||
set (HB_HAVE_FREETYPE ON)
|
||||
set (HB_HAVE_GRAPHITE2 ON)
|
||||
if (WIN32)
|
||||
set (HB_HAVE_UNISCRIBE ON)
|
||||
set (HB_HAVE_DIRECTWRITE ON)
|
||||
elseif (APPLE)
|
||||
set (HB_HAVE_CORETEXT ON)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include_directories(AFTER
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_BINARY_DIR}/src
|
||||
)
|
||||
|
||||
add_definitions(-DHAVE_FALLBACK)
|
||||
|
||||
# We need PYTHON_EXECUTABLE to be set for running the tests...
|
||||
include (FindPythonInterp)
|
||||
|
||||
|
@ -110,7 +88,7 @@ endmacro ()
|
|||
if (UNIX)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
|
||||
endif ()
|
||||
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l round)
|
||||
check_funcs(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
if (${HAVE_UNISTD_H})
|
||||
add_definitions(-DHAVE_UNISTD_H)
|
||||
|
@ -144,12 +122,12 @@ endif ()
|
|||
|
||||
## Extract variables from Makefile files
|
||||
function (extract_make_variable variable makefile_source)
|
||||
string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${makefile_source})
|
||||
string(REGEX MATCHALL "[^ \n\t\\]+" listVar ${CMAKE_MATCH_1})
|
||||
string(REGEX MATCH "${variable} = ([^$]+)\\$" temp "${makefile_source}")
|
||||
string(REGEX MATCHALL "[^ \n\t\\]+" listVar "${CMAKE_MATCH_1}")
|
||||
set (${variable} ${listVar} PARENT_SCOPE)
|
||||
endfunction ()
|
||||
|
||||
# http://stackoverflow.com/a/27630120
|
||||
# https://stackoverflow.com/a/27630120
|
||||
function (add_prefix_to_list var prefix)
|
||||
set (listVar "")
|
||||
foreach (f ${${var}})
|
||||
|
@ -160,14 +138,9 @@ endfunction ()
|
|||
|
||||
file(READ ${PROJECT_SOURCE_DIR}/src/Makefile.sources SRCSOURCES)
|
||||
file(READ ${PROJECT_SOURCE_DIR}/util/Makefile.sources UTILSOURCES)
|
||||
file(READ ${PROJECT_SOURCE_DIR}/src/hb-ucdn/Makefile.sources UCDNSOURCES)
|
||||
|
||||
extract_make_variable(HB_BASE_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_BASE_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
extract_make_variable(HB_BASE_headers ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_BASE_headers "${PROJECT_SOURCE_DIR}/src/")
|
||||
extract_make_variable(HB_FALLBACK_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_FALLBACK_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
|
||||
extract_make_variable(HB_SUBSET_sources ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
|
@ -191,9 +164,6 @@ add_prefix_to_list(HB_SUBSET_CLI_sources "${PROJECT_SOURCE_DIR}/util/")
|
|||
extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
|
||||
add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
|
||||
|
||||
extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES})
|
||||
add_prefix_to_list(LIBHB_UCDN_sources "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
|
||||
|
||||
|
||||
file(READ configure.ac CONFIGUREAC)
|
||||
string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
|
||||
|
@ -202,61 +172,12 @@ set (HB_VERSION_MAJOR ${CMAKE_MATCH_2})
|
|||
set (HB_VERSION_MINOR ${CMAKE_MATCH_3})
|
||||
set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
|
||||
|
||||
|
||||
## Define ragel tasks
|
||||
# if (NOT IN_HB_DIST)
|
||||
# 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}
|
||||
# COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
|
||||
# DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
|
||||
# )
|
||||
# add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
|
||||
# endforeach ()
|
||||
|
||||
# mark_as_advanced(RAGEL)
|
||||
# endif ()
|
||||
|
||||
|
||||
## Generate hb-version.h
|
||||
# if (NOT IN_HB_DIST)
|
||||
# set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
|
||||
# set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
|
||||
# set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
|
||||
# configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY)
|
||||
# execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
# "${HB_VERSION_H}.tmp"
|
||||
# "${HB_VERSION_H}"
|
||||
# )
|
||||
# file(REMOVE "${HB_VERSION_H}.tmp")
|
||||
# endif ()
|
||||
|
||||
|
||||
## Define sources and headers of the project
|
||||
set (project_sources
|
||||
${HB_BASE_sources}
|
||||
${HB_BASE_RAGEL_GENERATED_sources}
|
||||
|
||||
${HB_FALLBACK_sources}
|
||||
)
|
||||
|
||||
set (subset_project_sources
|
||||
${HB_SUBSET_sources}
|
||||
)
|
||||
|
||||
set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source
|
||||
set (subset_project_sources ${HB_SUBSET_sources})
|
||||
set (project_extra_sources)
|
||||
|
||||
set (project_headers
|
||||
#${HB_VERSION_H}
|
||||
|
||||
${HB_BASE_headers}
|
||||
)
|
||||
|
||||
set (subset_project_headers
|
||||
${HB_SUBSET_headers}
|
||||
)
|
||||
|
||||
set (project_headers ${HB_BASE_headers})
|
||||
set (subset_project_headers ${HB_SUBSET_headers})
|
||||
|
||||
## Find and include needed header folders and libraries
|
||||
if (HB_HAVE_FREETYPE)
|
||||
|
@ -269,7 +190,6 @@ if (HB_HAVE_FREETYPE)
|
|||
include_directories(AFTER ${FREETYPE_INCLUDE_DIRS})
|
||||
add_definitions(-DHAVE_FREETYPE=1)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ft.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-ft.h)
|
||||
|
||||
# So check_funcs can find its headers
|
||||
|
@ -287,7 +207,6 @@ if (HB_HAVE_GRAPHITE2)
|
|||
|
||||
include_directories(${GRAPHITE2_INCLUDE_DIR})
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-graphite2.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-graphite2.h)
|
||||
|
||||
list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
|
||||
|
@ -295,14 +214,6 @@ if (HB_HAVE_GRAPHITE2)
|
|||
mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
|
||||
endif ()
|
||||
|
||||
if (HB_BUILTIN_UCDN)
|
||||
include_directories(src/hb-ucdn)
|
||||
add_definitions(-DHAVE_UCDN)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-ucdn.cc)
|
||||
list(APPEND project_extra_sources ${LIBHB_UCDN_sources})
|
||||
endif ()
|
||||
|
||||
if (HB_HAVE_GLIB)
|
||||
add_definitions(-DHAVE_GLIB)
|
||||
|
||||
|
@ -316,7 +227,6 @@ if (HB_HAVE_GLIB)
|
|||
|
||||
include_directories(${GLIBCONFIG_INCLUDE_DIR} ${GLIB_INCLUDE_DIR})
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-glib.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-glib.h)
|
||||
|
||||
list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
|
||||
|
@ -336,7 +246,6 @@ if (HB_HAVE_ICU)
|
|||
|
||||
include_directories(${ICU_INCLUDE_DIR})
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-icu.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
|
||||
|
||||
list(APPEND THIRD_PARTY_LIBS ${ICU_LIBRARY})
|
||||
|
@ -348,7 +257,6 @@ if (APPLE AND HB_HAVE_CORETEXT)
|
|||
# Apple Advanced Typography
|
||||
add_definitions(-DHAVE_CORETEXT)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-coretext.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
|
||||
|
||||
if (HB_IOS)
|
||||
|
@ -379,21 +287,21 @@ if (APPLE AND HB_HAVE_CORETEXT)
|
|||
endif ()
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND HB_HAVE_GDI)
|
||||
add_definitions(-DHAVE_GDI)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
|
||||
list(APPEND THIRD_PARTY_LIBS gdi32)
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND HB_HAVE_UNISCRIBE)
|
||||
add_definitions(-DHAVE_UNISCRIBE)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
|
||||
|
||||
list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND HB_HAVE_DIRECTWRITE)
|
||||
add_definitions(-DHAVE_DIRECTWRITE)
|
||||
|
||||
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-directwrite.cc)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
|
||||
|
||||
list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
|
||||
endif ()
|
||||
|
||||
|
@ -501,7 +409,6 @@ if (HB_HAVE_GOBJECT)
|
|||
)
|
||||
endif ()
|
||||
|
||||
|
||||
## Atomic ops availability detection
|
||||
file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
|
||||
" void memory_barrier (void) { __sync_synchronize (); }
|
||||
|
@ -538,6 +445,19 @@ endif ()
|
|||
add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})
|
||||
target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
|
||||
|
||||
|
||||
## Define harfbuzz-icu library
|
||||
if (HB_HAVE_ICU)
|
||||
add_library(harfbuzz-icu ${PROJECT_SOURCE_DIR}/src/hb-icu.cc ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
|
||||
add_dependencies(harfbuzz-icu harfbuzz)
|
||||
target_link_libraries(harfbuzz-icu harfbuzz ${THIRD_PARTY_LIBS})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz harfbuzz-icu PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
## Define harfbuzz-subset library
|
||||
if (HB_BUILD_SUBSET)
|
||||
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
|
||||
|
@ -610,7 +530,6 @@ if (WIN32)
|
|||
endif ()
|
||||
|
||||
if (HB_HAVE_INTROSPECTION)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
|
||||
|
||||
|
@ -689,12 +608,14 @@ if (HB_HAVE_INTROSPECTION)
|
|||
POST_BUILD
|
||||
COMMAND ${G_IR_SCANNER_CMD}
|
||||
--warn-all --no-libtool --verbose
|
||||
-n hb
|
||||
--namespace=HarfBuzz
|
||||
--nsversion=0.0
|
||||
--symbol-prefix=hb
|
||||
--symbol-prefix=hb_gobject
|
||||
--identifier-prefix=hb_
|
||||
--include GObject-2.0
|
||||
--pkg-export=harfbuzz
|
||||
--pkg-export=harfbuzz-gobject
|
||||
--c-include=hb-gobject.h
|
||||
--cflags-begin
|
||||
-I${PROJECT_SOURCE_DIR}/src
|
||||
-I${PROJECT_BINARY_DIR}/src
|
||||
|
@ -797,6 +718,14 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
|
|||
NAMESPACE harfbuzz::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
|
||||
)
|
||||
if (HB_HAVE_ICU)
|
||||
install(TARGETS harfbuzz-icu
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
FRAMEWORK DESTINATION Library/Frameworks
|
||||
)
|
||||
endif ()
|
||||
if (HB_BUILD_UTILS)
|
||||
if (WIN32 AND BUILD_SHARED_LIBS)
|
||||
install(TARGETS harfbuzz-subset
|
||||
|
@ -841,54 +770,3 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
|
|||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (HB_BUILD_TESTS)
|
||||
## src/ executables
|
||||
foreach (prog main test test-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)
|
||||
|
||||
add_test(NAME check-static-inits.sh
|
||||
COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
|
||||
)
|
||||
add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
|
||||
add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
|
||||
|
||||
set_tests_properties(
|
||||
check-static-inits.sh check-libstdc++.sh check-symbols.sh
|
||||
PROPERTIES
|
||||
ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
|
||||
SKIP_RETURN_CODE 77)
|
||||
endif ()
|
||||
|
||||
add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
|
||||
add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
|
||||
add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
|
||||
add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
|
||||
set_tests_properties(
|
||||
check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
|
||||
SKIP_RETURN_CODE 77)
|
||||
endif ()
|
||||
|
||||
# Needs to come last so that variables defined above are passed to
|
||||
# subdirectories.
|
||||
add_subdirectory(test)
|
||||
endif ()
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
# Configuring HarfBuzz
|
||||
|
||||
Most of the time you will not need any custom configuration. The configuration
|
||||
options provided by `configure` or `meson` should be enough. In particular,
|
||||
if you just want HarfBuzz library plus hb-shape / hb-view utilities, make sure
|
||||
FreeType and Cairo are available and found during configuration.
|
||||
|
||||
If you are building for distribution, you should more carefully consider whether
|
||||
you need Glib, ICU, Graphite2, as well as CoreText / Uniscribe / DWrite. Make
|
||||
sure the relevant ones are enabled.
|
||||
|
||||
If you are building for custom environment (embedded, downloadable app, etc)
|
||||
where you mostly just want to call `hb_shape()` and the binary size of the
|
||||
resulting library is very important to you, the rest of this file guides you
|
||||
through your options to disable features you may not need, in exchange for
|
||||
binary size savings.
|
||||
|
||||
## Compiler Options
|
||||
|
||||
Make sure you build with your compiler's "optimize for size" option. On `gcc`
|
||||
this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os` either to `configure`
|
||||
(sticky) or to `make` (non-sticky). On clang there is an even more extreme flag,
|
||||
`-Oz`.
|
||||
|
||||
HarfBuzz heavily uses inline functions and the optimize-size flag can make the
|
||||
library smaller by 20% or more. Moreover, sometimes, based on the target CPU,
|
||||
the optimize-size builds perform *faster* as well, thanks to lower code
|
||||
footprint and caching effects. So, definitely try that even if size is not
|
||||
extremely tight but you have a huge application. For example, Chrome does
|
||||
that. Note that this configuration also automatically enables certain internal
|
||||
optimizations. Search for `HB_OPTIMIZE_SIZE` for details, if you are using
|
||||
other compilers, or continue reading.
|
||||
|
||||
Another compiler option to consider is "link-time optimization", also known as
|
||||
'lto'. To enable that, with `gcc` or `clang`, add `-flto` to both `CXXFLAGS`
|
||||
and `LDFLAGS`, either on `configure` invocation (sticky) or on `make` (non-sticky).
|
||||
This, also, can have a huge impact on the final size, 20% or more.
|
||||
|
||||
Finally, if you are making a static library build or otherwise linking the
|
||||
library into your app, make sure your linker removes unused functions. This
|
||||
can be tricky and differ from environment to environment, but you definitely
|
||||
want to make sure this happens. Otherwise, every unused public function will
|
||||
be adding unneeded bytes to your binary. The following pointers might come
|
||||
handy:
|
||||
|
||||
* https://lwn.net/Articles/741494/ (all of the four-part series)
|
||||
* https://elinux.org/images/2/2d/ELC2010-gc-sections_Denys_Vlasenko.pdf
|
||||
|
||||
Combining the above three build options should already shrink your library a lot.
|
||||
The rest of this file shows you ways to shrink the library even further at the
|
||||
expense of removing functionality (that may not be needed). The remaining
|
||||
options are all enabled by defining pre-processor macros, which can be done
|
||||
via `CXXFLAGS` or `CPPFLAGS` similarly.
|
||||
|
||||
|
||||
## Unicode-functions
|
||||
|
||||
Access to Unicode data can be configured at compile time as well as run-time.
|
||||
By default, HarfBuzz ships with its own compact subset of properties from
|
||||
Unicode Character Database that it needs. This is a highly-optimized
|
||||
implementation that depending on compile settings (optimize-size or not)
|
||||
takes around ~40kb or ~60kb. Using this implementation (default) is highly
|
||||
recommended, as HarfBuzz always ships with data from latest version of Unicode.
|
||||
This implementation can be disabled by defining `HB_NO_UCD`.
|
||||
|
||||
For example, if you are enabling ICU as a built-in option, or GLib, those
|
||||
can provide Unicode data as well, so defining `HB_NO_UCD` might save you
|
||||
space without reducing functionality (to the extent that the Unicode version
|
||||
of those implementations is recent.)
|
||||
|
||||
If, however, you provide your own Unicode data to HarfBuzz at run-time by
|
||||
calling `hb_buffer_set_unicode_funcs` on every buffer you create, and you do
|
||||
not rely on `hb_unicode_funcs_get_default()` results, you can disable the
|
||||
internal implementation by defining both `HB_NO_UCD` and `HB_NO_UNICODE_FUNCS`.
|
||||
The latter is needed to guard against accidentally building a library without
|
||||
any default Unicode implementations.
|
||||
|
||||
|
||||
## Font-functions
|
||||
|
||||
Access to certain font functionalities can also be configured at run-time. By
|
||||
default, HarfBuzz uses an efficient internal implementation of OpenType
|
||||
functionality for this. This internal implementation is called `hb-ot-font`.
|
||||
All newly-created `hb_font_t` objects by default use `hb-ot-font`. Using this
|
||||
is highly recommended, and is what fonts use by default when they are created.
|
||||
|
||||
Most embedded uses will probably use HarfBuzz with FreeType using `hb-ft.h`.
|
||||
In that case, or if you otherwise provide those functions by calling
|
||||
`hb_font_set_funcs()` on every font you create, you can disable `hb-ot-font`
|
||||
without loss of functionality by defining `HB_NO_OT_FONT`.
|
||||
|
||||
|
||||
## Shapers
|
||||
|
||||
Most HarfBuzz clients use it for the main shaper, called "ot". However, it
|
||||
is legitimate to want to compile HarfBuzz with only another backend, eg.
|
||||
CoreText, for example for an iOS app. For that, you want `HB_NO_OT_SHAPE`.
|
||||
If you are going down that route, check if you want `HB_NO_OT`.
|
||||
|
||||
This is very rarely what you need. Make sure you understand exactly what you
|
||||
are doing.
|
||||
|
||||
Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless. That removes the
|
||||
(unused) "fallback" shaper.
|
||||
|
||||
|
||||
## Thread-safety
|
||||
|
||||
By default HarfBuzz builds as a thread-safe library. The exception is that
|
||||
the `HB_TINY` predefined configuring (more below) disables thread-safety.
|
||||
|
||||
If you do /not/ need thread-safety in the library (eg. you always call into
|
||||
HarfBuzz from the same thread), you can disable thread-safety by defining
|
||||
`HB_NO_MT`. As noted already, this is enabled by `HB_TINY`.
|
||||
|
||||
|
||||
## Pre-defined configurations
|
||||
|
||||
The [`hb-config.hh`](src/hb-config.hh) internal header supports three
|
||||
pre-defined configurations as well grouping of various configuration options.
|
||||
The pre-defined configurations are:
|
||||
|
||||
* `HB_MINI`: Disables shaping of AAT as well as legacy fonts. Ie. it produces
|
||||
a capable OpenType shaper only.
|
||||
|
||||
* `HB_LEAN`: Disables various non-shaping functionality in the library, as well
|
||||
as esoteric or rarely-used shaping features. See the definition for details.
|
||||
|
||||
* `HB_TINY`: Enables both `HB_MINI` and `HB_LEAN` configurations, as well as
|
||||
disabling thread-safety and debugging, and use even more size-optimized data
|
||||
tables.
|
||||
|
||||
|
||||
## Tailoring configuration
|
||||
|
||||
Most of the time, one of the pre-defined configuration is exactly what one needs.
|
||||
Sometimes, however, the pre-defined configuration cuts out features that might
|
||||
be desired in the library. Unfortunately there is no quick way to undo those
|
||||
configurations from the command-line. But one can add a header file called
|
||||
`config-override.h` to undefine certain `HB_NO_*` symbols as desired. Then
|
||||
define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
|
||||
overrides at the end.
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and
|
||||
`HB_TINY` does /not/ mean that the resulting library won't work with CFF fonts.
|
||||
The library can shape valid CFF fonts just fine, with or without this option.
|
||||
This option disables (among other things) the code to calculate glyph exntents
|
||||
for CFF fonts.
|
4
COPYING
4
COPYING
|
@ -2,7 +2,9 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
|||
For parts of HarfBuzz that are licensed under different licenses see individual
|
||||
files names COPYING in subdirectories where applicable.
|
||||
|
||||
Copyright © 2010,2011,2012 Google, Inc.
|
||||
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
|
||||
Copyright © 2018,2019,2020 Ebrahim Byagowi
|
||||
Copyright © 2019,2020 Facebook, Inc.
|
||||
Copyright © 2012 Mozilla Foundation
|
||||
Copyright © 2011 Codethink Limited
|
||||
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
||||
|
|
38
Makefile.am
38
Makefile.am
|
@ -9,12 +9,30 @@ SUBDIRS = src util test docs
|
|||
EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
harfbuzz.doap \
|
||||
README.md \
|
||||
README.mingw.md \
|
||||
README.python.md \
|
||||
README.wine.md \
|
||||
BUILD.md \
|
||||
CONFIG.md \
|
||||
RELEASING.md \
|
||||
TESTING.md \
|
||||
CMakeLists.txt \
|
||||
replace-enum-strings.cmake \
|
||||
meson.build \
|
||||
meson_options.txt \
|
||||
subprojects/expat.wrap \
|
||||
subprojects/fontconfig.wrap \
|
||||
subprojects/freetype2.wrap \
|
||||
subprojects/glib.wrap \
|
||||
subprojects/libffi.wrap \
|
||||
subprojects/proxy-libintl.wrap \
|
||||
subprojects/zlib.wrap \
|
||||
meson-cc-tests/intel-atomic-primitives-test.c \
|
||||
meson-cc-tests/solaris-atomic-operations.c \
|
||||
mingw-configure.sh \
|
||||
mingw-ldd.py \
|
||||
mingw32.sh \
|
||||
mingw64.sh \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
|
@ -60,8 +78,6 @@ DISTCHECK_CONFIGURE_FLAGS = \
|
|||
--enable-introspection \
|
||||
$(NULL)
|
||||
|
||||
# TODO: Copy infrastructure from cairo
|
||||
|
||||
# TAR_OPTIONS is not set as env var for 'make dist'. How to fix that?
|
||||
TAR_OPTIONS = --owner=0 --group=0
|
||||
|
||||
|
@ -70,8 +86,7 @@ dist-hook: dist-clear-sticky-bits
|
|||
dist-clear-sticky-bits:
|
||||
chmod -R a-s $(distdir)
|
||||
|
||||
|
||||
tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.bz2
|
||||
tar_file = $(PACKAGE_TARNAME)-$(VERSION).tar.xz
|
||||
sha256_file = $(tar_file).sha256
|
||||
gpg_file = $(sha256_file).asc
|
||||
$(sha256_file): $(tar_file)
|
||||
|
@ -82,5 +97,18 @@ $(gpg_file): $(sha256_file)
|
|||
|
||||
release-files: $(tar_file) $(sha256_file) $(gpg_file)
|
||||
|
||||
dist-win:
|
||||
@case $(host_triplet) in *-w64-mingw32) ;; *) echo "Error: Requires mingw build. See README.mingw.md.">&2; exit 1 ;; esac
|
||||
@DIR=$(PACKAGE_TARNAME)-$(VERSION)-win`case $(host_triplet) in i686-*) echo 32 ;; x86_64-*) echo 64 ;; esac`; \
|
||||
$(RM) -r $$DIR; $(MKDIR_P) $$DIR || exit 1; \
|
||||
cp util/.libs/hb-{shape,view,subset}.exe $$DIR && \
|
||||
$(top_srcdir)/mingw-ldd.py $$DIR/hb-view.exe | grep -v 'not found' | cut -d '>' -f 2 | xargs cp -t $$DIR && \
|
||||
cp src/.libs/libharfbuzz{,-subset}-0.dll $$DIR && \
|
||||
chmod a+x $$DIR/*.{exe,dll} && \
|
||||
$(STRIP) $$DIR/*.{exe,dll} && \
|
||||
zip -r $$DIR.zip $$DIR && \
|
||||
$(RM) -r $$DIR && \
|
||||
echo "$$DIR.zip is ready."
|
||||
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
||||
|
|
112
NEWS
112
NEWS
|
@ -1,3 +1,115 @@
|
|||
Overview of changes leading to 2.6.5
|
||||
Friday, April 17, 2020
|
||||
====================================
|
||||
- Add experimental meson build system. Autotools is still the primary
|
||||
and supported build system.
|
||||
- AAT is now always preferred for horizontal scripts when both AAT and OT
|
||||
layout tables exist at the same time.
|
||||
- Subsetter improvements.
|
||||
- New API:
|
||||
+hb_ft_font_lock_face()
|
||||
+hb_ft_font_unlock_face()
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.4
|
||||
Monday, October 29, 2019
|
||||
====================================
|
||||
- Small bug fix.
|
||||
- Build fixes.
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.3
|
||||
Monday, October 28, 2019
|
||||
====================================
|
||||
- Misc small fixes, mostly to build-related issues.
|
||||
- New API:
|
||||
+hb_font_get_nominal_glyphs()
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.2
|
||||
Monday, September 30, 2019
|
||||
====================================
|
||||
- Misc small fixes, mostly to build-related issues.
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.1
|
||||
Thursday, August 22, 2019
|
||||
====================================
|
||||
- Fix regression with hb_font_create_sub_font scaling introduced in 2.6.0.
|
||||
- Change interpretation of font PTEM size / CoreText font size handling.
|
||||
See https://github.com/harfbuzz/harfbuzz/pull/1484
|
||||
- hb-ot-font: Prefer symbol cmap subtable if present.
|
||||
- Apply 'dist'/'abvm'/'blwm' features to all scripts.
|
||||
- Drop experimental DirectWrite API.
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.0
|
||||
Tuesday, August 13, 2019
|
||||
====================================
|
||||
- New OpenType metrics, baseline, and metadata table access APIs.
|
||||
- New API to set font variations to a named-instance.
|
||||
- New hb-gdi.h header and API for creating hb_face_t from HFONT.
|
||||
- Amalgam: Provide a single-file harfbuzz.cc file for easier alternate building.
|
||||
- More size-reduction configurable options, enabled by HB_TINY.
|
||||
- New API:
|
||||
+hb_font_set_var_named_instance()
|
||||
+hb_gdi_face_create()
|
||||
+hb_ot_layout_baseline_tag_t
|
||||
+hb_ot_layout_get_baseline()
|
||||
+hb_ot_meta_tag_t
|
||||
+hb_ot_meta_get_entry_tags()
|
||||
+hb_ot_meta_reference_entry()
|
||||
+hb_ot_metrics_tag_t
|
||||
+hb_ot_metrics_get_position()
|
||||
+hb_ot_metrics_get_variation()
|
||||
+hb_ot_metrics_get_x_variation()
|
||||
+hb_ot_metrics_get_y_variation()
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.3
|
||||
Wednesday, June 26, 2019
|
||||
====================================
|
||||
- Fix UCD script data for Unicode 10+ scripts. This was broken since 2.5.0.
|
||||
- More optimizations for HB_TINY.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.2
|
||||
Thursday, June 20, 2019
|
||||
====================================
|
||||
- More hb-config.hh facilities to shrink library size, namely when built as
|
||||
HB_TINY.
|
||||
- New documentation of custom configurations in CONFIG.md.
|
||||
- Fix build on gcc 4.8. That's supported again.
|
||||
- Universal Shaping Engine improvements thanks to David Corbett.
|
||||
- API Changes: Undeprecate some horizontal-kerning API and re-enable in hb-ft,
|
||||
such that Type1 fonts will continue kerning.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.1
|
||||
Friday, May 31, 2019
|
||||
====================================
|
||||
- Fix build with various versions of Visual Studio.
|
||||
- Improved documentation, thanks to Nathan Willis.
|
||||
- Bugfix in subsetting glyf table.
|
||||
- Improved scripts for cross-compiling for Windows using mingw.
|
||||
- Rename HB_MATH_GLYPH_PART_FLAG_EXTENDER to HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER.
|
||||
A deprecated macro is added for backwards-compatibility.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.0
|
||||
Friday, May 24, 2019
|
||||
====================================
|
||||
- This release does not include much functional changes, but includes major internal
|
||||
code-base changes. We now require C++11. Support for gcc 4.8 and earlier has been
|
||||
dropped.
|
||||
- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
|
||||
- New Unicode Character Databse implementation that is half the size of previously-used
|
||||
UCDN.
|
||||
- Subsetter improvements.
|
||||
- Improved documentation, thanks to Nathan Willis.
|
||||
- Misc shaping fixes.
|
||||
|
||||
|
||||
Overview of changes leading to 2.4.0
|
||||
Monday, March 25, 2019
|
||||
====================================
|
||||
|
|
18
README.md
18
README.md
|
@ -1,10 +1,12 @@
|
|||
[![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)
|
||||
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
|
||||
[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
|
||||
[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
|
||||
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
|
||||
[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
|
||||
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
|
||||
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
|
||||
|
||||
This is HarfBuzz, a text shaping library.
|
||||
|
@ -13,6 +15,20 @@ For bug reports, mailing list, and other information please visit:
|
|||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see the file COPYING.
|
||||
For license information, see [COPYING](COPYING).
|
||||
|
||||
For build information, see [BUILD.md](BUILD.md).
|
||||
|
||||
For custom configurations, see [CONFIG.md](CONFIG.md).
|
||||
|
||||
For test execution, see [TESTING.md](TESTING.md).
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Packaging status of HarfBuzz</summary>
|
||||
|
||||
[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
|
||||
|
||||
</details>
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
1. Install Wine from your favorite package manager. On Fedora that's `dnf install wine`.
|
||||
|
||||
2. And `mingw-w64` compiler.
|
||||
With `brew` on macOS, you can have it like `brew install mingw-w64`.
|
||||
On Fedora, with `dnf install mingw32-gcc-c++`, or `dnf install mingw64-gcc-c++` for the
|
||||
64-bit Windows.
|
||||
|
||||
3. Install cross-compiled dependency packages. Alternatively see [^1] below.
|
||||
On Fedora that would be `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
|
||||
for 32-bit, or `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype` for 64-bit.
|
||||
|
||||
5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
|
||||
6. Run `../mingw32.sh` for 32-bit build, or `../mingw64.sh` for 64-bit. This configures
|
||||
HarfBuzz for cross-compiling. It enables Uniscribe backend as well.
|
||||
|
||||
7. `make`
|
||||
|
||||
Now you can use hb-shape using `wine util/hb-shape.exe` but if you like to shape with
|
||||
the Microsoft Uniscribe,
|
||||
|
||||
8. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
|
||||
Windows installation (assuming you have a 64-bit installation, otherwise
|
||||
`C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy
|
||||
([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
You want a Uniscribe from Windows 7 or older.
|
||||
|
||||
Put the DLL in the folder you are going to run the next command,
|
||||
|
||||
9. `WINEDLLOVERRIDES="usp10=n" wine util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
||||
|
||||
|
||||
[^1] Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
|
||||
in your `~/.local/i686-w64-mingw32`. Then replace all the instances of
|
||||
`/home/behdad/.local/i586-mingw32msvc` and `/home/behdad/.local/i686-w64-mingw32`
|
||||
with `<$HOME>/.local/i686-w64-mingw32` on that folder.
|
||||
(`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
|
||||
You shouldn't replace the instances of those inside binary files.
|
|
@ -6,21 +6,21 @@ you can install that this way:
|
|||
sudo apt-get install libgirepository1.0-dev
|
||||
```
|
||||
|
||||
And then run autogen.sh (if building from git), and then:
|
||||
And then run `autogen.sh` (if building from git), and then:
|
||||
|
||||
```bash
|
||||
./configure --with-gobject --enable-introspection
|
||||
```
|
||||
|
||||
Make sure that gobject-introspection is enabled then in the final report.
|
||||
Make sure that gobject-introspection is reported enabled then in the `configure` script output.
|
||||
|
||||
Compile and install.
|
||||
|
||||
Make sure you have the installation lib dir in LD_LIBRARY_PATH, as needed
|
||||
Make sure you have the installation lib dir in `LD_LIBRARY_PATH`, as needed
|
||||
for the linker to find the library.
|
||||
|
||||
Then make sure you also have GI_TYPELIB_PATH pointing to the resulting
|
||||
$prefix/lib/girepository-* directory.
|
||||
Then make sure you also have `GI_TYPELIB_PATH` pointing to the resulting
|
||||
`$prefix/lib/girepository-*` directory.
|
||||
|
||||
Make sure you have pygobject installed. Then check that the following
|
||||
import works in your Python interpreter:
|
||||
|
@ -30,7 +30,7 @@ from gi.repository import HarfBuzz
|
|||
```
|
||||
|
||||
If it does, you are ready to call HarfBuzz from Python! Congratulations.
|
||||
See src/sample.py.
|
||||
See [`src/sample.py`](src/sample.py).
|
||||
|
||||
The Python API will change. Let us know on the mailing list if you are
|
||||
using it, and send lots of feedback.
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
1. Install Wine from your favorite package manager.
|
||||
|
||||
2. And `mingw-w64` compiler.
|
||||
With `brew` on macOS, you can have it like `brew install mingw-w64`
|
||||
|
||||
3. Download and put [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ)
|
||||
on your `~/.local/i686-w64-mingw32`.
|
||||
|
||||
4. Replace all the instances of `/home/behdad/.local/i586-mingw32msvc`
|
||||
and `/home/behdad/.local/i686-w64-mingw32` with `<$HOME>/.local/i686-w64-mingw32`
|
||||
on that folder. (`<$HOME>` replace it with `/home/XXX` or `/Users/XXX` on macOS)
|
||||
|
||||
Probably you shouldn't replace the ones are inside binaries.
|
||||
|
||||
5. `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
|
||||
6. `../mingw32.sh --with-uniscribe && cd ..`
|
||||
|
||||
7. `make -Cwinbuild`
|
||||
|
||||
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 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.
|
||||
|
||||
Put the dll on the folder you are going to run the next command,
|
||||
|
||||
9. `WINEDLLOVERRIDES="usp10=n" wine winbuild/util/hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
54
RELEASING.md
54
RELEASING.md
|
@ -46,27 +46,21 @@ HarfBuzz release walk-through checklist:
|
|||
|
||||
10. Build win32 bundle.
|
||||
|
||||
a. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
|
||||
a. Build Win32 binaries. See [README.mingw.md](README.mingw.md).
|
||||
|
||||
b. Run `../mingw32.sh --with-uniscribe` script to configure harfbuzz with mingw
|
||||
in a subdirector (eg. winbuild/),
|
||||
|
||||
c. make
|
||||
|
||||
d. Back in the parent directory, run `./UPDATE.sh`(available below) to build win32
|
||||
bundle.
|
||||
b. Run "make dist-win" to build Win32 bundle.
|
||||
|
||||
11. Copy all artefacts to users.freedesktop.org and move them into
|
||||
`/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four
|
||||
files. Eg.:
|
||||
```
|
||||
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.bz2
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.xz
|
||||
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256
|
||||
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.xz.sha256.asc
|
||||
-rw-r--r-- 1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
|
||||
```
|
||||
|
||||
12. While doing that, quickly double-check the size of the .tar.bz2 and .zip
|
||||
12. While doing that, quickly double-check the size of the .tar.xz and .zip
|
||||
files against their previous releases to make sure nothing bad happened.
|
||||
They should be in the ballpark, perhaps slightly larger. Sometimes they
|
||||
do shrink, that's not by itself a stopper.
|
||||
|
@ -76,39 +70,3 @@ HarfBuzz release walk-through checklist:
|
|||
|
||||
14. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
|
||||
edit the tag, upload artefacts and NEWS entry and save.
|
||||
|
||||
|
||||
## UPDATE.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
v=$1
|
||||
|
||||
if test "x$v" = x; then
|
||||
echo "usage: UPDATE.sh micro-version"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir_prefix=harfbuzz-1.4.
|
||||
dir_suffix=-win32
|
||||
dir=$dir_prefix$v$dir_suffix
|
||||
dir_old=$dir_prefix$((v-1))$dir_suffix
|
||||
if test -d "$dir"; then
|
||||
echo "New dir $dir exists; not overwriting"
|
||||
exit 1
|
||||
fi
|
||||
if ! test -d "$dir_old"; then
|
||||
echo "Old dir $dir_old does NOT exist; aborting"
|
||||
exit 1
|
||||
fi
|
||||
set -ex
|
||||
cp -a "$dir_old" "$dir.tmp"
|
||||
rm -f "$dir.tmp"/GDX32.dll
|
||||
rm -f "$dir.tmp"/usp10.dll
|
||||
cp ../winbuild/src/.libs/libharfbuzz-0.dll{,.def} $dir.tmp/
|
||||
cp ../winbuild/util/.libs/hb-{shape,view}.exe $dir.tmp/
|
||||
i686-w64-mingw32-strip $dir.tmp/{hb-shape.exe,hb-view.exe,libharfbuzz-0.dll}
|
||||
mv $dir.tmp $dir
|
||||
zip -r $dir.zip $dir
|
||||
echo Bundle $dir.zip ready
|
||||
```
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
## Build & Run
|
||||
|
||||
Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
|
||||
Values defined in `hb-debug.hh`.
|
||||
|
||||
```shell
|
||||
# quick sanity check
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& (make -j4 -C test/api check || cat test/api/test-suite.log))
|
||||
|
||||
# slower sanity check
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& make -j4 -C src check \
|
||||
&& make -j4 -C test/api check \
|
||||
&& make -j4 -C test/subset check)
|
||||
|
||||
# confirm you didn't break anything else
|
||||
time (make -j4 CPPFLAGS='-DHB_DEBUG_SUBSET=100' \
|
||||
&& make -j4 check)
|
||||
|
||||
# often catches files you didn't add, e.g. test fonts to EXTRA_DIST
|
||||
make distcheck
|
||||
```
|
||||
|
||||
### Run tests with asan
|
||||
|
||||
**NOTE**: this sometimes yields harder to read results than the full fuzzer
|
||||
|
||||
```shell
|
||||
# For nice symbols tell asan how to symoblize. Note that it doesn't like versioned copies like llvm-symbolizer-3.8
|
||||
# export ASAN_SYMBOLIZER_PATH=path to version-less llvm-symbolizer
|
||||
# ex
|
||||
export ASAN_SYMBOLIZER_PATH=/usr/lib/llvm-3.8/bin/llvm-symbolizer
|
||||
|
||||
./configure CC=clang CXX=clang++ CPPFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address
|
||||
# make/run tests as usual
|
||||
```
|
||||
|
||||
### Debug with GDB
|
||||
|
||||
```
|
||||
cd ./util
|
||||
../libtool --mode=execute gdb --args ./hb-subset ...
|
||||
```
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```shell
|
||||
# make clean if you previously build w/o debug logging
|
||||
make CPPFLAGS=-DHB_DEBUG_SUBSET=100
|
||||
```
|
||||
|
||||
## Build and Test via CMake
|
||||
|
||||
Note: You'll need to first install ninja-build via apt-get.
|
||||
|
||||
```shell
|
||||
meson build && ninja -Cbuild && ninja -Cbuild test
|
||||
```
|
||||
|
||||
## Test with the Fuzzer
|
||||
|
||||
```shell
|
||||
# push your changs to a branch on googlefonts/harfbuzz
|
||||
# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
|
||||
# Change the git clone to pull your branch
|
||||
|
||||
# Do this periodically
|
||||
sudo python infra/helper.py build_image harfbuzz
|
||||
|
||||
# Do these to update/run
|
||||
sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
|
||||
sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
|
||||
```
|
||||
|
||||
## Profiling
|
||||
|
||||
```
|
||||
make clean
|
||||
./configure CXXFLAGS="-fno-omit-frame-pointer -g"
|
||||
make
|
||||
perf record -o <perf output file> -g <command to run>
|
||||
perf report -i<perf output file>
|
||||
```
|
||||
|
2
THANKS
2
THANKS
|
@ -1,6 +1,6 @@
|
|||
Bradley Grainger
|
||||
Khaled Hosny
|
||||
Kenichi Ishibashi
|
||||
Ivan Kuckir <https://photopea.com/>
|
||||
Ryan Lortie
|
||||
Jeff Muizelaar
|
||||
suzuki toshiya
|
||||
|
|
52
appveyor.yml
52
appveyor.yml
|
@ -4,56 +4,50 @@ environment:
|
|||
matrix:
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14
|
||||
platform: Win32
|
||||
configuration: Debug
|
||||
triplet: x86-windows
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14 Win64
|
||||
platform: x64
|
||||
configuration: Debug
|
||||
triplet: x64-windows
|
||||
vcvarsallpath: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat
|
||||
arch: amd64
|
||||
|
||||
- compiler: msvc
|
||||
generator: Visual Studio 14 ARM
|
||||
platform: ARM
|
||||
configuration: Debug
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
compiler: msvc
|
||||
generator: Visual Studio 15
|
||||
vcvarsallpath: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat
|
||||
arch: x86
|
||||
|
||||
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
compiler: msvc
|
||||
generator: Visual Studio 16
|
||||
vcvarsallpath: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat
|
||||
arch: amd64
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /mingw64
|
||||
MINGW_CHOST: x86_64-w64-mingw32
|
||||
MSYS2_ARCH: x86_64
|
||||
MSYSTEM: MINGW64
|
||||
|
||||
- compiler: msys2
|
||||
MINGW_PREFIX: /mingw32
|
||||
MINGW_CHOST: i686-w64-mingw32
|
||||
MSYS2_ARCH: i686
|
||||
MSYSTEM: MINGW32
|
||||
|
||||
|
||||
install:
|
||||
# - '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%'
|
||||
- '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,python3,python3-pip,ragel,meson,ninja}"'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pip install fonttools"'
|
||||
|
||||
build_script:
|
||||
- 'if "%compiler%"=="msvc" md build'
|
||||
- 'if "%compiler%"=="msvc" cd build'
|
||||
- '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 ../'
|
||||
|
||||
- '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%'
|
||||
- set "PYTHON_ROOT=C:\python37-x64"
|
||||
- set "PATH=%PYTHON_ROOT%;%PYTHON_ROOT%\Scripts;%PATH%"
|
||||
- pip install --upgrade meson
|
||||
- pip install fonttools
|
||||
- 'if "%compiler%"=="msvc" "%vcvarsallpath%" %arch% && meson setup build --buildtype=release -Dglib=enabled -Dfreetype=enabled -Dgdi=enabled -Ddirectwrite=enabled && meson test --print-errorlogs --suite=harfbuzz -Cbuild'
|
||||
|
||||
- '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 -j3 check || .ci/fail.sh"'
|
||||
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; meson build --wrap-mode=nofallback -Dfreetype=enabled -Dglib=enabled -Dcairo=enabled -Dgobject=enabled -Dgdi=enabled -Ddirectwrite=enabled -Dgraphite=enabled && meson test -Cbuild --print-errorlogs"'
|
||||
|
||||
cache:
|
||||
- c:\tools\vcpkg\installed\
|
||||
- '%CYGWIN_PREFIX%\var\cache\setup'
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
pool:
|
||||
vmImage: 'VS2017-Win2016'
|
||||
|
||||
variables:
|
||||
buildPlatform: 'x86'
|
||||
buildConfiguration: 'Debug'
|
||||
triplet: 'x86-windows'
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
git clone https://github.com/Microsoft/vcpkg
|
||||
cd vcpkg
|
||||
.\bootstrap-vcpkg.bat
|
||||
.\vcpkg integrate install
|
||||
.\vcpkg install glib:x86-windows freetype:x86-windows cairo:x86-windows
|
||||
cd ..
|
||||
cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake ../
|
||||
msbuild harfbuzz.sln /p:Configuration=Debug /p:Platform=Win32
|
||||
cd build
|
||||
ctest --output-on-failure -C Debug
|
||||
displayName: Build and test
|
69
configure.ac
69
configure.ac
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[2.4.0],
|
||||
[2.6.5],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
@ -9,7 +9,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
|||
AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-xz no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_SILENT_RULES([yes])
|
||||
AX_CODE_COVERAGE
|
||||
|
||||
|
@ -23,7 +23,7 @@ AC_PROG_CC
|
|||
AC_PROG_CC_C99
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AX_CXX_COMPILE_STDCXX(11,, optional)
|
||||
AX_CXX_COMPILE_STDCXX(11)
|
||||
AC_SYS_LARGEFILE
|
||||
PKG_PROG_PKG_CONFIG([0.20])
|
||||
AM_MISSING_PROG([RAGEL], [ragel])
|
||||
|
@ -77,13 +77,7 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
|
|||
])
|
||||
|
||||
# Functions and headers
|
||||
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l posix_memalign)
|
||||
|
||||
save_libs="$LIBS"
|
||||
LIBS="$LIBS -lm"
|
||||
AC_CHECK_FUNCS([round], ,[AC_CHECK_DECLS([round], , ,[#include <math.h>])])
|
||||
LIBS="$save_libs"
|
||||
|
||||
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l roundf)
|
||||
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
|
||||
|
||||
# Compiler flags
|
||||
|
@ -134,9 +128,7 @@ AC_MSG_RESULT([$hb_os_win32])
|
|||
AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes")
|
||||
|
||||
have_pthread=false
|
||||
if test "$hb_os_win32" = no; then
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
fi
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
if $have_pthread; then
|
||||
AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
|
||||
fi
|
||||
|
@ -144,14 +136,6 @@ AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
|
|||
|
||||
dnl ==========================================================================
|
||||
|
||||
have_fallback=true
|
||||
if $have_fallback; then
|
||||
AC_DEFINE(HAVE_FALLBACK, 1, [Have simple TrueType Layout backend])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_FALLBACK, $have_fallback)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(glib,
|
||||
[AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@],
|
||||
[Use glib @<:@default=auto@:>@])],,
|
||||
|
@ -300,21 +284,6 @@ AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin")
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(ucdn,
|
||||
[AS_HELP_STRING([--with-ucdn=@<:@yes/no@:>@],
|
||||
[Use builtin UCDN library @<:@default=yes@:>@])],,
|
||||
[with_ucdn=yes])
|
||||
have_ucdn=false
|
||||
if test "x$with_ucdn" = "xyes"; then
|
||||
have_ucdn=true
|
||||
fi
|
||||
if $have_ucdn; then
|
||||
AC_DEFINE(HAVE_UCDN, 1, [Have UCDN Unicode functions])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_UCDN, $have_ucdn)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(graphite2,
|
||||
[AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@],
|
||||
[Use the graphite2 library @<:@default=no@:>@])],,
|
||||
|
@ -392,6 +361,28 @@ AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe)
|
|||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(gdi,
|
||||
[AS_HELP_STRING([--with-gdi=@<:@yes/no/auto@:>@],
|
||||
[Provide GDI integration helpers @<:@default=no@:>@])],,
|
||||
[with_gdi=no])
|
||||
have_gdi=false
|
||||
if test "x$with_gdi" = "xyes" -o "x$with_gdi" = "xauto"; then
|
||||
AC_CHECK_HEADERS(windows.h, have_gdi=true)
|
||||
fi
|
||||
if test "x$with_gdi" = "xyes" -a "x$have_gdi" != "xtrue"; then
|
||||
AC_MSG_ERROR([gdi support requested but not found])
|
||||
fi
|
||||
if $have_gdi; then
|
||||
GDI_CFLAGS=
|
||||
GDI_LIBS="-lgdi32"
|
||||
AC_SUBST(GDI_CFLAGS)
|
||||
AC_SUBST(GDI_LIBS)
|
||||
AC_DEFINE(HAVE_GDI, 1, [Have GDI library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GDI, $have_gdi)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(directwrite,
|
||||
[AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@],
|
||||
[Use the DirectWrite library (experimental) @<:@default=no@:>@])],,
|
||||
|
@ -407,7 +398,7 @@ if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
|
|||
fi
|
||||
if $have_directwrite; then
|
||||
DIRECTWRITE_CXXFLAGS=
|
||||
DIRECTWRITE_LIBS="-ldwrite"
|
||||
DIRECTWRITE_LIBS=
|
||||
AC_SUBST(DIRECTWRITE_CXXFLAGS)
|
||||
AC_SUBST(DIRECTWRITE_LIBS)
|
||||
AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
|
||||
|
@ -497,7 +488,6 @@ AC_CONFIG_FILES([
|
|||
Makefile
|
||||
src/Makefile
|
||||
src/harfbuzz-config.cmake
|
||||
src/hb-ucdn/Makefile
|
||||
util/Makefile
|
||||
test/Makefile
|
||||
test/api/Makefile
|
||||
|
@ -525,7 +515,7 @@ AC_MSG_NOTICE([
|
|||
Build configuration:
|
||||
|
||||
Unicode callbacks (you want at least one):
|
||||
Builtin (UCDN): ${have_ucdn}
|
||||
Builtin true
|
||||
Glib: ${have_glib}
|
||||
ICU: ${have_icu}
|
||||
|
||||
|
@ -542,6 +532,7 @@ Additional shapers (the more the merrier):
|
|||
Platform shapers (not normally needed):
|
||||
CoreText: ${have_coretext}
|
||||
DirectWrite: ${have_directwrite}
|
||||
GDI: ${have_gdi}
|
||||
Uniscribe: ${have_uniscribe}
|
||||
|
||||
Other features:
|
||||
|
|
|
@ -33,7 +33,7 @@ SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
|
|||
|
||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './hb-*/*.h' | sed 's@^.*/@@'`
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'`
|
||||
if HAVE_GOBJECT
|
||||
else
|
||||
IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
|
||||
|
@ -75,6 +75,7 @@ content_files= \
|
|||
usermanual-what-is-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-getting-started.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-shaping-concepts.xml \
|
||||
usermanual-object-model.xml \
|
||||
usermanual-buffers-language-script-and-direction.xml \
|
||||
|
|
|
@ -20,11 +20,7 @@
|
|||
|
||||
<para>
|
||||
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>.
|
||||
<ulink url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
|
||||
See <xref linkend="download" endterm="download.title"/> for
|
||||
release tarballs.
|
||||
</para>
|
||||
|
@ -138,6 +134,10 @@
|
|||
<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-6-0" role="2.6.0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-5-0" role="2.5.0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-4-0" role="2.4.0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-3-0" role="2.3.0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-2-0" role="2.2.0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<SUBSECTION Private>
|
||||
HB_H_IN
|
||||
HB_OT_H_IN
|
||||
HB_AAT_H_IN
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -179,6 +180,7 @@ HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
|
|||
HB_SCRIPT_CANADIAN_ABORIGINAL
|
||||
hb_font_funcs_set_glyph_func
|
||||
hb_font_get_glyph_func_t
|
||||
HB_MATH_GLYPH_PART_FLAG_EXTENDER
|
||||
hb_ot_layout_table_choose_script
|
||||
hb_ot_layout_table_find_script
|
||||
hb_ot_tag_from_language
|
||||
|
@ -195,12 +197,7 @@ 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>
|
||||
|
@ -271,6 +268,7 @@ 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
|
||||
|
@ -300,8 +298,12 @@ 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
|
||||
|
@ -323,6 +325,7 @@ hb_font_get_scale
|
|||
hb_font_get_user_data
|
||||
hb_font_get_variation_glyph
|
||||
hb_font_get_variation_glyph_func_t
|
||||
hb_font_get_var_coords_design
|
||||
hb_font_get_var_coords_normalized
|
||||
hb_font_glyph_from_string
|
||||
hb_font_glyph_to_string
|
||||
|
@ -340,6 +343,7 @@ hb_font_set_user_data
|
|||
hb_font_set_variations
|
||||
hb_font_set_var_coords_design
|
||||
hb_font_set_var_coords_normalized
|
||||
hb_font_set_var_named_instance
|
||||
hb_font_subtract_glyph_origin_for_direction
|
||||
hb_font_t
|
||||
hb_reference_table_func_t
|
||||
|
@ -362,11 +366,18 @@ hb_ft_font_create
|
|||
hb_ft_font_create_referenced
|
||||
hb_ft_font_changed
|
||||
hb_ft_font_get_face
|
||||
hb_ft_font_lock_face
|
||||
hb_ft_font_unlock_face
|
||||
hb_ft_font_set_load_flags
|
||||
hb_ft_font_get_load_flags
|
||||
hb_ft_font_set_funcs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-gdi</FILE>
|
||||
hb_gdi_face_create
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-glib</FILE>
|
||||
hb_glib_get_unicode_funcs
|
||||
|
@ -540,6 +551,9 @@ HB_OT_TAG_GDEF
|
|||
HB_OT_TAG_GPOS
|
||||
HB_OT_TAG_GSUB
|
||||
HB_OT_TAG_JSTF
|
||||
hb_ot_layout_baseline_tag_t
|
||||
hb_ot_layout_closure_lookups
|
||||
hb_ot_layout_closure_features
|
||||
hb_ot_layout_collect_lookups
|
||||
hb_ot_layout_collect_features
|
||||
hb_ot_layout_feature_get_characters
|
||||
|
@ -547,6 +561,7 @@ 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_baseline
|
||||
hb_ot_layout_get_glyph_class
|
||||
hb_ot_layout_get_glyphs_in_class
|
||||
hb_ot_layout_get_ligature_carets
|
||||
|
@ -600,6 +615,22 @@ hb_ot_math_get_min_connector_overlap
|
|||
hb_ot_math_get_glyph_assembly
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-meta</FILE>
|
||||
hb_ot_meta_tag_t
|
||||
hb_ot_meta_get_entry_tags
|
||||
hb_ot_meta_reference_entry
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-metrics</FILE>
|
||||
hb_ot_metrics_tag_t
|
||||
hb_ot_metrics_get_position
|
||||
hb_ot_metrics_get_variation
|
||||
hb_ot_metrics_get_x_variation
|
||||
hb_ot_metrics_get_y_variation
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-shape</FILE>
|
||||
hb_ot_shape_glyphs_closure
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<para>
|
||||
However, since these properties are often the repeated for
|
||||
However, since these properties are often repeated for
|
||||
multiple text runs, you can also save them in a
|
||||
<literal>hb_segment_properties_t</literal> for reuse:
|
||||
</para>
|
||||
|
@ -215,7 +215,7 @@
|
|||
bottom-to-top (<literal>HB_DIRECTION_BTT</literal>). For the
|
||||
script property, HarfBuzz uses identifiers based on the
|
||||
<ulink
|
||||
url="https://unicode.org/iso15924/">ISO-15924
|
||||
url="https://unicode.org/iso15924/">ISO 15924
|
||||
standard</ulink>. For languages, HarfBuzz uses tags based on the
|
||||
<ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
|
||||
</para>
|
||||
|
@ -300,10 +300,13 @@
|
|||
decomposing code points.
|
||||
</para>
|
||||
<para>
|
||||
At build time, HarfBuzz looks first for the GLib library. If
|
||||
it is found, HarfBuzz will use GLib's Unicode functions by
|
||||
default. If there is no GLib, HarfBuzz will fall back to its own
|
||||
internal, lightweight set of Unicode functions instead.
|
||||
HarfBuzz includes its own internal, lightweight set of Unicode
|
||||
functions. At build time, it is also possible to compile support
|
||||
for some other options, such as the Unicode functions provided
|
||||
by GLib or the International Components for Unicode (ICU)
|
||||
library. Generally, this option is only of interest for client
|
||||
programs that have specific integration requirements or that do
|
||||
a significant amount of customization.
|
||||
</para>
|
||||
<para>
|
||||
If your program has access to other Unicode functions, however,
|
||||
|
|
|
@ -156,18 +156,20 @@
|
|||
order.
|
||||
</para>
|
||||
<para>
|
||||
For left-to-right scripts (LTR) and top-to-bottom scripts (TTB),
|
||||
For buffers in the left-to-right (LTR)
|
||||
or top-to-bottom (TTB) text flow direction,
|
||||
HarfBuzz will preserve the monotonic property: client programs
|
||||
are guaranteed that monotonically increasing initial clulster
|
||||
are guaranteed that monotonically increasing initial cluster
|
||||
values will be returned as monotonically increasing final
|
||||
cluster values.
|
||||
</para>
|
||||
<para>
|
||||
For right-to-left scripts (RTL) and bottom-to-top scripts (BTT),
|
||||
For buffers in the right-to-left (RTL)
|
||||
or bottom-to-top (BTT) text flow direction,
|
||||
the directionality of the buffer itself is reversed for final
|
||||
output as a matter of design. Therefore, HarfBuzz inverts the
|
||||
monotonic property: client programs are guaranteed that
|
||||
monotonically increasing initial clulster values will be
|
||||
monotonically increasing initial cluster values will be
|
||||
returned as monotonically <emphasis>decreasing</emphasis> final
|
||||
cluster values.
|
||||
</para>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
|
||||
in HarfBuzz. This data type is a wrapper around an
|
||||
<type>hb_blob_t</type> blob that holds the contents of a binary
|
||||
fotn file. Since HarfBuzz supports TrueType Collections and
|
||||
font file. Since HarfBuzz supports TrueType Collections and
|
||||
OpenType Collections (each of which can include multiple
|
||||
typefaces), a HarfBuzz face also requires an index number
|
||||
specifying which typeface in the file you want to use. Most of
|
||||
|
@ -86,7 +86,7 @@
|
|||
objects. <function>hb_font_set_ppem(font, x_ppem,
|
||||
y_ppem)</function> sets the pixels-per-EM value of the font. You
|
||||
can also set the point size of the font with
|
||||
<function>hb_font_set_ppem(font, ptem)</function>. HarfBuzz uses the
|
||||
<function>hb_font_set_ptem(font, ptem)</function>. HarfBuzz uses the
|
||||
industry standard 72 points per inch.
|
||||
</para>
|
||||
<para>
|
||||
|
|
|
@ -246,7 +246,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GLib
|
||||
library. The default setting is to check for the
|
||||
|
@ -297,7 +297,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://www.freedesktop.org/wiki/Software/fontconfig/">Fontconfig</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Fontconfig
|
||||
library, which provides font-matching functions and
|
||||
|
@ -317,7 +317,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the
|
||||
<emphasis>International Components for
|
||||
|
@ -330,30 +330,12 @@
|
|||
</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>
|
||||
<para>
|
||||
This option enables or disables usage of the Graphite2
|
||||
library, which provides support for the Graphite shaping
|
||||
|
@ -367,7 +349,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the FreeType
|
||||
font-rendering library. The default setting is to check for the
|
||||
|
@ -384,7 +366,7 @@
|
|||
Use the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
|
||||
library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Uniscribe
|
||||
font-rendering library. Uniscribe is available on
|
||||
|
@ -400,7 +382,7 @@
|
|||
<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>
|
||||
<para>
|
||||
This option enables or disables usage of the DirectWrite
|
||||
font-rendering library. DirectWrite is available on
|
||||
|
@ -416,7 +398,7 @@
|
|||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the CoreText
|
||||
library. CoreText is available on macOS and iOS systems.
|
||||
|
|
|
@ -244,7 +244,7 @@
|
|||
<function>malloc()</function>, you would create the blob using
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
|
||||
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, data, free)
|
||||
</programlisting>
|
||||
<para>
|
||||
That way, HarfBuzz will call <function>free()</function> on the
|
||||
|
|
|
@ -66,15 +66,15 @@
|
|||
<para>
|
||||
The algorithms
|
||||
used for complex scripts can be quite involved; HarfBuzz tries
|
||||
to be 100% compatible with the OpenType Layout specification
|
||||
to be compatible with the OpenType Layout specification
|
||||
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
|
||||
output of Microsoft's Uniscribe engine. See the <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
|
||||
Typeography pages</ulink> for more detail.
|
||||
Typography pages</ulink> for more detail.
|
||||
</para>
|
||||
<para>
|
||||
In general, though, all that you need to know if that
|
||||
<function>hb-shape()</function> returns the results of shaping
|
||||
In general, though, all that you need to know is that
|
||||
<function>hb_shape()</function> returns the results of shaping
|
||||
in the same buffer that you provided. The buffer's content type
|
||||
will now be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
|
||||
|
@ -139,7 +139,8 @@
|
|||
Other features are more generic and can apply to several (or
|
||||
any) script, and shaping engines are expected to implement
|
||||
them. By default, HarfBuzz activates several of these features
|
||||
on every text run. They include <literal>ccmp</literal>,
|
||||
on every text run. They include <literal>abvm</literal>,
|
||||
<literal>blwm</literal>, <literal>ccmp</literal>,
|
||||
<literal>locl</literal>, <literal>mark</literal>,
|
||||
<literal>mkmk</literal>, and <literal>rlig</literal>.
|
||||
</para>
|
||||
|
@ -147,8 +148,9 @@
|
|||
In addition, if the text direction is horizontal, HarfBuzz
|
||||
also applies the <literal>calt</literal>,
|
||||
<literal>clig</literal>, <literal>curs</literal>,
|
||||
<literal>kern</literal>, <literal>liga</literal>,
|
||||
<literal>rclt</literal>, and <literal>frac</literal> features.
|
||||
<literal>dist</literal>, <literal>kern</literal>,
|
||||
<literal>liga</literal>, <literal>rclt</literal>,
|
||||
and <literal>frac</literal> features.
|
||||
</para>
|
||||
<para>
|
||||
If the text direction is vertical, HarfBuzz applies
|
||||
|
@ -194,7 +196,10 @@
|
|||
Just like we enabled the <literal>dlig</literal> feature by
|
||||
setting its <parameter>value</parameter> to
|
||||
<literal>1</literal>, you would disable a feature by setting its
|
||||
<parameter>value</parameter> to <literal>0</literal>.
|
||||
<parameter>value</parameter> to <literal>0</literal>. Some
|
||||
features can take other <parameter>value</parameter> settings;
|
||||
be sure you read the full specification of each feature tag to
|
||||
understand what it does and how to control it.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
@ -212,7 +217,7 @@
|
|||
mix of tables, or one of the tables might simply be broken for
|
||||
the script you need to shape. So, sometimes, you might not
|
||||
want to rely on HarfBuzz's process for deciding what to do, and
|
||||
just tell hb-shape what you want it to try.
|
||||
just tell <function>hb_shape()</function> what you want it to try.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_shape_full()</function> is an alternate shaping
|
||||
|
@ -243,7 +248,7 @@
|
|||
<para>
|
||||
Internally, HarfBuzz uses a structure called a shape plan to
|
||||
track its decisions about how to shape the contents of a
|
||||
buffer. The hb-shape function builds up the shape plan by
|
||||
buffer. The <function>hb_shape()</function> function builds up the shape plan by
|
||||
examining segment properties and by inspecting the contents of
|
||||
the font.
|
||||
</para>
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<title>Command-line tools</title>
|
||||
<para>
|
||||
HarfBuzz include three command-line tools:
|
||||
<program>hb-shape</program>, <program>hb-view</program>, and
|
||||
<program>hb-subset</program>. They can be used to examine
|
||||
<command>hb-shape</command>, <command>hb-view</command>, and
|
||||
<command>hb-subset</command>. They can be used to examine
|
||||
HarfBuzz's functionality, debug font binaries, or explore the
|
||||
various shaping models and features from a terminal.
|
||||
</para>
|
||||
|
@ -27,12 +27,12 @@
|
|||
<section id="utilities-command-line-hbshape">
|
||||
<title>hb-shape</title>
|
||||
<para>
|
||||
<emphasis><program>hb-shape</program></emphasis> allows you to run HarfBuzz's
|
||||
<emphasis><command>hb-shape</command></emphasis> allows you to run HarfBuzz's
|
||||
<function>hb_shape()</function> function on an input string and
|
||||
to examine the outcome, in human-readable form, as terminal
|
||||
output. <program>hb-shape</program> does
|
||||
output. <command>hb-shape</command> does
|
||||
<emphasis>not</emphasis> render the results of the shaping call
|
||||
into rendered text (you can use <program>hb-view</program>, below, for
|
||||
into rendered text (you can use <command>hb-view</command>, below, for
|
||||
that). Instead, it prints out the final glyph indices and
|
||||
positions, taking all shaping operations into account, as if the
|
||||
input string were a HarfBuzz input buffer.
|
||||
|
@ -80,10 +80,10 @@
|
|||
<section id="utilities-command-line-hbview">
|
||||
<title>hb-view</title>
|
||||
<para>
|
||||
<emphasis><program>hb-view</program></emphasis> allows you to
|
||||
<emphasis><command>hb-view</command></emphasis> allows you to
|
||||
see the shaped output of an input string in rendered
|
||||
form. Like <program>hb-shape</program>,
|
||||
<program>hb-view</program> takes a font file and a text string
|
||||
form. Like <command>hb-shape</command>,
|
||||
<command>hb-view</command> takes a font file and a text string
|
||||
as its arguments:
|
||||
</para>
|
||||
<programlisting>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
By default, <program>hb-view</program> renders the shaped
|
||||
By default, <command>hb-view</command> renders the shaped
|
||||
text in ASCII block-character images as terminal output. By
|
||||
appending the
|
||||
<command>--output-file=<optional>filename</optional></command>
|
||||
|
@ -100,7 +100,7 @@
|
|||
(among other formats).
|
||||
</para>
|
||||
<para>
|
||||
As with <program>hb-shape</program>, a lengthy set of options
|
||||
As with <command>hb-shape</command>, a lengthy set of options
|
||||
is available, with which you can enable or disable
|
||||
specific font features, set variation-font axis values,
|
||||
alter the language, script, direction, and clustering settings
|
||||
|
@ -114,10 +114,10 @@
|
|||
with
|
||||
</para>
|
||||
<para>
|
||||
In general, <program>hb-view</program> is a quick way to
|
||||
In general, <command>hb-view</command> is a quick way to
|
||||
verify that the output of HarfBuzz's shaping operation looks
|
||||
correct for a given text-and-font combination, but you may
|
||||
want to use <program>hb-shape</program> to figure out exactly
|
||||
want to use <command>hb-shape</command> to figure out exactly
|
||||
why something does not appear as expected.
|
||||
</para>
|
||||
</section>
|
||||
|
@ -125,13 +125,13 @@
|
|||
<section id="utilities-command-line-hbsubset">
|
||||
<title>hb-subset</title>
|
||||
<para>
|
||||
<emphasis><program>hb-subset</program></emphasis> allows you
|
||||
<emphasis><command>hb-subset</command></emphasis> allows you
|
||||
to generate a subset of a given font, with a limited set of
|
||||
supported characters, features, and variation settings.
|
||||
</para>
|
||||
<para>
|
||||
By default, you provide an input font and an input text string
|
||||
as the arguments to <program>hb-subset</program>, and it will
|
||||
as the arguments to <command>hb-subset</command>, and it will
|
||||
generate a font that covers the input text exactly like the
|
||||
input font does, but includes no other characters or features.
|
||||
</para>
|
||||
|
|
|
@ -151,9 +151,9 @@
|
|||
</para>
|
||||
<para>
|
||||
For example, in Tamil, when the letter "TTA" (ட)
|
||||
letter is followed by "U" (உ), the pair
|
||||
letter is followed by the vowel sign "U" (ு), the pair
|
||||
must be replaced by the single glyph "டு". The
|
||||
sequence of Unicode characters "டஉ" needs to be
|
||||
sequence of Unicode characters "ட,ு" needs to be
|
||||
substituted with a single "டு" glyph from the
|
||||
font.
|
||||
</para>
|
||||
|
|
|
@ -422,7 +422,7 @@ namespace cxx11
|
|||
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||
// because of this.
|
||||
namespace test_template_alias_sfinae
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
void memory_barrier (void) { __sync_synchronize (); }
|
||||
int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
|
||||
int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
|
||||
void mutex_unlock (int *m) { __sync_lock_release (m); }
|
||||
|
||||
int main(void) { return 0;}
|
|
@ -0,0 +1,8 @@
|
|||
#include <atomic.h>
|
||||
/* This requires Solaris Studio 12.2 or newer: */
|
||||
#include <mbarrier.h>
|
||||
void memory_barrier (void) { __machine_rw_barrier (); }
|
||||
int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
|
||||
void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
|
||||
|
||||
int main(void) { return 0; }
|
|
@ -0,0 +1,348 @@
|
|||
project('harfbuzz', 'c', 'cpp',
|
||||
meson_version: '>= 0.47.0',
|
||||
default_options : ['cpp_std=c++11'],
|
||||
version: '2.6.5')
|
||||
|
||||
warning('Meson is not our main build system yet, don\'t use it for packaging HarfBuzz for *nix distros for now')
|
||||
|
||||
hb_version_arr = meson.project_version().split('.')
|
||||
hb_version_major = hb_version_arr[0].to_int()
|
||||
hb_version_minor = hb_version_arr[1].to_int()
|
||||
hb_version_micro = hb_version_arr[2].to_int()
|
||||
|
||||
# libtool versioning
|
||||
hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro
|
||||
if hb_version_minor % 2 == 1
|
||||
hb_libtool_revision = 0 # for unstable releases
|
||||
else
|
||||
hb_libtool_revision = hb_version_micro # for stable releases
|
||||
endif
|
||||
hb_libtool_age = hb_version_int - hb_libtool_revision
|
||||
hb_libtool_current = hb_libtool_age
|
||||
hb_libtool_version_info = '@0@:@1@:@2@'.format(hb_libtool_current, hb_libtool_revision, hb_libtool_age)
|
||||
|
||||
pkgmod = import('pkgconfig')
|
||||
cpp = meson.get_compiler('cpp')
|
||||
|
||||
if cpp.get_id() == 'msvc'
|
||||
# Ignore several spurious warnings for things HarfBuzz does very commonly.
|
||||
# If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
|
||||
# If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
|
||||
# NOTE: Only add warnings here if you are sure they're spurious
|
||||
msvc_args = [
|
||||
'/wd4018', # implicit signed/unsigned conversion
|
||||
'/wd4146', # unary minus on unsigned (beware INT_MIN)
|
||||
'/wd4244', # lossy type conversion (e.g. double -> int)
|
||||
'/wd4305', # truncating type conversion (e.g. double -> float)
|
||||
cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
|
||||
]
|
||||
add_project_arguments(msvc_args, language : ['c', 'cpp'])
|
||||
# Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW
|
||||
# noseh_link_args = ['/SAFESEH:NO']
|
||||
endif
|
||||
|
||||
add_project_arguments(cpp.get_supported_arguments([
|
||||
'-fno-rtti',
|
||||
'-fno-exceptions',
|
||||
'-fno-threadsafe-statics',
|
||||
'-fvisibility-inlines-hidden', # maybe shouldn't be applied for mingw
|
||||
]), language : 'cpp')
|
||||
|
||||
if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') != 1
|
||||
if cpp.has_argument('-mstructure-size-boundary=8')
|
||||
add_project_arguments('-mstructure-size-boundary=8', language : 'cpp')
|
||||
endif
|
||||
endif
|
||||
|
||||
python3 = import('python').find_installation('python3')
|
||||
|
||||
check_headers = [
|
||||
['unistd.h'],
|
||||
['sys/mman.h'],
|
||||
['xlocale.h'],
|
||||
['stdbool.h'],
|
||||
]
|
||||
|
||||
check_funcs = [
|
||||
['atexit'],
|
||||
['mprotect'],
|
||||
['sysconf'],
|
||||
['getpagesize'],
|
||||
['mmap'],
|
||||
['isatty'],
|
||||
['newlocale'],
|
||||
['strtod_l'],
|
||||
['roundf'],
|
||||
]
|
||||
|
||||
freetype_dep = dependency('freetype2', required: false)
|
||||
|
||||
if not freetype_dep.found() and cpp.get_id() == 'msvc'
|
||||
if cpp.has_header('ft2build.h')
|
||||
freetype_dep = cpp.find_library('freetype', required: false)
|
||||
endif
|
||||
endif
|
||||
|
||||
if not freetype_dep.found() and get_option('freetype').enabled()
|
||||
freetype_dep = dependency('freetype2', fallback: ['freetype2', 'freetype_dep'])
|
||||
endif
|
||||
|
||||
glib_dep = dependency('glib-2.0', required: get_option('glib'),
|
||||
fallback: ['glib', 'libglib_dep'])
|
||||
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'),
|
||||
fallback: ['glib', 'libgobject_dep'])
|
||||
cairo_dep = dependency('cairo', required: false)
|
||||
fontconfig_dep = dependency('fontconfig', required: get_option('fontconfig'),
|
||||
fallback: ['fontconfig', 'fontconfig_dep'])
|
||||
graphite2_dep = dependency('graphite2', required: get_option('graphite'))
|
||||
icu_dep = dependency('icu-uc', required: false)
|
||||
m_dep = cpp.find_library('m', required: false)
|
||||
|
||||
if not icu_dep.found() and get_option('icu').enabled()
|
||||
icu_dep = dependency('icu-uc', required: cpp.get_id() != 'msvc')
|
||||
endif
|
||||
|
||||
if not icu_dep.found() and cpp.get_id() == 'msvc'
|
||||
if cpp.has_header('unicode/uchar.h') and \
|
||||
cpp.has_header('unicode/unorm2.h') and \
|
||||
cpp.has_header('unicode/ustring.h') and \
|
||||
cpp.has_header('unicode/utf16.h') and \
|
||||
cpp.has_header('unicode/uversion.h') and \
|
||||
cpp.has_header('unicode/uscript.h')
|
||||
if get_option('buildtype') == 'debug'
|
||||
icu_dep = cpp.find_library('icuucd', required: get_option('icu'))
|
||||
else
|
||||
icu_dep = cpp.find_library('icuuc', required: get_option('icu'))
|
||||
endif
|
||||
else
|
||||
if get_option('icu').enabled()
|
||||
error('ICU headers and libraries must be present to build ICU support')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if not cairo_dep.found() and cpp.get_id() == 'msvc'
|
||||
if cpp.has_header('cairo.h')
|
||||
cairo_dep = cpp.find_library('cairo')
|
||||
endif
|
||||
endif
|
||||
|
||||
if not cairo_dep.found() and get_option('cairo').enabled()
|
||||
cairo_dep = dependency('cairo', fallback: ['cairo', 'libcairo_dep'])
|
||||
endif
|
||||
|
||||
# Ensure that cairo-ft is fetched from the same library as cairo itself
|
||||
if cairo_dep.found()
|
||||
if cairo_dep.type_name() == 'pkgconfig'
|
||||
cairo_ft_dep = dependency('cairo-ft', required: get_option('cairo'))
|
||||
else
|
||||
if cpp.has_header('cairo-ft.h') and \
|
||||
cpp.has_function('cairo_ft_font_face_create_for_ft_face', dependencies: cairo_dep)
|
||||
cairo_ft_dep = cairo_dep
|
||||
endif
|
||||
endif
|
||||
else
|
||||
# Not-found dependency
|
||||
cairo_ft_dep = dependency('', required: false)
|
||||
endif
|
||||
|
||||
deps = []
|
||||
|
||||
conf = configuration_data()
|
||||
incconfig = include_directories('.')
|
||||
|
||||
add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
|
||||
|
||||
warn_cflags = [
|
||||
'-Wno-non-virtual-dtor',
|
||||
]
|
||||
|
||||
cpp_args = cpp.get_supported_arguments(warn_cflags)
|
||||
|
||||
if m_dep.found()
|
||||
deps += [m_dep]
|
||||
endif
|
||||
|
||||
if glib_dep.found()
|
||||
conf.set('HAVE_GLIB', 1)
|
||||
deps += [glib_dep]
|
||||
endif
|
||||
|
||||
if gobject_dep.found()
|
||||
conf.set('HAVE_GOBJECT', 1)
|
||||
deps += [gobject_dep]
|
||||
endif
|
||||
|
||||
if cairo_dep.found()
|
||||
conf.set('HAVE_CAIRO', 1)
|
||||
deps += [cairo_dep]
|
||||
endif
|
||||
|
||||
if cairo_ft_dep.found()
|
||||
conf.set('HAVE_CAIRO_FT', 1)
|
||||
deps += [cairo_ft_dep]
|
||||
endif
|
||||
|
||||
if graphite2_dep.found()
|
||||
conf.set('HAVE_GRAPHITE2', 1)
|
||||
deps += [graphite2_dep]
|
||||
endif
|
||||
|
||||
if icu_dep.found()
|
||||
conf.set('HAVE_ICU', 1)
|
||||
endif
|
||||
|
||||
if get_option('icu-builtin')
|
||||
conf.set('HAVE_ICU_BUILTIN', 1)
|
||||
endif
|
||||
|
||||
if get_option('experimental-api')
|
||||
conf.set('HB_EXPERIMENTAL_API', 1)
|
||||
endif
|
||||
|
||||
if freetype_dep.found()
|
||||
conf.set('HAVE_FREETYPE', 1)
|
||||
deps += [freetype_dep]
|
||||
check_freetype_funcs = [
|
||||
['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
|
||||
['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
|
||||
['FT_Done_MM_Var', {'deps': freetype_dep}],
|
||||
]
|
||||
|
||||
if freetype_dep.type_name() == 'internal'
|
||||
foreach func: check_freetype_funcs
|
||||
name = func[0]
|
||||
conf.set('HAVE_@0@'.format(name.to_upper()), 1)
|
||||
endforeach
|
||||
else
|
||||
check_funcs += check_freetype_funcs
|
||||
endif
|
||||
endif
|
||||
|
||||
if fontconfig_dep.found()
|
||||
conf.set('HAVE_FONTCONFIG', 1)
|
||||
deps += [fontconfig_dep]
|
||||
endif
|
||||
|
||||
# GDI (uniscribe) (windows)
|
||||
if host_machine.system() == 'windows' and not get_option('gdi').disabled()
|
||||
# TODO: make nicer once we have https://github.com/mesonbuild/meson/issues/3940
|
||||
if cpp.has_header('usp10.h') and cpp.has_header('windows.h')
|
||||
foreach usplib : ['usp10', 'gdi32', 'rpcrt4']
|
||||
deps += [cpp.find_library(usplib, required: true)]
|
||||
endforeach
|
||||
conf.set('HAVE_UNISCRIBE', 1)
|
||||
conf.set('HAVE_GDI', 1)
|
||||
elif get_option('gdi').enabled()
|
||||
error('gdi was enabled explicitly, but some required headers are missing.')
|
||||
endif
|
||||
endif
|
||||
|
||||
# DirectWrite (windows)
|
||||
if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
|
||||
if cpp.has_header('dwrite_1.h')
|
||||
deps += [cpp.find_library('dwrite', required: true)]
|
||||
conf.set('HAVE_DIRECTWRITE', 1)
|
||||
elif get_option('directwrite').enabled()
|
||||
error('DirectWrite was enabled explicitly, but required header is missing.')
|
||||
endif
|
||||
endif
|
||||
|
||||
# CoreText (macOS) - FIXME: untested
|
||||
if host_machine.system() == 'darwin' and not get_option('coretext').disabled()
|
||||
app_services_dep = dependency('appleframeworks', modules : ['ApplicationServices'], required: false)
|
||||
if cpp.has_type('CTFontRef', prefix: '#include <ApplicationServices/ApplicationServices.h>', dependencies: app_services_dep)
|
||||
deps += [app_services_dep]
|
||||
conf.set('HAVE_CORETEXT', 1)
|
||||
# On iOS CoreText and CoreGraphics are stand-alone frameworks
|
||||
# Check for a different symbol to avoid getting cached result
|
||||
else
|
||||
coretext_dep = dependency('appleframeworks', modules : ['CoreText'], required: false)
|
||||
coregraphics_dep = dependency('appleframeworks', modules : ['CoreGraphics'], required: false)
|
||||
corefoundation_dep = dependency('appleframeworks', modules : ['CoreFoundation'], required: false)
|
||||
if cpp.has_type('CTRunRef', prefix: '#include <CoreText/CoreText.h>', dependencies: [coretext_dep, coregraphics_dep, corefoundation_dep])
|
||||
deps += [coretext_dep, coregraphics_dep, corefoundation_dep]
|
||||
conf.set('HAVE_CORETEXT', 1)
|
||||
elif get_option('coretext').enabled()
|
||||
error('CoreText was enabled explicitly, but required headers or frameworks are missing.')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# threads
|
||||
if host_machine.system() != 'windows'
|
||||
thread_dep = dependency('threads', required: false)
|
||||
|
||||
if thread_dep.found()
|
||||
conf.set('HAVE_PTHREAD', 1)
|
||||
deps += [thread_dep]
|
||||
else
|
||||
check_headers += ['sched.h']
|
||||
check_funcs += ['sched_yield', {'link_with': 'rt'}]
|
||||
endif
|
||||
endif
|
||||
|
||||
conf.set('HAVE_OT', 1)
|
||||
conf.set('HAVE_FALLBACK', 1)
|
||||
conf.set_quoted('PACKAGE_NAME', 'HarfBuzz')
|
||||
conf.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
||||
foreach check : check_headers
|
||||
name = check[0]
|
||||
|
||||
if cpp.has_header(name)
|
||||
conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
foreach check : check_funcs
|
||||
name = check[0]
|
||||
opts = check.get(1, {})
|
||||
link_withs = opts.get('link_with', [])
|
||||
check_deps = opts.get('deps', [])
|
||||
extra_deps = []
|
||||
found = true
|
||||
|
||||
# First try without linking
|
||||
|
||||
found = cpp.has_function(name, dependencies: check_deps)
|
||||
|
||||
if not found and link_withs.length() > 0
|
||||
found = true
|
||||
|
||||
foreach link_with : link_withs
|
||||
dep = cpp.find_library(link_with, required: false)
|
||||
if dep.found()
|
||||
extra_deps += dep
|
||||
else
|
||||
found = false
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if found
|
||||
found = cpp.has_function(name, dependencies: check_deps + extra_deps)
|
||||
endif
|
||||
endif
|
||||
|
||||
if found
|
||||
deps += extra_deps
|
||||
conf.set('HAVE_@0@'.format(name.to_upper()), 1)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if cpp.links(files('meson-cc-tests/intel-atomic-primitives-test.c'), name: 'Intel atomics')
|
||||
conf.set('HAVE_INTEL_ATOMIC_PRIMITIVES', 1)
|
||||
endif
|
||||
|
||||
if cpp.links(files('meson-cc-tests/solaris-atomic-operations.c'), name: 'Solaris atomic ops')
|
||||
conf.set('HAVE_SOLARIS_ATOMIC_OPS', 1)
|
||||
endif
|
||||
|
||||
subdir('src')
|
||||
subdir('util')
|
||||
|
||||
if not get_option('tests').disabled()
|
||||
subdir('test')
|
||||
endif
|
||||
|
||||
configure_file(output: 'config.h', configuration: conf)
|
|
@ -0,0 +1,34 @@
|
|||
# HarfBuzz feature options
|
||||
option('glib', type: 'feature', value: 'auto',
|
||||
description: 'Enable GLib unicode functions')
|
||||
option('gobject', type: 'feature', value: 'disabled',
|
||||
description: 'Enable GObject bindings')
|
||||
option('cairo', type: 'feature', value: 'auto',
|
||||
description: 'Use Cairo graphics library')
|
||||
option('fontconfig', type: 'feature', value: 'auto',
|
||||
description: 'Use fontconfig')
|
||||
option('icu', type: 'feature', value: 'auto',
|
||||
description: 'Enable ICU library unicode functions')
|
||||
option('graphite', type: 'feature', value: 'disabled',
|
||||
description: 'Enable Graphite2 complementary shaper')
|
||||
option('freetype', type: 'feature', value: 'auto',
|
||||
description: 'Enable freetype interop helpers')
|
||||
option('gdi', type: 'feature', value: 'disabled',
|
||||
description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
|
||||
option('directwrite', type: 'feature', value: 'disabled',
|
||||
description: 'Enable DirectWrite shaper backend on Windows (experimental)')
|
||||
option('coretext', type: 'feature', value: 'disabled',
|
||||
description: 'Enable CoreText shaper backend on macOS')
|
||||
|
||||
# Common feature options
|
||||
option('tests', type : 'feature', value : 'enabled', yield : true,
|
||||
description: 'Enable or disable unit tests')
|
||||
option('introspection', type : 'feature', value : 'disabled', yield : true,
|
||||
description : 'Generate gobject-introspection bindings (.gir/.typelib files)')
|
||||
|
||||
option('icu-builtin', type: 'boolean', value: false,
|
||||
description: 'Don\'t separate ICU support as harfbuzz-icu module')
|
||||
option('experimental-api', type: 'boolean', value: false,
|
||||
description: 'Enable experimental APIs')
|
||||
option('amalgam', type : 'boolean', value : false,
|
||||
description : 'Enable amalgam builds')
|
|
@ -0,0 +1,28 @@
|
|||
#!/bin/sh
|
||||
|
||||
case $1 in
|
||||
i686 | x86_64) ;;
|
||||
*) echo "Usage: $0 i686|x86_64" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
target=$1-w64-mingw32
|
||||
shift
|
||||
|
||||
exec "$(dirname "$0")"/configure \
|
||||
--build=`../config.guess` \
|
||||
--host=$target \
|
||||
--prefix=$HOME/.local/$target \
|
||||
CC= \
|
||||
CXX= \
|
||||
CPP= \
|
||||
LD= \
|
||||
CFLAGS="-static-libgcc" \
|
||||
CXXFLAGS="-static-libgcc -static-libstdc++" \
|
||||
CPPFLAGS="-I$HOME/.local/$target/include" \
|
||||
LDFLAGS=-L$HOME/.local/$target/lib \
|
||||
PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
|
||||
PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
|
||||
PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
|
||||
--without-icu \
|
||||
--with-uniscribe \
|
||||
"$@"
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py
|
||||
# Modified to point to right prefix location on Fedora.
|
||||
|
||||
# WTFPL - Do What the Fuck You Want to Public License
|
||||
import pefile
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def get_dependency(filename):
|
||||
deps = []
|
||||
pe = pefile.PE(filename)
|
||||
for imp in pe.DIRECTORY_ENTRY_IMPORT:
|
||||
deps.append(imp.dll.decode())
|
||||
return deps
|
||||
|
||||
|
||||
def dep_tree(root, prefix=None):
|
||||
if not prefix:
|
||||
arch = get_arch(root)
|
||||
#print('Arch =', arch)
|
||||
prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin'
|
||||
#print('Using default prefix', prefix)
|
||||
dep_dlls = dict()
|
||||
|
||||
def dep_tree_impl(root, prefix):
|
||||
for dll in get_dependency(root):
|
||||
if dll in dep_dlls:
|
||||
continue
|
||||
full_path = os.path.join(prefix, dll)
|
||||
if os.path.exists(full_path):
|
||||
dep_dlls[dll] = full_path
|
||||
dep_tree_impl(full_path, prefix=prefix)
|
||||
else:
|
||||
dep_dlls[dll] = 'not found'
|
||||
|
||||
dep_tree_impl(root, prefix)
|
||||
return (dep_dlls)
|
||||
|
||||
|
||||
def get_arch(filename):
|
||||
type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686',
|
||||
pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'}
|
||||
pe = pefile.PE(filename)
|
||||
try:
|
||||
return type2arch[pe.PE_TYPE]
|
||||
except KeyError:
|
||||
sys.stderr.write('Error: unknown architecture')
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
filename = sys.argv[1]
|
||||
for dll, full_path in dep_tree(filename).items():
|
||||
print(' ' * 7, dll, '=>', full_path)
|
||||
|
24
mingw32.sh
24
mingw32.sh
|
@ -1,22 +1,2 @@
|
|||
#!/bin/bash
|
||||
|
||||
target=i686-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS="-I$HOME/.local/$target/include -O2"
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/mingw-configure.sh i686 "$@"
|
||||
|
|
24
mingw64.sh
24
mingw64.sh
|
@ -1,22 +1,2 @@
|
|||
#!/bin/bash
|
||||
|
||||
target=x86_64-w64-mingw32
|
||||
|
||||
unset CC
|
||||
unset CXX
|
||||
unset CPP
|
||||
unset LD
|
||||
unset LDFLAGS
|
||||
unset CFLAGS
|
||||
unset CXXFLAGS
|
||||
unset PKG_CONFIG_PATH
|
||||
|
||||
# Removed -static from the following
|
||||
export CFLAGS="-static-libgcc"
|
||||
export CXXFLAGS="-static-libgcc -static-libstdc++"
|
||||
export CPPFLAGS="-I$HOME/.local/$target/include -O2"
|
||||
export LDFLAGS=-L$HOME/.local/$target/lib
|
||||
export PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig
|
||||
export PATH=$HOME/.local/$target/bin:$PATH
|
||||
|
||||
../configure --build=`../config.guess` --host=$target --prefix=$HOME/.local/$target "$@"
|
||||
#!/bin/sh
|
||||
exec "$(dirname "$0")"/mingw-configure.sh x86_64 "$@"
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
CXX=clang++
|
||||
FONT=fonts/NotoNastaliqUrdu-Regular.ttf
|
||||
TEXT=texts/fa-monologue.txt
|
||||
|
||||
$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \
|
||||
-lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \
|
||||
-I../src $FLAGS $SOURCES \
|
||||
-DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \
|
||||
-DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \
|
||||
-o hb-shape -g -O2 # -O3 \
|
||||
#-march=native -mtune=native \
|
||||
#-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \
|
||||
#-Rpass-analysis=loop-vectorize -fsave-optimization-record
|
||||
|
||||
# -march=native: enable all vector instructions current CPU can offer
|
||||
# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics
|
||||
|
||||
#sudo rm capture.syscap > /dev/null
|
||||
#sysprof-cli -c "./a.out $@"
|
||||
#sysprof capture.syscap
|
||||
|
||||
perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
|
||||
#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
|
||||
#perf report -g
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,923 @@
|
|||
شازده کوچولو
|
||||
اثر آنتوان دو سنتگزوپهری
|
||||
برگردان احمد شاملو
|
||||
|
||||
|
||||
اهدانامچه
|
||||
به لئون ورث Leon Werth
|
||||
از بچهها عذر میخواهم که این کتاب را به یکی از بزرگترها هدیه کردهام. برای این کار یک دلیل حسابی دارم: این «بزرگتر» بهترین دوست من تو همه دنیا است. یک دلیل دیگرم هم آن که این «بزرگتر» همه چیز را میتواند بفهمد حتا کتابهایی را که برای بچهها نوشته باشند. عذر سومم این است که این «بزرگتر» تو فرانسه زندگی میکند و آنجا گشنگی و تشنگی میکشد و سخت محتاج دلجویی است. اگر همهی این عذرها کافی نباشد اجازه میخواهم این کتاب را تقدیم آن بچهای کنم که این آدمبزرگ یک روزی بوده. آخر هر آدم بزرگی هم روزی روزگاری بچهای بوده (گیرم کمتر کسی از آنها این را به یاد میآورد). پس من هم اهدانامچهام را به این شکل تصحیح میکنم:
|
||||
|
||||
به لئون ورث
|
||||
موقعی که پسربچه بود
|
||||
آنتوان دو سنتگزوپهری
|
||||
|
||||
من هم برگردان فارسی این شعر بزرگ را به دو بچهی دوستداشتنی دیگر تقدیم میکنم: دکتر جهانگیر کازرونی و دکتر محمدجواد گلبن
|
||||
|
||||
احمد شاملو
|
||||
|
||||
۱
|
||||
یک بار شش سالم که بود تو کتابی به اسم قصههای واقعی -که دربارهی جنگل بِکر نوشته شده بود- تصویر محشری دیدم از یک مار بوآ که داشت حیوانی را میبلعید. آن تصویر یک چنین چیزی بود:
|
||||
|
||||
یک مار بوآ که دارد حیوانی را میبلعد
|
||||
تو کتاب آمده بود که: «مارهای بوآ شکارشان را همین جور درسته قورت میدهند. بی این که بجوندش. بعد دیگر نمیتوانند از جا بجنبند و تمام شش ماهی را که هضمش طول میکشد میگیرند میخوابند».
|
||||
|
||||
این را که خواندم، راجع به چیزهایی که تو جنگل اتفاق میافتد کلی فکر کردم و دست آخر توانستم با یک مداد رنگی اولین نقاشیم را از کار درآرم. یعنی نقاشی شمارهی یکم را که این جوری بود:
|
||||
|
||||
نقاشی شمارهی یکم — مار شبیه به کلاه
|
||||
شاهکارم را نشان بزرگتر ها دادم و پرسیدم از دیدنش ترستان بر میدارد؟
|
||||
جوابم دادند: -چرا کلاه باید آدم را بترساند؟
|
||||
|
||||
نقاشی من کلاه نبود، یک مار بوآ بود که داشت یک فیل را هضم میکرد. آن وقت برای فهم بزرگترها برداشتم توی شکم بوآ را کشیدم. آخر همیشه باید به آنها توضیحات داد. نقاشی دومم این جوری بود:
|
||||
|
||||
نقاشی دوم — مار و فیل درونش
|
||||
بزرگترها بم گفتند کشیدن مار بوآی باز یا بسته را بگذارم کنار و عوضش حواسم را بیشتر جمع جغرافی و تاریخ و حساب و دستور زبان کنم. و این جوری شد که تو شش سالگی دور کار ظریف نقاشی را قلم گرفتم. از این که نقاشی شمارهی یک و نقاشی شمارهی دو ام یخشان نگرفت دلسرد شده بودم. بزرگترها اگر به خودشان باشد هیچ وقت نمیتوانند از چیزی سر درآرند. برای بچهها هم خسته کننده است که همین جور مدام هر چیزی را به آنها توضیح بدهند.
|
||||
|
||||
ناچار شدم برای خودم کار دیگری پیدا کنم و این بود که رفتم خلبانی یاد گرفتم. بگویی نگویی تا حالا به همه جای دنیا پرواز کرده ام و راستی راستی جغرافی خیلی بم خدمت کرده. میتوانم به یک نظر چین و آریزونا را از هم تمیز بدهم. اگر آدم تو دل شب سرگردان شده باشد جغرافی خیلی به دادش میرسد.
|
||||
|
||||
از این راه است که من تو زندگیم با گروه گروه آدمهای حسابی برخورد داشتهام. پیش خیلی از بزرگترها زندگی کردهام و آنها را از خیلی نزدیک دیدهام گیرم این موضوع باعث نشده در بارهی آنها عقیدهی بهتری پیدا کنم.
|
||||
|
||||
هر وقت یکیشان را گیر آوردهام که یک خرده روشن بین به نظرم آمده با نقاشی شمارهی یکم که هنوز هم دارمش محکش زدهام ببینم راستی راستی چیزی بارش هست یا نه. اما او هم طبق معمول در جوابم در آمده که: «این یک کلاه است». آن وقت دیگر من هم نه از مارهای بوآ باش اختلاط کردهام نه از جنگلهای بکر دست نخورده نه از ستارهها. خودم را تا حد او آوردهام پایین و باش از بریج و گلف و سیاست و انواع کرات حرف زدهام. او هم از این که با یک چنین شخص معقولی آشنایی به هم رسانده سخت خوشوقت شده.
|
||||
|
||||
۲
|
||||
این جوری بود که روزگارم تو تنهایی میگذشت بی این که راستی راستی یکی را داشته باشم که باش دو کلمه حرف بزنم، تااین که زد و شش سال پیش در کویر صحرا حادثهیی برایم اتفاق افتاد؛ یک چیز موتور هواپیمایم شکسته بود و چون نه تعمیرکاری همراهم بود نه مسافری یکه و تنها دست به کار شدم تا از پس چنان تعمیر مشکلی برآیم. مسالهی مرگ و زندگی بود. آبی که داشتم زورکی هشت روز را کفاف میداد.
|
||||
|
||||
شب اول را هزار میل دورتر از هر آبادی مسکونی رو ماسهها به روز آوردم پرت افتادهتر از هر کشتی شکستهیی که وسط اقیانوس به تخته پارهیی چسبیده باشد. پس لابد میتوانید حدس بزنید چه جور هاج و واج ماندم وقتی کلهی آفتاب به شنیدن صدای ظریف عجیبی که گفت: «بی زحمت یک برّه برام بکش!» از خواب پریدم.
|
||||
-ها؟
|
||||
-یک برّه برام بکش...
|
||||
|
||||
چنان از جا جستم که انگار صاعقه بم زده. خوب که چشمهام را مالیدم و نگاه کردم آدم کوچولوی بسیار عجیبی را دیدم که با وقار تمام تو نخ من بود. این بهترین شکلی است که بعد ها توانستم از او در آرم، گیرم البته آنچه من کشیدهام کجا و خود او کجا! تقصیر من چیست؟ بزرگتر ها تو شش سالگی از نقاشی دلسردم کردند و جز بوآی باز و بسته یاد نگرفتم چیزی بکشم.
|
||||
|
||||
با چشمهایی که از تعجب گرد شده بود به این حضور ناگهانی خیره شدم. یادتان نرود که من از نزدیکترین آبادی مسکونی هزار میل فاصله داشتم و این آدمیزاد کوچولوی من هم اصلا به نظر نمیآمد که راه گم کرده باشد یا از خستگی دم مرگ باشد یا از گشنگی دم مرگ باشد یا از تشنگی دم مرگ باشد یا از وحشت دم مرگ باشد. هیچ چیزش به بچهیی نمیبُرد که هزار میل دور از هر آبادی مسکونی تو دل صحرا گم شده باشد.
|
||||
|
||||
این بهترین شکلی است که بعدها از او در آوردم.
|
||||
وقتی بالاخره صدام در آمد، گفتم:
|
||||
-آخه... تو این جا چه میکنی؟
|
||||
و آن وقت او خیلی آرام، مثل یک چیز خیلی جدی، دوباره در آمد که:
|
||||
-بی زحمت واسهی من یک برّه بکش.
|
||||
آدم وقتی تحت تاثیر شدید رازی قرار گرفت جرات نافرمانی نمیکند. گرچه تو آن نقطهی هزار میل دورتر از هر آبادی مسکونی و با قرار داشتن در معرض خطر مرگ این نکته در نظرم بی معنی جلوه کرد باز کاغذ و خودنویسی از جیبم در آوردم اما تازه یادم آمد که آنچه من یاد گرفتهام بیشتر جغرافیا و تاریخ و حساب و دستور زبان است، و با کج خلقی مختصری به آن موجود کوچولو گفتم نقاشی بلد نیستم.
|
||||
بم جواب داد: -عیب ندارد، یک بَرّه برام بکش.
|
||||
|
||||
از آنجایی که هیچ وقت تو عمرم بَرّه نکشیده بودم یکی از آن دو تا نقاشیای را که بلد بودم برایش کشیدم. آن بوآی بسته را. ولی چه یکهای خوردم وقتی آن موجود کوچولو در آمد که: -نه! نه! فیلِ تو شکم یک بوآ نمیخواهم. بوآ خیلی خطرناک است فیل جا تنگ کن. خانهی من خیلی کوچولوست، من یک بره لازم دارم. برام یک بره بکش.برهی مریض
|
||||
-خب، کشیدم.
|
||||
با دقت نگاهش کرد و گفت:
|
||||
-نه! این که همین حالاش هم حسابی مریض است. یکی دیگر بکش.قوچ
|
||||
-کشیدم.
|
||||
لبخند با نمکی زد و در نهایت گذشت گفت:
|
||||
-خودت که میبینی... این بره نیست، قوچ است. شاخ دارد نه...برهی پیر
|
||||
باز نقاشی را عوض کردم.
|
||||
آن را هم مثل قبلی ها رد کرد:
|
||||
-این یکی خیلی پیر است... من یک بره میخواهم که مدت ها عمر کند...
|
||||
|
||||
باری چون عجله داشتم که موتورم را پیاده کنم رو بی حوصلگی جعبهای کشیدم که دیوارهاش سه تا سوراخ داشت، و از دهنم پرید که:جعبه
|
||||
-این یک جعبه است. برهای که میخواهی این تو است.
|
||||
|
||||
و چه قدر تعجب کردم از این که دیدم داور کوچولوی من قیافهاش از هم باز شد و گفت:
|
||||
-آها... این درست همان چیزی است که میخواستم! فکر میکنی این بره خیلی علف بخواهد؟
|
||||
-چطور مگر؟
|
||||
-آخر جای من خیلی تنگ است...
|
||||
-هر چه باشد حتماً بسش است. برهیی که بت دادهام خیلی کوچولوست.
|
||||
-آن قدرهاهم کوچولو نیست... اِه! گرفته خوابیده...
|
||||
|
||||
و این جوری بود که من با شهریار کوچولو آشنا شدم.
|
||||
|
||||
۳
|
||||
خیلی طول کشید تا توانستم بفهمم از کجا آمده. شهریار کوچولو که مدام مرا سوال پیچ میکرد خودش انگار هیچ وقت سوالهای مرا نمیشنید. فقط چیزهایی که جسته گریخته از دهنش میپرید کم کم همه چیز را به من آشکار کرد. مثلا اول بار که هواپیمای مرا دید (راستی من هواپیما نقاشی نمیکنم، سختم است.) ازم پرسید:
|
||||
-این چیز چیه؟
|
||||
-این «چیز» نیست: این پرواز میکند. هواپیماست. هواپیمای من است.
|
||||
|
||||
و از این که بهاش میفهماندم من کسیام که پرواز میکنم به خود میبالیدم.
|
||||
حیرت زده گفت: -چی؟ تو از آسمان افتادهای؟
|
||||
با فروتنی گفتم: -آره.
|
||||
گفت: -اوه، این دیگر خیلی عجیب است!
|
||||
و چنان قهقههی ملوسی سر داد که مرا حسابی از جا در برد. راستش من دلم میخواهد دیگران گرفتاریهایم را جدی بگیرند.
|
||||
خندههایش را که کرد گفت: -خب، پس تو هم از آسمان میآیی! اهل کدام سیارهای؟...
|
||||
|
||||
بفهمی نفهمی نور مبهمی به معمای حضورش تابید. یکهو پرسیدم:
|
||||
-پس تو از یک سیارهی دیگر آمدهای؟
|
||||
آرام سرش را تکان داد بی این که چشم از هواپیما بردارد.
|
||||
|
||||
اما جوابم را نداد، تو نخ هواپیما رفته بود و آرام آرام سر تکان میداد.
|
||||
گفت: -هر چه باشد با این نباید از جای خیلی دوری آمده باشی...
|
||||
|
||||
مدت درازی تو خیال فرو رفت، بعد برهاش را از جیب در آورد و محو تماشای آن گنج گرانبها شد.تصویری از شهریار کوچولو بر روی زمین
|
||||
فکر میکنید از این نیمچه اعتراف «سیارهی دیگر»ِ او چه هیجانی به من دست داد؟ زیر پاش نشستم که حرف بیشتری از زبانش بکشم:
|
||||
-تو از کجا میآیی آقا کوچولوی من؟ خانهات کجاست؟ برهی مرا میخواهی کجا ببری؟
|
||||
مدتی در سکوت به فکر فرورفت و بعد در جوابم گفت:
|
||||
-حسن جعبهای که بم دادهای این است که شبها میتواند خانهاش بشود.
|
||||
-معلوم است... اما اگر بچهی خوبی باشی یک ریسمان هم بِت میدهم که روزها ببندیش. یک ریسمان با یک میخ طویله...
|
||||
انگار از پیشنهادم جا خورد، چون که گفت:
|
||||
-ببندمش؟ چه فکر ها!
|
||||
-آخر اگر نبندیش راه میافتد میرود گم میشود.
|
||||
|
||||
دوست کوچولوی من دوباره غش غش خنده را سر داد:
|
||||
-مگر کجا میتواند برود؟
|
||||
-خدا میداند. راستِ شکمش را میگیرد و میرود...
|
||||
-بگذار برود...اوه، خانهی من آنقدر کوچک است!
|
||||
و شاید با یک خرده اندوه در آمد که:
|
||||
-یکراست هم که بگیرد برود جای دوری نمیرود...
|
||||
|
||||
۴
|
||||
به این ترتیب از یک موضوع خیلی مهم دیگر هم سر در آوردم: این که سیارهی او کمی از یک خانهی معمولی بزرگتر بود.این نکته آنقدرها به حیرتم نینداخت. میدانستم گذشته از سیارههای بزرگی مثل زمین و کیوان و تیر و ناهید که هرکدام برای خودشان اسمی دارند، صدها سیارهی دیگر هم هست که بعضیشان از بس کوچکند با دوربین نجومی هم به هزار زحمت دیده میشوند و هرگاه اخترشناسی یکیشان را کشف کند به جای اسم شمارهای بهاش میدهد. مثلا اسمش را میگذارد «اخترک ۳۲۵۱».
|
||||
|
||||
دلایل قاطعی دارم که ثابت میکند شهریار کوچولو از اخترک ب۶۱۲ آمدهبود.
|
||||
|
||||
شهریار کوچولو بر اخترکِ ب۶۱۲
|
||||
این اخترک را فقط یک بار به سال ۱۹۰۹ یک اخترشناس ترک توانسته بود ببیند اخترشناسِ ترک در حالِ دیدنِ اخترکِ ب۶۱۲که تو یک کنگرهی بینالمللی نجوم هم با کشفش هیاهوی زیادی به راه انداخت اما واسه خاطر لباسی که تنش بود هیچ کس حرفش را باور نکرد. اخترشناسِ ترک در کنگرهی بینالمللیِ نجوم، با لباس قدیمیآدم بزرگها این جوریاند!
|
||||
|
||||
بختِ اخترک ب۶۱۲ زد و، ترک مستبدی ملتش را به ضرب دگنک وادار به پوشیدن لباس اروپاییها کرد. اخترشناس به سال ۱۹۲۰ دوباره، و این بار با سر و وضع آراسته برای کشفش ارائهی دلیل کرد و این بار همه جانب او را گرفتند.اخترشناسِ ترک در کنگرهی بینالمللیِ نجوم، با لباس جدید
|
||||
به خاطر آدم بزرگهاست که من این جزئیات را در باب اخترکِ ب۶۱۲ برایتان نقل میکنم یا شمارهاش را میگویم چون که آنها عاشق عدد و رقماند. وقتی با آنها از یک دوست تازهتان حرف بزنید هیچ وقت ازتان دربارهی چیزهای اساسیاش سوال نمیکنند که هیج وقت نمیپرسند «آهنگ صداش چهطور است؟ چه بازیهایی را بیشتر دوست دارد؟ پروانه جمع میکند یا نه؟» -میپرسند: «چند سالش است؟ چند تا برادر دارد؟ وزنش چهقدر است؟ پدرش چهقدر حقوق میگیرد؟» و تازه بعد از این سوالها است که خیال میکنند طرف را شناختهاند.
|
||||
|
||||
اگر به آدم بزرگها بگویید یک خانهی قشنگ دیدم از آجر قرمز که جلو پنجرههاش غرقِ شمعدانی و بامش پر از کبوتر بود محال است بتوانند مجسمش کنند. باید حتماً بهشان گفت یک خانهی صد میلیون تومنی دیدم تا صداشان بلند بشود که: -وای چه قشنگ!
|
||||
|
||||
یا مثلا اگر بهشان بگویید «دلیل وجودِ شهریارِ کوچولو این که تودلبرو بود و میخندید و دلش یک بره میخواست و بره خواستن، خودش بهترین دلیل وجود داشتن هر کسی است» شانه بالا میاندازند و باتان مثل بچهها رفتار میکنند! اما اگر بهشان بگویید «سیارهای که ازش آمدهبود اخترک ب۶۱۲ است» بیمعطلی قبول میکنند و دیگر هزار جور چیز ازتان نمیپرسند. این جوریاند دیگر. نباید ازشان دلخور شد. بچهها باید نسبت به آدم بزرگها گذشت داشته باشند.
|
||||
|
||||
اما البته ماها که مفهوم حقیقی زندگی را درک میکنیم میخندیم به ریش هرچه عدد و رقم است! چیزی که من دلم میخواست این بود که این ماجرا را مثل قصهی پریا نقل کنم. دلم میخواست بگویم: «یکی بود یکی نبود. روزی روزگاری یه شهریار کوچولو بود که تو اخترکی زندگی میکرد همهاش یه خورده از خودش بزرگتر و واسه خودش پیِ دوستِ همزبونی میگشت...»، آن هایی که مفهوم حقیقی زندگی را درک کردهاند واقعیت قضیه را با این لحن بیشتر حس میکنند. آخر من دوست ندارم کسی کتابم را سرسری بخواند. خدا میداند با نقل این خاطرات چه بار غمی روی دلم مینشیند. شش سالی میشود که دوستم با بَرّهاش رفته. این که این جا میکوشم او را وصف کنم برای آن است که از خاطرم نرود. فراموش کردن یک دوست خیلی غمانگیز است. همه کس که دوستی ندارد. من هم میتوانم مثل آدم بزرگها بشوم که فقط اعداد و ارقام چشمشان را میگیرد. و باز به همین دلیل است که رفتهام یک جعبه رنگ و چند تا مداد خریدهام. تو سن و سال من واسه کسی که جز کشیدنِ یک بوآی باز یا یک بوآی بسته هیچ کار دیگری نکرده -و تازه آن هم در شش سالگی- دوباره به نقاشی رو کردن از آن حرفهاست! البته تا آنجا که بتوانم سعی میکنم چیزهایی که میکشم تا حد ممکن شبیه باشد. گیرم به موفقیت خودم اطمینان چندانی ندارم. یکیش شبیه از آب در میآید یکیش نه. سرِ قدّ و قوارهاش هم حرف است. یک جا زیادی بلند درش آوردهام یک جا زیادی کوتاه. از رنگ لباسش هم مطمئن نیستم. خب، رو حدس و گمان پیش رفتهام؛ کاچی به زِ هیچی. و دست آخر گفته باشم که تو بعضِ جزئیات مهمترش هم دچار اشتباه شدهام. اما در این مورد دیگر باید ببخشید: دوستم زیر بار هیچ جور شرح و توصیفی نمیرفت. شاید مرا هم مثل خودش میپنداشت. اما از بختِ بد، دیدن برهها از پشتِ جعبه از من بر نمیآید. نکند من هم یک خرده به آدم بزرگها رفتهام؟ «باید پیر شده باشم».
|
||||
|
||||
۵
|
||||
هر روزی که میگذشت از اخترک و از فکرِ عزیمت و از سفر و این حرفها چیزهای تازهای دستگیرم میشد که همهاش معلولِ بازتابهایِ اتفاقی بود. و از همین راه بود که روز سوم از ماجرایِ تلخِ بائوباب ها سردرآوردم.
|
||||
|
||||
این بار هم بَرّه باعثش شد، چون شهریار کوچولو که انگار سخت دودل ماندهبود ناگهان ازم پرسید:
|
||||
-بَرّهها بتهها را هم میخورند دیگر، مگر نه؟
|
||||
-آره. همین جور است.
|
||||
-آخ! چه خوشحال شدم!
|
||||
|
||||
نتوانستم بفهمم این موضوع که بَرّهها بوتهها را هم میخورند اهمیتش کجاست اما شهریار کوچولو درآمد که:
|
||||
-پس لابد بائوباب ها را هم میخورند دیگر؟
|
||||
|
||||
یک گله فیل که در اخترکِ ب۶۱۲ روی هم چیده شدهاندمن برایش توضیح دادم که بائوباب بُتّه نیست. درخت است و از ساختمان یک معبد هم گندهتر، و اگر یک گَلّه فیل هم با خودش ببرد حتا یک درخت بائوباب را هم نمیتوانند بخورند.
|
||||
از فکر یک گَلّه فیل به خنده افتاد و گفت: -باید چیدشان روی هم.
|
||||
اما با فرزانگی تمام متذکر شد که: -بائوباب هم از بُتِّگی شروع میکند به بزرگ شدن.
|
||||
-درست است. اما نگفتی چرا دلت میخواهد برههایت نهالهای بائوباب را بخورند؟
|
||||
گفت: -دِ! معلوم است!
|
||||
|
||||
و این را چنان گفت که انگار موضوع از آفتاب هم روشنتر است؛ منتها من برای این که به تنهایی از این راز سر در آرم ناچار شدم حسابی کَلّه را به کار بیندازم.
|
||||
|
||||
راستش این که تو اخترکِ شهریار کوچولو هم مثل سیارات دیگر هم گیاهِ خوب به هم میرسید هم گیاهِ بد. یعنی هم تخمِ خوب گیاههای خوب به هم میرسید، هم تخمِ بدِ گیاههایِ بد. اما تخم گیاهها نامرییاند. آنها تو حرمِ تاریک خاک به خواب میروند تا یکیشان هوس بیدار شدن به سرش بزند. آن وقت کش و قوسی میآید و اول با کم رویی شاخکِ باریکِ خوشگل و بیآزاری به طرف خورشید میدواند. اگر این شاخک شاخکِ تربچهای گلِ سرخی چیزی باشد میشود گذاشت برای خودش رشد کند اما اگر گیاهِ بدی باشد آدم باید به مجردی که دستش را خواند ریشهکنش کند.
|
||||
|
||||
باری، تو سیارهی شهریار کوچولو گیاه تخمههای وحشتناکی به هم میرسید. یعنی تخم درختِ بائوباب که خاکِ سیاره حسابی ازشان لطمه خورده بود. بائوباب هم اگر دیر بهاش برسند دیگر هیچ جور نمیشود حریفش شد: تمام سیاره را میگیرد و با ریشههایش سوراخ سوراخش میکند و اگر سیاره خیلی کوچولو باشد و بائوبابها خیلی زیاد باشند پاک از هم متلاشیش میکنند.
|
||||
|
||||
شهریار کوچولو در حال نظافت ِ اخترکششهریار کوچولو بعدها یک روز به من گفت: «این، یک امر انضباطی است. صبح به صبح بعد از نظافتِ خود باید با دفت تمام به نظافتِ اخترک پرداخت. آدم باید خودش را مجبور کند که به مجردِ تشخیص دادن بائوبابها از بتههای گلِ سرخ که تا کوچولواَند عین هماَند با دقت ریشهکنشان بکند. کار کسلکنندهای هست اما هیچ مشکل نیست.»
|
||||
|
||||
یک روز هم بم توصیه کرد سعی کنم هر جور شده یک نقاشی حسابی از کار درآرم که بتواند قضیه را به بچههای سیارهی من هم حالی کند. گفت اگر یک روز بروند سفر ممکن است به دردشان بخورد. پارهای وقتها پشت گوش انداختن کار ایرادی ندارد اما اگر پای بائوباب در میان باشد گاوِ آدم میزاید. اخترکی را سراغ دارم که یک تنبلباشی ساکنش بود و برای کندن سه تا نهال بائوباب امروز و فردا کرد...».
|
||||
|
||||
آن وقت من با استفاده از چیزهایی که گفت شکل آن اخترک را کشیدم.
|
||||
|
||||
اخترکِ تنبلباشی با سه درختِ بائوباب
|
||||
هیچ دوست ندارم اندرزگویی کنم. اما خطر بائوبابها آنقدر کم شناخته شده و سر راهِ کسی که تو چنان اخترکی سرگیدان بشود آن قدر خطر به کمین نشسته که این مرتبه را از رویهی همیشگی خودم دست بر میدارم و میگویم: «بچهها! هوای بائوبابها را داشته باشید!»
|
||||
|
||||
اگر من سرِ این نقاشی این همه به خودم فشار آوردهام فقط برای آن بوده که دوستانم را متوجه خطری کنم که از مدتها پیش بیخ گوششان بوده و مثلِ خودِ من ازش غافل بودهاند. درسی که با این نقاشی دادهام به زحمتش میارزد. حالا ممکن است شما از خودتان بپرسید: «پس چرا هیچ کدام از بقیهی نقاشیهای این کتاب هیبتِ تصویرِ بائوبابها را ندارد؟» -خب، جوابش خیلی ساده است: من زور خودم را زدهام اما نتوانستهام از کار درشان بیاورم. اما عکس بائوبابها را که میکشیدم احساس میکردم قضیه خیلی فوریت دارد و به این دلیل شور بَرَم داشته بود.
|
||||
|
||||
۶
|
||||
آخ، شهریار کوچولو! این جوری بود که من کَم کَمَک از زندگیِ محدود و دلگیر تو سر درآوردم. تا مدتها تنها سرگرمیِ تو تماشای زیباییِ غروب آفتاب بوده. به این نکتهی تازه صبح روز چهارم بود که پی بردم؛ یعنی وقتی که به من گفتی:
|
||||
-غروب آفتاب را خیلی دوست دارم. برویم فرورفتن آفتاب را تماشا کنیم...شهریار کوچولو در اخترکش مشغولِ تماشای غروبِ آفتاب
|
||||
-هوم، حالاها باید صبر کنی...
|
||||
-واسه چی صبر کنم؟
|
||||
-صبر کنی که آفتاب غروب کند.
|
||||
|
||||
اول سخت حیرت کردی بعد از خودت خندهات گرفت و برگشتی به من گفتی:
|
||||
-همهاش خیال میکنم تو اخترکِ خودمم!
|
||||
-راستش موقعی که تو آمریکا ظهر باشد همه میدانند تو فرانسه تازه آفتاب دارد غروب میکند. کافی است آدم بتواند در یک دقیقه خودش را برساند به فرانسه تا بتواند غروب آفتاب را تماشا کند. متاسفانه فرانسه کجا اینجا کجا! اما رو اخترک تو که به آن کوچکی است همینقدر که چند قدمی صندلیت را جلو بکشی میتوانی هرقدر دلت خواست غروب تماشا کنی.
|
||||
-یک روز چهل و سه بار غروب آفتاب را تماشا کردم!
|
||||
و کمی بعد گفت:
|
||||
-خودت که میدانی... وقتی آدم خیلی دلش گرفته باشد از تماشای غروب لذت میبرد.
|
||||
-پس خدا میداند آن روز چهل و سه غروبه چهقدر دلت گرفته بوده.
|
||||
|
||||
اما مسافر کوچولو جوابم را نداد.
|
||||
|
||||
۷
|
||||
روز پنجم باز سرِ گوسفند از یک راز دیگر زندگی شهریار کوچولو سر در آوردم. مثل چیزی که مدتها تو دلش بهاش فکر کرده باشد یکهو بی مقدمه از من پرسید:
|
||||
-گوسفندی که بُتّه ها را بخورد گل ها را هم میخورد؟
|
||||
-گوسفند هرچه گیرش بیاید میخورد.
|
||||
-حتا گلهایی را هم که خار دارند؟
|
||||
-آره، حتا گلهایی را هم که خار دارند.
|
||||
-پس خارها فایدهشان چیست؟
|
||||
|
||||
من چه میدانستم؟ یکی از آن: سخت گرفتار باز کردن یک مهرهی سفتِ موتور بودم. از این که یواش یواش بو میبردم خرابیِ کار به آن سادگیها هم که خیال میکردم نیست برج زهرمار شدهبودم و ذخیرهی آبم هم که داشت ته میکشید بیشتر به وحشتم میانداخت.
|
||||
-پس خارها فایدهشان چسیت؟
|
||||
|
||||
شهریار کوچولو وقتی سوالی را میکشید وسط دیگر به این مفتیها دست بر نمیداشت. مهره پاک کلافهام کرده بود. همین جور سرسری پراندم که:
|
||||
-خارها به درد هیچ کوفتی نمیخورند. آنها فقط نشانهی بدجنسی گلها هستند.
|
||||
-دِ!
|
||||
و پس از لحظهیی سکوت با یک جور کینه درآمد که:
|
||||
-حرفت را باور نمیکنم! گلها ضعیفند. بی شیلهپیلهاند. سعی میکنند یک جوری تهِ دل خودشان را قرص کنند. این است که خیال میکنند با آن خارها چیزِ ترسناکِ وحشتآوری میشوند...
|
||||
|
||||
لام تا کام بهاش جواب ندادم. در آن لحظه داشتم تو دلم میگفتم: «اگر این مهرهی لعنتی همین جور بخواهد لج کند با یک ضربهی چکش حسابش را میرسم.» اما شهریار کوچولو دوباره افکارم را به هم ریخت:
|
||||
-تو فکر میکنی گلها...
|
||||
من باز همان جور بیتوجه گفتم:
|
||||
-ای داد بیداد! ای داد بیداد! نه، من هیچ کوفتی فکر نمیکنم! آخر من گرفتار هزار مسالهی مهمتر از آنم!
|
||||
هاج و واج نگاهم کرد و گفت:
|
||||
-مسالهی مهم!
|
||||
|
||||
مرا میدید که چکش به دست با دست و بالِ سیاه روی چیزی که خیلی هم به نظرش زشت میآمد خم شدهام.
|
||||
-مثل آدم بزرگها حرف میزنی!
|
||||
از شنیدنِ این حرف خجل شدم اما او همین جور بیرحمانه میگفت:
|
||||
-تو همه چیز را به هم میریزی... همه چیز را قاتی میکنی!
|
||||
حسابی از کوره در رفتهبود.
|
||||
|
||||
موهای طلایی طلائیش تو باد میجنبید.
|
||||
-اخترکی را سراغ دارم که یک آقا سرخ روئه توش زندگی میکند. او هیچ وقت یک گل را بو نکرده، هیچ وقت یک ستارهرا تماشا نکرده هیچ وقت کسی را دوست نداشته هیچ وقت جز جمع زدن عددها کاری نکرده. او هم مثل تو صبح تا شب کارش همین است که بگوید: «من یک آدم مهمم! یک آدم مهمم!» این را بگوید و از غرور به خودش باد کند. اما خیال کرده: او آدم نیست، یک قارچ است!
|
||||
-یک چی؟
|
||||
-یک قارچ!گلِ سرخ
|
||||
حالا دیگر رنگش از فرط خشم مثل گچ سفید شدهبود:
|
||||
-کرورها سال است که گلها خار میسازند و با وجود این کرورها سال است که برّهها گلها را میخورند. آن وقت هیچ مهم نیست آدم بداند پس چرا گلها واسه ساختنِ خارهایی که هیچ وقتِ خدا به هیچ دردی نمیخورند این قدر به خودشان زحمت میدهند؟ جنگ میان برّهها و گلها هیچ مهم نیست؟ این موضوع از آن جمع زدنهای آقا سرخروئهیِ شکمگنده مهمتر و جدیتر نیست؟ اگر من گلی را بشناسم که تو همهی دنیا تک است و جز رو اخترک خودم هیچ جای دیگر پیدا نمیشه و ممکن است یک روز صبح یک برّه کوچولو، مفت و مسلم، بی این که بفهمد چهکار دارد میکند به یک ضرب پاک از میان ببردش چی؟ یعنی این هم هیچ اهمیتی ندارد؟ اگر کسی گلی را دوست داشته باشد که تو کرورها و کرورها ستاره فقط یک دانه ازش هست واسه احساس وشبختی همین قدر بس است که نگاهی به آن همه ستاره بیندازد و با خودش بگوید: «گل من یک جایی میان آن ستارههاست»، اما اگر برّه گل را بخورد برایش مثل این است که یکهو تمام آن ستارهها پِتّی کنند و خاموش بشوند. یعنی این هم هیچ اهمیتی ندارد؟
|
||||
دیگر نتوانست چیزی بگوید و ناگهان هِق هِق کنان زد زیر گریه.
|
||||
|
||||
حالا دیگر شب شدهبود. اسباب و ابزارم را کنار انداختهبودم. دیگر چکش و مهره و تشنگی و مرگ به نظرم مضحک میآمد. رو ستارهای، رو سیارهای، رو سیارهی من، زمین، شهریارِ کوچولویی بود که احتیاج به دلداری داشت! به آغوشش گرفتم مثل گهواره تابش دادم بهاش گفتم: «گلی که تو دوست داری تو خطر نیست. خودم واسه گوسفندت یک پوزهبند میکشم... خودم واسه گفت یک تجیر میکشم... خودم...» بیش از این نمیدانستم چه بگویم. خودم را سخت چُلمَن و بی دست و پا حس میکردم. نمیدانستم چهطور باید خودم را بهاش برسانم یا بهاش بپیوندم...p چه دیار اسرارآمیزی است دیار اشک!
|
||||
|
||||
۸
|
||||
راه شناختن آن گل را خیلی زود پیدا کردم:
|
||||
تو اخترکِ شهریار کوچولو همیشه یک مشت گلهای خیلی ساده در میآمده. گلهایی با یک ردیف گلبرگ که جای چندانی نمیگرفته، دست و پاگیرِ کسی نمیشده. صبحی سر و کلهشان میان علفها پیدا میشده شب از میان میرفتهاند. اما این یکی یک روز از دانهای جوانه زده بود که خدا میدانست از کجا آمده رود و شهریار کوچولو با جان و دل از این شاخکِ نازکی که به هیچ کدام از شاخکهای دیگر نمیرفت مواظبت کردهبود. بعید بنود که این هم نوعِ تازهای از بائوباب باشد اما بته خیلی زود از رشد بازماند و دستبهکارِ آوردن گل شد. شهریار کوچولو که موقعِ نیش زدن آن غنچهی بزرگ حاضر و ناظر بود به دلش افتاد که باید چیز معجزهآسایی از آن بیرون بیاید. اما گل تو پناهِ خوابگاهِ سبزش سر فرصت دست اندکار خودآرایی بود تا هرچه زیباتر جلوهکند. رنگهایش را با وسواس تمام انتخاب میکرد سر صبر لباس میپوشید و گلبرگها را یکی یکی به خودش میبست. دلش نمیخواست مثل شقایقها با جامهی مچاله و پر چروک بیرون بیاید.
|
||||
|
||||
شهریار کوچولو و گلِ سرخنمیخواست جز در اوج درخشندگی زیبائیش رو نشان بدهد!...
|
||||
|
||||
هوه، بله عشوهگری تمام عیار بود! آرایشِ پر راز و رمزش روزها و روزها طول کشید تا آن که سرانجام یک روز صبح درست با بر آمدن آفتاب نقاب از چهره برداشت و با این که با آن همه دقت و ظرافت روی آرایش و پیرایش خودش کار کرده بود خمیازهکشان گفت:
|
||||
-اوه، تازه همین حالا از خواب پا شدهام... عذر میخواهم که موهام این جور آشفتهاست...
|
||||
|
||||
شهریار کوچولو نتوانست جلو خودش را بگیرد و از ستایش او خودداری کند:
|
||||
-وای چهقدر زیبائید!
|
||||
گل به نرمی گفت:
|
||||
-چرا که نه؟ من و آفتاب تو یک لحظه به دنیا آمدیم...
|
||||
شهریار کوچولو شستش خبردار شد که طرف آنقدرها هم اهل شکستهنفسی نیست اما راستی که چهقدر هیجان انگیز بود!
|
||||
-به نظرم وقت خوردن ناشتایی است. بی زحمت برایم فکری بکنید.
|
||||
و شهریار کوچولوی مشوش و در هم یک آبپاش آب خنک آورده به گل دادهبود.شهریار کوچولو در حالِ تماشای گلِ سرخ
|
||||
با این حساب، هنوزهیچی نشده با آن خودپسندیش که بفهمینفهمی از ضعفش آب میخورد دل او را شکسته بود. مثلا یک روز که داشت راجع به چهارتا خارش حرف میزد یکهو در آمده بود که:ببر و گلِ سرخ
|
||||
-نکند ببرها با آن چنگالهای تیزشان بیایند سراغم!
|
||||
شهریار کوچولو ازش ایراد گرفتهبود که:
|
||||
-تو اخترک من ببر به هم نمیرسد. تازه ببرها که علفخوار نیستند.
|
||||
گل به گلایه جواب داده بود:
|
||||
-من که علف نیستم.
|
||||
و شهریار کوچولو گفته بود:
|
||||
-عذر میخواهم...
|
||||
-من از ببرها هیچ ترسی ندارم اما از جریان هوا وحشت میکنم. تو دستگاهتان تجیر به هم نمیرسد؟شهریار کوچولو در حالِ پوشاندنِ گلِ سرخ
|
||||
شهریار کوچولو تو دلش گفت: «وحشت از جریان هوا... این که واسه یک گیاه تعریفی ندارد... چه مرموز است این گل!»
|
||||
-شب مرا بگذارید زیر یک سرپوش. این جا هواش خیلی سرد است. چه جای بدی افتادم! جایی که پیش از این بودم...شهریار کوچولو در حالِ گذاشتنِ سرپوش روی گلِ سرخ
|
||||
اما حرفش را خورده بود. آخر، آمدنا هنوز به شکل دانه بود. امکان نداشت توانستهباشد دنیاهای دیگری را بشناسد. شرمسار از این که گذاشته بود سر به هم بافتن دروغی به این آشکاری مچش گیربیفتد دو سه بار سرفه کرده بود تا اهمالِ شهریار کوچولو را بهاش یادآور شود:
|
||||
-تجیر کو پس؟
|
||||
-داشتم میرفتم اما شما داشتید صحبت میکردید!
|
||||
و با وجود این زورکی بنا کردهبود به سرفه کردن تا او احساس پشیمانی کند.
|
||||
|
||||
به این ترتیب شهریار کوچولو با همهی حسن نیّتی که از عشقش آب میخورد همان اول کار به او بد گمان شدهبود. حرفهای بی سر و تهش را جدی گرفتهبود و سخت احساس شوربختی میکرد.
|
||||
|
||||
یک روز دردِدل کنان به من گفت: -حقش بود به حرفهاش گوش نمیدادم. هیچ وقت نباید به حرف گلها گوش داد. گل را فقط باید بوئید و تماشا کرد. گلِ من تمامِ اخترکم را معطر میکرد گیرم من بلد نبودم چهجوری از آن لذت ببرم. قضیهی چنگالهای ببر که آن جور دَمَغم کردهبود میبایست دلم را نرم کرده باشد...»
|
||||
|
||||
یک روز دیگر هم به من گفت: «آن روزها نتوانستم چیزی بفهمم. من بایست روی کرد و کارِ او در بارهاش قضاوت میکردم نه روی گفتارش... عطرآگینم میکرد. دلم را روشن میکرد. نمیبایست ازش بگریزم. میبایست به مهر و محبتی که پشتِ آن کلکهای معصومانهاش پنهان بود پی میبردم. گلها پُرَند از این جور تضادها. اما خب دیگر، من خامتر از آن بودم که راهِ دوست داشتنش را بدانم!».
|
||||
|
||||
۹
|
||||
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرندههای وحشی استفاده کرد.
|
||||
|
||||
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرندههای وحشی استفاده کرد.
|
||||
صبح روز حرکت، اخترکش را آن جور که باید مرتب کرد، آتشفشانهای فعالش را با دقت پاک و دودهگیری کرد: شهریار کوچولو در حالِ پاک کردنِ آتشفشان.دو تا آتشفشان فعال داشت که برای گرم کردن ناشتایی خیلی خوب بود. یک آتشفشان خاموش هم داشت. منتها به قول خودش «آدم کف دستش را که بو نکرده!» این بود که آتشفشان خاموش را هم پاک کرد. آتشفشان که پاک باشد مرتب و یک هوا میسوزد و یکهو گُر نمیزند. آتشفشان هم عینهو بخاری یکهو اَلُو میزند. البته ما رو سیارهمان زمین کوچکتر از آن هستیم که آتشفشانهامان را پاک و دودهگیری کنیم و برای همین است که گاهی آن جور اسباب زحمتمان میشوند.
|
||||
|
||||
شهریار کوچولو با دلِگرفته آخرین نهالهای بائوباب را هم ریشهکن کرد. فکر میکرد دیگر هیچ وقت نباید برگردد. اما آن روز صبح گرچه از این کارهای معمولیِ هر روزه کُلّی لذت برد موقعی که آخرین آب را پای گل داد و خواست بگذاردش زیرِ سرپوش چیزی نماندهبود که اشکش سرازیر شود.
|
||||
به گل گفت: -خدا نگهدار!
|
||||
اما او جوابش را نداد.
|
||||
دوباره گفت: -خدا نگهدار!
|
||||
گل سرفهکرد، گیرم این سرفه اثر چائیدن نبود. بالاخره به زبان آمد و گفت:
|
||||
-من سبک مغز بودم. ازت عذر میخواهم. سعی کن خوشبخت باشی.
|
||||
از این که به سرکوفت و سرزنشهای همیشگی برنخورد حیرت کرد و سرپوش به دست هاجوواج ماند. از این محبتِ آرام سر در نمیآورد.
|
||||
گل بهاش گفت: -خب دیگر، دوستت دارم. اگر تو روحت هم از این موضوع خبردار نشد تقصیر من است. باشد، زیاد مهم نیست. اما تو هم مثل من بیعقل بودی... سعی کن خوشبخت بشوی... این سرپوش را هم بگذار کنار، دیگر به دردم نمیخورد.
|
||||
-آخر، باد...
|
||||
-آن قدرهاهم سَرمائو نیستم... هوای خنک شب برای سلامتیم خوب است. خدانکرده گُلم آخر.
|
||||
-آخر حیوانات...
|
||||
-اگر خواستهباشم با شبپرهها آشنا بشوم جز این که دو سه تا کرمِ حشره را تحمل کنم چارهای ندارم. شبپره باید خیلی قشنگ باشد. جز آن کی به دیدنم میآید؟ تو که میروی به آن دور دورها. از بابتِ درندهها هم هیچ کَکَم نمیگزد: «من هم برای خودم چنگ و پنجهای دارم».
|
||||
و با سادگی تمام چهارتا خارش را نشان داد. بعد گفت:
|
||||
-دستدست نکن دیگر! این کارت خلق آدم را تنگ میکند. حالا که تصمیم گرفتهای بروی برو!
|
||||
|
||||
و این را گفت، چون که نمیخواست شهریار کوچولو گریهاش را ببیند. گلی بود تا این حد خودپسند...
|
||||
|
||||
۱۰
|
||||
خودش را در منطقهی اخترکهای ۳۲۵، ۳۲۶، ۳۲۷، ۳۲۸، ۳۲۹ و ۳۳۰ دید. این بود که هم برای سرگرمی و هم برای چیزیادگرفتن بنا کرد یکییکیشان را سیاحت کردن.
|
||||
|
||||
اخترکِ اول مسکن پادشاهی بود که با شنلی از مخمل ارغوانی قاقم بر اورنگی بسیار ساده و در عین حال پرشکوه نشسته بود و همین که چشمش به شهریار کوچولو افتاد داد زد:
|
||||
-خب، این هم رعیت!
|
||||
شهریار کوچولو از خودش پرسید: -او که تا حالا هیچ وقت مرا ندیده چه جوری میتواند بشناسدم؟
|
||||
دیگر اینش را نخواندهبود که دنیابرای پادشاهان به نحو عجیبی ساده شده و تمام مردم فقط یک مشت رعیت به حساب میآیند.
|
||||
|
||||
پادشاه در سیارهاش
|
||||
پادشاه که میدید بالاخره شاهِ کسی شده و از این بابت کبکش خروس میخواند گفت: -بیا جلو بهتر ببینیمت. شهریار کوچولو با چشم پیِ جایی گشت که بنشیند اما شنلِ قاقمِ حضرتِ پادشاهی تمام اخترک را دربرگرفتهبود. ناچار همان طور سر پا ماند و چون سخت خسته بود به دهندره افتاد.
|
||||
شاه بهاش گفت: -خمیازه کشیدن در حضرتِ سلطان از نزاکت به دور است. این کار را برایت قدغن میکنم. شهریار کوچولو که سخت خجل شدهبود در آمد که:
|
||||
-نمیتوانم جلوِ خودم را بگیرم. راه درازی طیکردهام و هیچ هم نخوابیدهام...
|
||||
پادشاه گفت: -خب خب، پس بِت امر میکنم خمیازه بکشی. سالهاست خمیازهکشیدن کسی را ندیدهام برایم تازگی دارد. یاالله باز هم خمیازه بکش. این یک امر است.
|
||||
شهریار کوچولو گفت: -آخر این جوری من دست و پایم را گم میکنم... دیگر نمیتوانم.
|
||||
شاه گفت: -هوم! هوم! خب، پس من بهات امر میکنم که گاهی خمیازه بکشی گاهی نه.
|
||||
تند و نامفهوم حرف میزد و انگار خلقش حسابی تنگ بود.
|
||||
|
||||
پادشاه فقط دربند این بود که مطیع فرمانش باشند. در مورد نافرمانیها هم هیچ نرمشی از خودش نشان نمیداد. یک پادشاهِ تمام عیار بود گیرم چون زیادی خوب بود اوامری که صادر میکرد اوامری بود منطقی. مثلا خیلی راحت در آمد که: «اگر من به یکی از سردارانم امر کنم تبدیل به یکی از این مرغهای دریایی بشود و یارو اطاعت نکند تقسیر او نیست که، تقصیر خودم است».
|
||||
شهریار کوچولو در نهایت ادب پرسید: -اجازه میفرمایید بنشینم؟
|
||||
پادشاه که در نهایتِ شکوه و جلال چینی از شنل قاقمش را جمع میکرد گفت: -بهات امر میکنیم بنشینی.
|
||||
|
||||
منتها شهریار کوچولو ماندهبود حیران: آخر آن اخترک کوچکتر از آن بود که تصورش را بشود کرد. واقعا این پادشاه به چی سلطنت میکرد؟ گفت: -قربان عفو میفرمایید که ازتان سوال میکنم...
|
||||
پادشاه با عجله گفت: -بهات امر میکنیم از ما سوال کنی.
|
||||
-شما قربان به چی سلطنت میفرمایید؟
|
||||
پادشاه خیلی ساده گفت: -به همه چی.
|
||||
-به همهچی؟
|
||||
پادشاه با حرکتی قاطع به اخترک خودش و اخترکهای دیگر و باقی ستارهها اشاره کرد.
|
||||
شهریار کوچولو پرسید: -یعنی به همهی این ها؟
|
||||
شاه جواب داد: -به همهی این ها.
|
||||
آخر او فقط یک پادشاه معمولی نبود که، یک پادشاهِ جهانی بود.
|
||||
-آن وقت ستارهها هم سربهفرمانتانند؟
|
||||
پادشاه گفت: -البته که هستند. همهشان بیدرنگ هر فرمانی را اطاعت میکنند. ما نافرمانی را مطلقا تحمل نمیکنیم.
|
||||
|
||||
یک چنین قدرتی شهریار کوچولو را به شدت متعجب کرد. اگر خودش چنین قدرتی میداشت بی این که حتا صندلیش را یک ذره تکان بدهد روزی چهل و چهار بار که هیچ روزی هفتاد بار و حتا صدبار و دویستبار غروب آفتاب را تماشا میکرد! و چون بفهمی نفهمی از یادآوریِ اخترکش که به امان خدا ولکردهبود غصهاش شد جراتی به خودش داد که از پادشاه درخواست محبتی بکند:
|
||||
-دلم میخواست یک غروب آفتاب تماشا کنم... در حقم التفات بفرمایید امر کنید خورشید غروب کند.
|
||||
-اگر ما به یک سردار امر کنیم مثل شبپره از این گل به آن گل بپرد یا قصهی سوزناکی بنویسد یا به شکل مرغ دریایی در آید و او امریه را اجرا نکند کدام یکیمان مقصریم، ما یا او؟
|
||||
شهریار کوچولو نه گذاشت، نه برداشت، گفت: -شما.
|
||||
پادشاه گفت: -حرف ندارد. باید از هر کسی چیزی را توقع داشت که ازش ساخته باشد. قدرت باید پیش از هر چیز به عقل متکی باشد. اگر تو به ملتت فرمان بدهی که بروند خودشان را بیندازند تو دریا انقلاب میکنند. حق داریم توقع اطاعت داشته باشیم چون اوامرمان عاقلانه است.
|
||||
شهریار کوچولو که هیچ وقت چیزی را که پرسیده بود فراموش نمیکرد گفت: -غروب آفتاب من چی؟
|
||||
-تو هم به غروب آفتابت میرسی. امریهاش را صادر میکنیم. منتها با شَمِّ حکمرانیمان منتظریم زمینهاش فراهم بشود.
|
||||
شهریار کوچولو پرسید: -کِی فراهم میشود؟
|
||||
پادشاه بعد از آن که تقویم کَت و کلفتی را نگاه کرد جواب داد:
|
||||
-هوم! هوم! حدودِ... حدودِ... غروب. حدودِ ساعت هفت و چهل دقیقه... و آن وقت تو با چشمهای خودت میبینی که چهطور فرمان ما اجرا میشود!
|
||||
|
||||
شهریار کوچولو خمیازه کشید. از این که تماشای آفتاب غروب از کیسهاش رفتهبود تاسف میخورد. از آن گذشته دلش هم کمی گرفتهبود. این بود که به پادشاه گفت:
|
||||
-من دیگر اینجا کاری ندارم. میخواهم بروم.
|
||||
شاه که دلش برای داشتن یک رعیت غنج میزد گفت:
|
||||
-نرو! نرو! وزیرت میکنیم.
|
||||
-وزیرِ چی؟
|
||||
-وزیرِ دادگستری!
|
||||
-آخر این جا کسی نیست که محاکمه بشود.
|
||||
پادشاه گفت: -معلوم نیست. ما که هنوز گشتی دور قلمرومان نزدهایم. خیلی پیر شدهایم، برای کالسکه جا نداریم. پیادهروی هم خستهمان میکند.
|
||||
شهریار کوچولو که خم شدهبود تا نگاهی هم به آن طرف اخترک بیندازد گفت: -بَه! من نگاه کردهام، آن طرف هم دیارالبشری نیست.
|
||||
پادشاه بهاش جواب داد: -خب، پس خودت را محاکمه کن. این کار مشکلتر هم هست. محاکمه کردن خود از محاکمهکردن دیگران خیلی مشکل تر است. اگر توانستی در مورد خودت قضاوت درستی بکنی معلوم میشود یک فرزانهی تمام عیاری.
|
||||
شهریار کوچولو گفت: -من هر جا باشم میتوانم خودم را محاکمه کنم، چه احتیاجی است این جا بمانم؟ پادشاه گفت: -هوم! هوم! فکر میکنیم یک جایی تو اخترک ما یک موش پیر هست. صدایش را شب ها میشنویم. میتوانی او را به محاکمه بکشی و گاهگاهی هم به اعدام محکومش کنی. در این صورت زندگی او به عدالت تو بستگی پیدا میکند. گیرم تو هر دفعه عفوش میکنی تا همیشه زیر چاق داشته باشیش. آخر یکی بیشتر نیست که.
|
||||
شهریار کوچولو جواب داد: -من از حکم اعدام خوشم نمیآید. فکر میکنم دیگر باید بروم.
|
||||
پادشاه گفت: -نه!
|
||||
|
||||
اما شهریار کوچولو که آمادهی حرکت شده بود و ضمنا هم هیچ دلش نمیخواست اسباب ناراحتی سلطان پیر بشود گفت:
|
||||
-اگر اعلیحضرت مایلند اوامرشان دقیقا اجرا بشود میتوانند فرمان خردمندانهای در مورد بنده صادر بفرمایند. مثلا میتوانند به بنده امر کنند ظرف یک دقیقه راه بیفتم. تصور میکنم زمینهاش هم آماده باشد...
|
||||
چون پادشاه جوابی نداد شهریار کوچولو اول دو دل ماند اما بعد آهی کشید و به راه افتاد.
|
||||
آنوقت پادشاه با شتاب فریاد زد: -سفیر خودمان فرمودیمت!
|
||||
حالت بسیار شکوهمندی داشت.
|
||||
|
||||
شهریار کوچولو همان طور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۱
|
||||
اخترک دوم مسکن آدم خود پسندی بود.
|
||||
خود پسند چشمش که به شهریار کوچولو افتاد از همان دور داد زد: -بهبه! این هم یک ستایشگر که دارد میآید مرا ببیند!
|
||||
|
||||
خودپسند در سیارهاش
|
||||
آخر برای خودپسندها دیگران فقط یک مشت ستایشگرند.
|
||||
شهریار کوچولو گفت: -سلام! چه کلاه عجیب غریبی سرتان گذاشتهاید!
|
||||
خود پسند جواب داد: -مال اظهار تشکر است. منظورم موقعی است که هلهلهی ستایشگرهایم بلند میشود. گیرم متاسفانه تنابندهای گذارش به این طرفها نمیافتد.
|
||||
شهریار کوچولو که چیزی حالیش نشده بود گفت:
|
||||
-چی؟
|
||||
خودپسند گفت: -دستهایت را بزن به هم دیگر.
|
||||
شهریار کوچولو دست زد و خودپسند کلاهش را برداشت و متواضعانه از او تشکر کرد.
|
||||
شهریار کوچولو با خودش گفت: «دیدنِ این تفریحش خیلی بیشتر از دیدنِ پادشاهاست». و دوباره بنا کرد دستزدن و خودپسند با برداشتن کلاه بنا کرد تشکر کردن.
|
||||
|
||||
پس از پنج دقیقهای شهریار کوچولو که از این بازی یکنواخت خسته شده بود پرسید: -چه کار باید کرد که کلاه از سرت بیفتد؟
|
||||
اما خودپسند حرفش را نشنید. آخر آنها جز ستایش خودشان چیزی را نمیشنوند.
|
||||
از شهریار کوچولو پرسید: -تو راستی راستی به من با چشم ستایش و تحسین نگاه میکنی؟
|
||||
-ستایش و تحسین یعنی چه؟
|
||||
-یعنی قبول این که من خوشقیافهترین و خوشپوشترین و ثروتمندترین و باهوشترین مرد این اخترکم.
|
||||
-آخر روی این اخترک که فقط خودتی و کلاهت.
|
||||
-با وجود این ستایشم کن. این لطف را در حق من بکن.
|
||||
شهریار کوچولو نیمچه شانهای بالا انداخت و گفت: -خب، ستایشت کردم. اما آخر واقعا چیِ این برایت جالب است؟
|
||||
|
||||
شهریار کوچولو به راه افتاد و همان طور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۲
|
||||
تو اخترک بعدی میخوارهای مینشست. دیدار کوتاه بود اما شهریار کوچولو را به غم بزرگی فرو برد.
|
||||
|
||||
میخواره در سیارهاش
|
||||
|
||||
به میخواره که صُمبُکم پشت یک مشت بطری خالی و یک مشت بطری پر نشسته بود گفت: -چه کار داری میکنی؟
|
||||
میخواره با لحن غمزدهای جواب داد: -مِی میزنم.
|
||||
شهریار کوچولو پرسید: -مِی میزنی که چی؟
|
||||
میخواره جواب داد: -که فراموش کنم.
|
||||
شهریار کوچولو که حالا دیگر دلش برای او میسوخت پرسید: -چی را فراموش کنی؟
|
||||
میخواره همان طور که سرش را میانداخت پایین گفت: -سر شکستگیم را.
|
||||
شهریار کوچولو که دلش میخواست دردی از او دوا کند پرسید: -سرشکستگی از چی؟
|
||||
میخواره جواب داد: -سرشکستگیِ میخواره بودنم را.
|
||||
این را گفت و قال را کند و به کلی خاموش شد. و شهریار کوچولو مات و مبهوت راهش را گرفت و رفت و همان جور که میرفت تو دلش میگفت: -این آدم بزرگها راستیراستی چهقدر عجیبند!
|
||||
|
||||
۱۳
|
||||
اخترک چهارم اخترک مرد تجارتپیشه بود. این بابا چنان مشغول و گرفتار بود که با ورود شهریار کوچولو حتا سرش را هم بلند نکرد.
|
||||
|
||||
مردِ تجارتپیشه در سیارهاش
|
||||
شهریار کوچولو گفت: -سلام. آتشسیگارتان خاموش شده.
|
||||
-سه و دو میکند پنج. پنج و هفت دوازده و سه پانزده. سلام. پانزده و هفت بیست و دو. بیست و دو و شش بیست و هشت. وقت ندارم روشنش کنم. بیست و شش و پنج سی و یک. اوف! پس جمعش میکند پانصدویک میلیون و ششصد و بیست و دو هزار هفتصد و سی و یک.
|
||||
-پانصد میلیون چی؟
|
||||
-ها؟ هنوز این جایی تو؟ پانصد و یک میلیون چیز. چه میدانم، آن قدر کار سرم ریخته که!... من یک مرد جدی هستم و با حرفهای هشتمننهشاهی سر و کار ندارم!... دو و پنج هفت...
|
||||
شهریار کوچولو که وقتی چیزی میپرسید دیگر تا جوابش را نمیگرفت دست بردار نبود دوباره پرسید:
|
||||
-پانصد و یک میلیون چی؟
|
||||
تاجر پیشه سرش را بلند کرد:
|
||||
-تو این پنجاه و چهار سالی که ساکن این اخترکم همهاش سه بار گرفتار مودماغ شدهام. اولیش بیست و دو سال پیش یک سوسک بود که خدا میداند از کدام جهنم پیدایش شد. صدای وحشتناکی از خودش در میآورد که باعث شد تو یک جمع چهار جا اشتباه کنم. دفعهی دوم یازده سال پیش بود که استخوان درد بیچارهام کرد. من ورزش نمیکنم. وقت یللیتللی هم ندارم. آدمی هستم جدی... این هم بار سومش!... کجا بودم؟ پانصد و یک میلیون و...
|
||||
-این همه میلیون چی؟
|
||||
تاجرپیشه فهمید که نباید امید خلاصی داشته باشد. گفت: -میلیونها از این چیزهای کوچولویی که پارهای وقتها تو هوا دیده میشود.
|
||||
-مگس؟
|
||||
-نه بابا. این چیزهای کوچولوی براق.
|
||||
-زنبور عسل؟
|
||||
-نه بابا! همین چیزهای کوچولوی طلایی که وِلِنگارها را به عالم هپروت میبرد. گیرم من شخصا آدمی هستم جدی که وقتم را صرف خیالبافی نمیکنم.
|
||||
-آها، ستاره؟
|
||||
-خودش است: ستاره.
|
||||
-خب پانصد میلیون ستاره به چه دردت میخورد؟
|
||||
-پانصد و یک میلیون و ششصد و بیست و دو هزار و هفتصد و سی و یکی. من جدیّم و دقیق.
|
||||
-خب، به چه دردت میخورند؟
|
||||
-به چه دردم میخورند؟
|
||||
-ها.
|
||||
-هیچی تصاحبشان میکنم.
|
||||
-ستارهها را؟
|
||||
-آره خب.
|
||||
-آخر من به یک پادشاهی برخوردم که...
|
||||
-پادشاهها تصاحب نمیکنند بلکه بهاش «سلطنت» میکنند. این دو تا با هم خیلی فرق دارد.
|
||||
-خب، حالا تو آنها را تصاحب میکنی که چی بشود؟
|
||||
-که دارا بشوم.
|
||||
-خب دارا شدن به چه کارت میخورد؟
|
||||
-به این کار که، اگر کسی ستارهای پیدا کرد من ازش بخرم.
|
||||
شهریار کوچولو با خودش گفت: «این بابا هم منطقش یک خرده به منطق آن دائمالخمره میبَرَد.» با وجود این باز ازش پرسید:
|
||||
-چه جوری میشود یک ستاره را صاحب شد؟
|
||||
تاجرپیشه بی درنگ با اَخم و تَخم پرسید: -این ستارهها مال کیاند؟
|
||||
-چه میدانم؟ مال هیچ کس.
|
||||
-پس مال منند، چون من اول به این فکر افتادم.
|
||||
-همین کافی است؟
|
||||
-البته که کافی است. اگر تو یک جواهر پیدا کنی که مال هیچ کس نباشد میشود مال تو. اگر جزیرهای کشف کنی که مال هیچ کس نباشد میشود مال تو. اگر فکری به کلهات بزند که تا آن موقع به سر کسی نزده به اسم خودت ثبتش میکنی و میشود مال تو. من هم ستارهها را برای این صاحب شدهام که پیش از من هیچ کس به فکر نیفتاده بود آنها را مالک بشود.
|
||||
شهریار کوچولو گفت: -این ها همهاش درست. منتها چه کارشان میکنی؟
|
||||
تاجر پیشه گفت: -ادارهشان میکنم، همین جور میشمارمشان و میشمارمشان. البته کار مشکلی است ولی خب دیگر، من آدمی هستم بسیار جدی.
|
||||
شهریار کوچولو که هنوز این حرف تو کَتَش نرفتهبود گفت:
|
||||
-اگر من یک شال گردن ابریشمی داشته باشم میتوانم بپیچم دور گردنم با خودم ببرمش. اگر یک گل داشته باشم میتوانم بچینم با خودم ببرمش. اما تو که نمیتوانی ستارهها را بچینی!
|
||||
-نه. اما میتوانم بگذارمشان تو بانک.
|
||||
-اینی که گفتی یعنی چه؟
|
||||
-یعنی این که تعداد ستارههایم را رو یک تکه کاغذ مینویسم میگذارم تو کشو درش را قفل میکنم.
|
||||
-همهاش همین؟
|
||||
-آره همین کافی است.
|
||||
|
||||
شهریار کوچولو فکر کرد «جالب است. یک خرده هم شاعرانه است. اما کاری نیست که آن قدرها جدیش بشود گرفت». آخر تعبیر او از چیزهای جدی با تعبیر آدمهای بزرگ فرق میکرد.
|
||||
باز گفت: -من یک گل دارم که هر روز آبش میدهم. سه تا هم آتشفشان دارم که هفتهای یک بار پاک و دودهگیریشان میکنم. آخر آتشفشان خاموشه را هم پاک میکنم. آدم کفِ دستش را که بو نکرده! رو این حساب، هم برای آتشفشانها و هم برای گل این که من صاحبشان باشم فایده دارد. تو چه فایدهای به حال ستارهها داری؟
|
||||
|
||||
تاجرپیشه دهن باز کرد که جوابی بدهد اما چیزی پیدا نکرد. و شهریار کوچولو راهش را گرفت و رفت و همان جور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۴
|
||||
اخترکِ پنجم چیز غریبی بود. از همهی اخترکهای دیگر کوچکتر بود، یعنی فقط به اندازهی یک فانوس پایهدار و یک فانوسبان جا داشت.
|
||||
|
||||
فانوسبان در حالِ روشن کردنِ فانوس در سیارهاش
|
||||
شهریار کوچولو از این راز سر در نیاورد که یک جا میان آسمان خدا تو اخترکی که نه خانهای روش هست نه آدمی، حکمت وجودی یک فانوس و یک فانوسبان چه میتواند باشد. با وجود این تو دلش گفت:
|
||||
-خیلی احتمال دارد که این بابا عقلش پارهسنگ ببرد. اما به هر حال از پادشاه و خودپسند و تاجرپیشه و مسته کم عقلتر نیست. دست کم کاری که میکند یک معنایی دارد. فانوسش را که روشن میکند عینهو مثل این است که یک ستارهی دیگر یا یک گل به دنیا میآورد و خاموشش که میکند پنداری گل یا ستارهای را میخواباند. سرگرمی زیبایی است و چیزی که زیبا باشد بی گفتوگو مفید هم هست.
|
||||
|
||||
وقتی رو اخترک پایین آمد با ادب فراوان به فانوسبان سلام کرد:
|
||||
-سلام. واسه چی فانوس را خاموش کردی؟
|
||||
-دستور است. صبح به خیر!
|
||||
-دستور چیه؟
|
||||
-این است که فانوسم را خاموش کنم. شب خوش!
|
||||
و دوباره فانوس را روشن کرد.
|
||||
-پس چرا روشنش کردی باز؟
|
||||
فانوسبان جواب داد: -خب دستور است دیگر.
|
||||
شهریار کوچولو گفت: -اصلا سر در نمیارم.
|
||||
فانوسبان گفت: -چیز سر در آوردنییی توش نیست که. دستور دستور است. روز بخیر!
|
||||
و باز فانوس را خاموش کرد.
|
||||
بعد با دستمال شطرنجی قرمزی عرق پیشانیش را خشکاند و گفت:
|
||||
-کار جانفرسایی دارم. پیشتر ها معقول بود: صبح خاموشش میکردم و شب که میشد روشنش میکردم. باقی روز را فرصت داشتم که استراحت کنم و باقی شب را هم میتوانستم بگیرم بخوابم...
|
||||
-بعدش دستور عوض شد؟
|
||||
فانوسبان گفت: -دستور عوض نشد و بدبختی من هم از همین جاست: سیاره سال به سال گردشش تندتر و تندتر شده اما دستور همان جور به قوت خودش باقی مانده است.
|
||||
-خب؟
|
||||
-حالا که سیاره دقیقهای یک بار دور خودش میگردد دیگر من یک ثانیه هم فرصت استراحت ندارم: دقیقهای یک بار فانوس را روشن میکنم یک بار خاموش.
|
||||
-چه عجیب است! تو اخترک تو شبانه روز همهاش یک دقیقه طول میکشد!
|
||||
فانوسبان گفت: -هیچ هم عجیب نیست. الان یک ماه تمام است که ما داریم با هم اختلاط میکنیم.
|
||||
-یک ماه؟
|
||||
-آره. سی دقیقه. سی روز! شب خوش!
|
||||
و دوباره فانوس را روشن کرد.
|
||||
|
||||
شهریار کوچولو به فانوسبان نگاه کرد و حس کرد این مرد را که تا این حد به دستور وفادار است دوست میدارد. یادِ آفتابغروبهایی افتاد که آن وقتها خودش با جابهجا کردن صندلیش دنبال میکرد. برای این که دستی زیر بال دوستش کرده باشد گفت:
|
||||
-میدانی؟ یک راهی بلدم که میتوانی هر وقت دلت بخواهد استراحت کنی.
|
||||
فانوسبان گفت: -آرزوش را دارم.
|
||||
آخر آدم میتواند هم به دستور وفادار بماند هم تنبلی کند.
|
||||
شهریار کوچولو دنبال حرفش را گرفت و گفت:
|
||||
-تو، اخترکت آنقدر کوچولوست که با سه تا شلنگ برداشتن میتوانی یک بار دور بزنیش. اگر آن اندازه که لازم است یواش راه بروی میتوانی کاری کنی که مدام تو آفتاب بمانی. پس هر وقت خواستی استراحت کنی شروع میکنی به راهرفتن... به این ترتیب روز هرقدر که بخواهی برایت کِش میآید.
|
||||
فانوسبان گفت: -این کار گرهی از بدبختی من وا نمیکند. تنها چیزی که تو زندگی آرزویش را دارم یک چرت خواب است.
|
||||
شهریار کوچولو گفت: -این یکی را دیگر باید بگذاری در کوزه.
|
||||
فانوسبان گفت: -آره. باید بگذارمش در کوزه... صبح بخیر!
|
||||
و فانوس را خاموش کرد.
|
||||
|
||||
شهریار کوچولو میان راه با خودش گفت: گرچه آنهای دیگر، یعنی خودپسنده و تاجره اگر این را میدیدند دستش میانداختند و تحقیرش میکردند، هر چه نباشد کار این یکی به نظر من کمتر از کار آنها بیمعنی و مضحک است. شاید به خاطر این که دست کم این یکی به چیزی جز خودش مشغول است.
|
||||
|
||||
از حسرت آهی کشید و همان طور با خودش گفت:
|
||||
-این تنها کسی بود که من میتوانستم باش دوست بشوم. گیرم اخترکش راستی راستی خیلی کوچولو است و دو نفر روش جا نمیگیرند.
|
||||
|
||||
چیزی که جرات اعترافش را نداشت حسرت او بود به این اخترک کوچولویی که، بخصوص، به هزار و چهارصد و چهل بار غروب آفتاب در هر بیست و چهار ساعت برکت پیدا کرده بود.
|
||||
|
||||
۱۵
|
||||
اخترک ششم اخترکی بود ده بار فراختر، و آقاپیرهای توش بود که کتابهای کَتوکلفت مینوشت.
|
||||
|
||||
جغرافیدان در سیارهاش
|
||||
همین که چشمش به شهریار کوچولو افتاد با خودش گفت:
|
||||
-خب، این هم یک کاشف!
|
||||
شهریار کوچولو لب میز نشست و نفس نفس زد. نه این که راه زیادی طی کرده بود؟
|
||||
آقا پیره بهاش گفت: -از کجا میآیی؟
|
||||
شهریار کوچولو گفت: -این کتاب به این کلفتی چی است؟ شما اینجا چهکار میکنید؟
|
||||
آقا پیره گفت: -من جغرافیدانم.
|
||||
-جغرافیدان چه باشد؟
|
||||
-جغرافیدان به دانشمندی میگویند که جای دریاها و رودخانهها و شهرها و کوهها و بیابانها را میداند.
|
||||
شهریار کوچولو گفت: -محشر است. یک کار درست و حسابی است.
|
||||
و به اخترک جغرافیدان، این سو و آنسو نگاهی انداخت. تا آن وقت اخترکی به این عظمت ندیدهبود.
|
||||
-اخترکتان خیلی قشنگ است. اقیانوس هم دارد؟
|
||||
جغرافیدان گفت: -از کجا بدانم؟
|
||||
شهریار کوچولو گفت: -عجب! (بد جوری جا خورده بود) کوه چهطور؟
|
||||
جغرافیدان گفت: -از کجا بدانم؟
|
||||
-شهر، رودخانه، بیابان؟
|
||||
جغرافیدان گفت: از اینها هم خبری ندارم.
|
||||
-آخر شما جغرافیدانید؟
|
||||
جغرافیدان گفت: -درست است ولی کاشف که نیستم. من حتا یک نفر کاشف هم ندارم. کار جغرافیدان نیست که دورهبیفتد برود شهرها و رودخانهها و کوهها و دریاها و اقیانوسها و بیابانها را بشمرد. مقام جغرافیدان برتر از آن است که دوره بیفتد و ولبگردد. اصلا از اتاق کارش پا بیرون نمیگذارد بلکه کاشفها را آن تو میپذیرد ازشان سوالات میکند و از خاطراتشان یادداشت بر میدارد و اگر خاطرات یکی از آنها به نظرش جالب آمد دستور میدهد روی خُلقیات آن کاشف تحقیقاتی صورت بگیرد.
|
||||
-برای چه؟
|
||||
-برای این که اگر کاشفی گندهگو باشد کار کتابهای جغرافیا را به فاجعه میکشاند. هکذا کاشفی که اهل پیاله باشد.
|
||||
-آن دیگر چرا؟
|
||||
b-چون آدمهای دائمالخمر همه چیز را دوتا میبینند. آن وقت جغرافیدان برمیدارد جایی که یک کوه
|
||||
بیشتر نیست مینویسد دو کوه.
|
||||
شهریار کوچولو گفت: -پس من یک بابایی را میشناسم که کاشف هجوی از آب در میآید.
|
||||
-بعید نیست. بنابراین، بعد از آن که کاملا ثابت شد پالان کاشف کج نیست تحقیقاتی هم روی کشفی که کرده انجام میگیرد.
|
||||
-یعنی میروند میبینند؟
|
||||
-نه، این کار گرفتاریش زیاد است. از خود کاشف میخواهند دلیل بیاورد. مثلا اگر پای کشف یک کوه بزرگ در میان بود ازش میخواهند سنگهای گندهای از آن کوه رو کند.
|
||||
جغرافیدان ناگهان به هیجان در آمد و گفت: -راستی تو داری از راه دوری میآیی! تو کاشفی! باید چند و چون اخترکت را برای من بگویی.
|
||||
و با این حرف دفتر و دستکش را باز کرد و مدادش را تراشید. معمولا خاطرات کاشفها را اول بامداد یادداشت میکنند و دست نگه میدارند تا دلیل اقامه کند، آن وقت با جوهر مینویسند.
|
||||
گفت: -خب؟
|
||||
شهریار کوچولو گفت: -اخترک من چیز چندان جالبی ندارد. آخر خیلی کوچک است. سه تا آتشفشان دارم که دوتاش فعال است یکیش خاموش. اما، خب دیگر، آدم کف دستش را که بو نکرده.
|
||||
جغرافیدان هم گفت: -آدم چه میداند چه پیش میآید.
|
||||
-یک گل هم دارم.
|
||||
-نه، نه، ما دیگر گل ها را یادداشت نمیکنیم.
|
||||
-چرا؟ گل که زیباتر است.
|
||||
-برای این که گلها فانیاند.
|
||||
-فانی یعنی چی؟
|
||||
جغرافیدان گفت: -کتابهای جغرافیا از کتابهای دیگر گرانبهاترست و هیچ وقت هم از اعتبار نمیافتد. بسیار به ندرت ممکن است یک کوه جا عوض کند. بسیار به ندرت ممکن است آب یک اقیانوس خالی شود. ما فقط چیزهای پایدار را مینویسیم.
|
||||
شهریار کوچولو تو حرف او دوید و گفت: -اما آتشفشانهای خاموش میتوانند از نو بیدار بشوند. فانی را نگفتید یعنی چه؟
|
||||
جغرافیدان گفت: -آتشفشان چه روشن باشد چه خاموش برای ما فرقی نمیکند. آنچه به حساب میآید خود کوه است که تغییر پیدا نمیکند.
|
||||
شهریار کوچولو که تو تمام عمرش وقتی چیزی از کسی میپرسید دیگر دست بردار نبود دوباره سوال کرد: -فانی یعنی چه؟
|
||||
-یعنی چیزی که در آینده تهدید به نابودی شود.
|
||||
-گل من هم در آینده نابود میشود؟
|
||||
-البته که میشود.
|
||||
شهریار کوچولو در دل گفت: «گل من فانی است و جلو دنیا برای دفاع از خودش جز چهارتا خار هیچی ندارد، و آن وقت مرا بگو که او را توی اخترکم تک و تنها رها کردهام!»
|
||||
این اولین باری بود که دچار پریشانی و اندوه میشد اما توانست به خودش مسلط بشود. پرسید: -شما به من دیدن کجا را توصیه میکنید؟
|
||||
جغرافیدان بهاش جواب داد: -سیارهی زمین. شهرت خوبی دارد...
|
||||
|
||||
و شهریار کوچولو هم چنان که به گلش فکر میکرد به راه افتاد.
|
||||
|
||||
۱۶
|
||||
لاجرم، زمین، سیارهی هفتم شد.
|
||||
|
||||
زمین، فلان و بهمان سیاره نیست. رو پهنهی زمین یکصد و یازده پادشاه (البته بامحاسبهی پادشاهان سیاهپوست)، هفت هزار جغرافیدان، نهصد هزار تاجرپیشه، پانزده کرور میخواره و ششصد و بیست و دو کرور خودپسند و به عبارت دیگر حدود دو میلیارد آدم بزرگ زندگی میکند. برای آنکه از حجم زمین مقیاسی به دستتان بدهم بگذارید بهتان بگویم که پیش از اختراع برق مجبور بودند در مجموع شش قارهی زمین وسایل زندگیِ لشکری جانانه شامل یکصد و شصت و دو هزار و پانصد و یازده نفر فانوسبان را تامین کنند.
|
||||
|
||||
روشن شدن فانوسها از دور خیلی باشکوه بود. حرکات این لشکر مثل حرکات یک بالهی تو اپرا مرتب و منظم بود. اول از همه نوبت فانوسبانهای زلاندنو و استرالیا بود. اینها که فانوسهاشان را روشن میکردند، میرفتند میگرفتند میخوابیدند آن وقت نوبت فانوسبانهای چین و سیبری میرسید که به رقص درآیند. بعد، اینها با تردستی تمام به پشت صحنه میخزیدند و جا را برای فانوسبانهای ترکیه و هفت پَرکَنِهی هند خالی می کردند. بعد نوبت به فانوسبانهای آمریکایجنوبی میشد. و آخر سر هم نوبت فانوسبانهای افریقا و اروپا میرسد و بعد نوبت فانوسبانهای آمریکای شمالی بود. و هیچ وقتِ خدا هم هیچکدام اینها در ترتیب ورودشان به صحنه دچار اشتباه نمیشدند. چه شکوهی داشت! میان این جمع عظیم فقط نگهبانِ تنها فانوسِ قطب شمال و همکارش نگهبانِ تنها فانوسِ قطب جنوب بودند که عمری به بطالت و بیهودگی میگذراندند: آخر آنها سالی به سالی همهاش دو بار کار میکردند.
|
||||
|
||||
۱۷
|
||||
آدمی که اهل اظهار لحیه باشد بفهمی نفهمی میافتد به چاخان کردن. من هم تو تعریف قضیهی فانوسبانها برای شما آنقدرهاروراست نبودم. میترسم به آنهایی که زمین ما را نمیسناسند تصور نادرستی داده باشم. انسانها رو پهنهی زمین جای خیلی کمی را اشغال میکنند. اگر همهی دو میلیارد نفری که رو کرهی زمین زندگی میکنند بلند بشوند و مثل موقعی که به تظاهرات میروند یک خورده جمع و جور بایستند راحت و بیدرپسر تو میدانی به مساحت بیست میل در بیست میل جا میگیرند. همهی جامعهی بشری را میشود یکجا روی کوچکترین جزیرهی اقیانوس آرام کُپه کرد.
|
||||
|
||||
البته گفتوگو ندارد که آدم بزرگها حرفتان را باور نمیکنند. آخر تصور آنها این است که کلی جا اشغال کردهاند، نه اینکه مثل بائوبابها خودشان را خیلی مهم میبینند؟ بنابراین بهشان پیشنهاد میکنید که بنشینند حساب کنند. آنها هم که عاشق اعداد و ارقامند، پس این پیشنهاد حسابی کیفورشان میکند. اما شما را به خدا بیخودی وقت خودتان را سر این جریمهی مدرسه به هدر ندهید. این کار دو قاز هم نمیارزد. به من که اطمینان دارید. شهریار کوچولو پاش که به زمین رسید از این که دیارالبشری دیده نمیشد سخت هاج و واج ماند.
|
||||
|
||||
شهریار کوچولو وسطِ کویر
|
||||
تازه داشت از این فکر که شاید سیاره را عوضی گرفته ترسش بر میداشت که چنبرهی مهتابی رنگی رو ماسهها جابهجا شد.شهریار کوچولو و مار
|
||||
شهریار کوچولو همینجوری سلام کرد.
|
||||
مار گفت: -سلام.
|
||||
شهریار کوچولو پرسید: -رو چه سیارهای پایین آمدهام؟
|
||||
مار جواب داد: -رو زمین تو قارهی آفریقا.
|
||||
-عجب! پس رو زمین انسان به هم نمیرسد؟
|
||||
مار گفت: -اینجا کویر است. تو کویر کسی زندگی نمیکند. زمین بسیار وسیع است.
|
||||
شهریار کوچولو رو سنگی نشست و به آسمان نگاه کرد. گفت: -به خودم میگویم ستارهها واسه این روشنند که هرکسی بتواند یک روز مال خودش را پیدا کند!... اخترک مرا نگاه! درست بالا سرمان است... اما چهقدر دور است!
|
||||
مار گفت: -قشنگ است. اینجا آمدهای چه کار؟
|
||||
شهریار کوچولو گفت: -با یک گل بگومگویم شده.
|
||||
مار گفت: -عجب!
|
||||
و هر دوشان خاموش ماندند.
|
||||
دست آخر شهریار کوچولو درآمد که: -آدمها کجاند؟ آدم تو کویر یک خرده احساس تنهایی میکند.
|
||||
مار گفت: -پیش آدمها هم احساس تنهایی میکنی.
|
||||
شهریار کوچولو مدت درازی تو نخ او رفت و آخر سر بهاش گفت: -تو چه جانور بامزهای هستی! مثل یک انگشت، باریکی.
|
||||
مار گفت: -عوضش از انگشت هر پادشاهی مقتدرترم.
|
||||
شهریار کوچولو لبخندی زد و گفت: -نه چندان... پا هم که نداری. حتا راه هم نمیتونی بری...
|
||||
-من میتونم تو را به چنان جای دوری ببرم که با هیچ کشتییی هم نتونی بری.
|
||||
مار این را گفت و دور قوزک پای شهریار کوچولو پیچید. عین یک خلخال طلا. و باز درآمد که: -هر کسی را لمس کنم به خاکی که ازش درآمده بر میگردانم اما تو پاکی و از یک سیّارهی دیگر آمدهای...
|
||||
شهریار کوچولو جوابی بش نداد.
|
||||
-تو رو این زمین خارایی آنقدر ضعیفی که به حالت رحمم میآید. روزیروزگاری اگر دلت خیلی هوای اخترکت را کرد بیا من کمکت کنم... من میتوانم...
|
||||
شهریار کوچولو گفت: -آره تا تهش را خواندم. اما راستی تو چرا همهی حرفهایت را به صورت معما درمیآری؟
|
||||
|
||||
مار گفت: -حلّال همهی معماهام من.
|
||||
و هر دوشان خاموش شدند.
|
||||
|
||||
۱۸
|
||||
شهریار کوچولو کویر را از پاشنه درکرد و جز یک گل به هیچی برنخورد: یک گل سه گلبرگه. یک گلِ ناچیز.
|
||||
|
||||
یک گُل وسطِ کویر
|
||||
|
||||
شهریار کوچولو گفت: -سلام.
|
||||
گل گفت: -سلام.
|
||||
شهریار کوچولو با ادب پرسید: -آدمها کجاند؟
|
||||
گل روزی روزگاری عبور کاروانی را دیدهبود. این بود که گفت: -آدمها؟ گمان کنم ازشان شش هفت تایی باشد. سالها پیش دیدمشان. منتها خدا میداند کجا میشود پیداشان کرد. باد اینور و آنور میبَرَدشان؛ نه این که ریشه ندارند؟ بیریشگی هم حسابی اسباب دردسرشان شده.
|
||||
شهریار کوچولو گفت: -خداحافظ.
|
||||
گل گفت: -خداحافظ.
|
||||
|
||||
۱۹
|
||||
از کوه بلندی بالا رفت.
|
||||
|
||||
شهریار کوچولو بر قلهی کوهِ بلند
|
||||
تنها کوههایی که به عمرش دیده بود سه تا آتشفشانهای اخترک خودش بود که تا سر زانویش میرسید و از آن یکی که خاموش بود جای چارپایه استفاده میکرد. این بود که با خودش گفت: «از سر یک کوه به این بلندی میتوانم به یک نظر همهی سیاره و همهی آدمها را ببینم...» اما جز نوکِ تیزِ صخرههای نوکتیز چیزی ندید.
|
||||
همین جوری گفت: -سلام.
|
||||
طنین بهاش جواب داد: -سلام... سلام... سلام...
|
||||
شهریار کوچولو گفت: -کی هستید شما؟
|
||||
طنین بهاش جواب داد: -کی هستید شما... کی هستید شما... کی هستید شما...
|
||||
گفت: -با من دوست بشوید. من تک و تنهام.
|
||||
طنین بهاش جواب داد: -من تک و تنهام... من تک و تنهام... من تک و تنهام...
|
||||
آنوقت با خودش فکر کرد: «چه سیارهی عجیبی! خشکِخشک و تیزِتیز و شورِشور. این آدمهاش که یک ذره قوهی تخیل ندارند و هر چه را بشنوند عینا تکرار میکنند... تو اخترک خودم گلی داشتم که همیشه اول او حرف میزد...»
|
||||
|
||||
۲۰
|
||||
اما سرانجام، بعد از مدتها راه رفتن از میان ریگها و صخرهها و برفها به جادهای برخورد. و هر جادهای یکراست میرود سراغ آدمها.
|
||||
گفت: -سلام.
|
||||
و مخاطبش گلستان پرگلی بود.
|
||||
|
||||
شهریار کوچولو در گلستانِ پرگل
|
||||
|
||||
گلها گفتند: -سلام.
|
||||
شهریار کوچولو رفت تو بحرشان. همهشان عین گل خودش بودند. حیرتزده ازشان پرسید: -شماها کی هستید؟
|
||||
گفتند: -ما گل سرخیم.
|
||||
|
||||
آهی کشید و سخت احساس شوربختی کرد. گلش به او گفته بود که از نوع او تو تمام عالم فقط همان یکی هست و حالا پنجهزارتا گل، همه مثل هم، فقط تو یک گلستان! فکر کرد: «اگر گل من این را میدید بدجور از رو میرفت. پشت سر هم بنا میکرد سرفهکردن و، برای اینکه از هُوشدن نجات پیدا کند خودش را به مردن میزد و من هم مجبور میشدم وانمود کنم به پرستاریش، وگرنه برای سرشکسته کردنِ من هم شده بود راستی راستی میمرد...» و باز تو دلش گفت: «مرا باش که فقط بایک دانه گل خودم را دولتمندِ عالم خیال میکردم در صورتیکه آنچه دارم فقط یک گل معمولی است. با آن گل و آن سه تا آتشفشان که تا سرِ زانومَند و شاید هم یکیشان تا ابد خاموش بماند شهریارِ چندان پُرشوکتی به حساب نمیآیم.»
|
||||
|
||||
شهریار کوچولو در حالِ احساسِ شوربختی
|
||||
رو سبزهها دراز شد و حالا گریه نکن کی گریهکن.
|
||||
|
||||
۲۱
|
||||
آن وقت بود که سر و کلهی روباه پیدا شد.
|
||||
|
||||
شهریار کوچولو و روباه
|
||||
|
||||
روباه گفت: -سلام.
|
||||
شهریار کوچولو برگشت اما کسی را ندید. با وجود این با ادب تمام گفت: -سلام.
|
||||
صداگفت: -من اینجام، زیر درخت سیب...
|
||||
شهریار کوچولو گفت: -کی هستی تو؟ عجب خوشگلی!
|
||||
روباه گفت: -یک روباهم من.
|
||||
شهریار کوچولو گفت: -بیا با من بازی کن. نمیدانی چه قدر دلم گرفته...
|
||||
روباه گفت: -نمیتوانم بات بازی کنم. هنوز اهلیم نکردهاند آخر.
|
||||
شهریار کوچولو آهی کشید و گفت: -معذرت میخواهم.
|
||||
اما فکری کرد و پرسید: -اهلی کردن یعنی چه؟
|
||||
روباه گفت: -تو اهل اینجا نیستی. پی چی میگردی؟
|
||||
شهریار کوچولو گفت: -پی آدمها میگردم. نگفتی اهلی کردن یعنی چه؟
|
||||
روباه گفت: -آدمها تفنگ دارند و شکار میکنند. اینش اسباب دلخوری است! اما مرغ و ماکیان هم پرورش میدهند و خیرشان فقط همین است. تو پی مرغ میکردی؟
|
||||
شهریار کوچولو گفت: -نَه، پیِ دوست میگردم. اهلی کردن یعنی چی؟
|
||||
روباه گفت: -یک چیزی است که پاک فراموش شده. معنیش ایجاد علاقه کردن است.
|
||||
-ایجاد علاقه کردن؟
|
||||
روباه گفت: -معلوم است. تو الان واسه من یک پسر بچهای مثل صد هزار پسر بچهی دیگر. نه من هیچ احتیاجی به تو دارم نه تو هیچ احتیاجی به من. من هم واسه تو یک روباهم مثل صد هزار روباه دیگر. اما اگر منو اهلی کردی هر دوتامان به هم احتیاج پیدا میکنیم. تو واسه من میان همهی عالم موجود یگانهای میشوی من واسه تو.
|
||||
شهریار کوچولو گفت: -کمکم دارد دستگیرم میشود. یک گلی هست که گمانم مرا اهلی کرده باشد.
|
||||
روباه گفت: -بعید نیست. رو این کرهی زمین هزار جور چیز میشود دید.
|
||||
شهریار کوچولو گفت: -اوه نه! آن رو کرهی زمین نیست.
|
||||
روباه که انگار حسابی حیرت کرده بود گفت: -رو یک سیارهی دیگر است؟
|
||||
-آره.
|
||||
شکارچی-تو آن سیاره شکارچی هم هست؟
|
||||
-نه.
|
||||
-محشر است! مرغ و ماکیان چهطور؟
|
||||
-نه.
|
||||
روباه آهکشان گفت: -همیشهی خدا یک پای بساط لنگ است!
|
||||
اما پی حرفش را گرفت و گفت: -زندگی یکنواختی دارم. من مرغها را شکار میکنم آدمها مرا. همهی مرغها عین همند همهی آدمها هم عین همند. این وضع یک خرده خلقم را تنگ میکند. اما اگر تو منو اهلی کنی انگار که زندگیم را چراغان کرده باشی. آن وقت صدای پایی را میشناسم که باهر صدای پای دیگر فرق میکند: صدای پای دیگران مرا وادار میکند تو هفت تا سوراخ قایم بشوم اما صدای پای تو مثل نغمهای مرا از سوراخم میکشد بیرون. تازه، نگاه کن آنجا آن گندمزار را میبینی؟ برای من که نان بخور نیستم گندم چیز بیفایدهای است. پس گندمزار هم مرا به یاد چیزی نمیاندازد. اسباب تاسف است. اما تو موهات رنگ طلا است. پس وقتی اهلیم کردی محشر میشود! گندم که طلایی رنگ است مرا به یاد تو میاندازد و صدای باد را هم که تو گندمزار میپیچد دوست خواهم داشت...
|
||||
خاموش شد و مدت درازی شهریار کوچولو را نگاه کرد. آن وقت گفت: -اگر دلت میخواهد منو اهلی کن!
|
||||
شهریار کوچولو جواب داد: -دلم که خیلی میخواهد، اما وقتِ چندانی ندارم. باید بروم دوستانی پیدا کنم و از کلی چیزها سر در آرم.
|
||||
روباه گفت: -آدم فقط از چیزهایی که اهلی کند میتواند سر در آرد. انسانها دیگر برای سر در آوردن از چیزها وقت ندارند. همه چیز را همین جور حاضر آماده از دکانها میخرند. اما چون دکانی نیست که دوست معامله کند آدمها ماندهاند بیدوست... تو اگر دوست میخواهی خب منو اهلی کن!
|
||||
شهریار کوچولو پرسید: -راهش چیست؟
|
||||
روباه جواب داد: -باید خیلی خیلی حوصله کنی. اولش یک خرده دورتر از من میگیری این جوری میان علفها مینشینی. من زیر چشمی نگاهت میکنم و تو لامتاکام هیچی نمیگویی، چون تقصیر همهی سؤِتفاهمها زیر سر زبان است. عوضش میتوانی هر روز یک خرده نزدیکتر بنشینی.
|
||||
|
||||
روباه در حالِ انتظارفردای آن روز دوباره شهریار کوچولو آمد.
|
||||
روباه گفت: -کاش سر همان ساعت دیروز آمده بودی. اگر مثلا سر ساعت چهار بعد از ظهر بیایی من از ساعت سه تو دلم قند آب میشود و هر چه ساعت جلوتر برود بیشتر احساس شادی و خوشبختی میکنم. ساعت چهار که شد دلم بنا میکند شور زدن و نگران شدن. آن وقت است که قدرِ خوشبختی را میفهمم! اما اگر تو وقت و بی وقت بیایی من از کجا بدانم چه ساعتی باید دلم را برای دیدارت آماده کنم؟... هر چیزی برای خودش قاعدهای دارد.
|
||||
شهریار کوچولو گفت: -قاعده یعنی چه؟
|
||||
روباه گفت: -این هم از آن چیزهایی است که پاک از خاطرها رفته. این همان چیزی است که باعث میشود فلان روز با باقی روزها و فلان ساعت با باقی ساعتها فرق کند. مثلا شکارچیهای ما میان خودشان رسمی دارند و آن این است که پنجشنبهها را با دخترهای ده میروند رقص. پس پنجشنبهها بَرّهکشانِ من است: برای خودم گردشکنان میروم تا دم مُوِستان. حالا اگر شکارچیها وقت و بی وقت میرقصیدند همهی روزها شبیه هم میشد و منِ بیچاره دیگر فرصت و فراغتی نداشتم.
|
||||
|
||||
به این ترتیب شهریار کوچولو روباه را اهلی کرد.
|
||||
لحظهی جدایی که نزدیک شد روباه گفت: -آخ! نمیتوانم جلو اشکم را بگیرم.
|
||||
شهریار کوچولو گفت: -تقصیر خودت است. من که بدت را نمیخواستم، خودت خواستی اهلیت کنم.
|
||||
روباه گفت: -همین طور است.
|
||||
شهریار کوچولو گفت: -آخر اشکت دارد سرازیر میشود!
|
||||
روباه گفت: -همین طور است.
|
||||
-پس این ماجرا فایدهای به حال تو نداشته.
|
||||
روباه گفت: -چرا، واسه خاطرِ رنگ گندم.
|
||||
بعد گفت: -برو یک بار دیگر گلها را ببین تا بفهمی که گلِ خودت تو عالم تک است. برگشتنا با هم وداع میکنیم و من به عنوان هدیه رازی را بهات میگویم.
|
||||
شهریار کوچولو بار دیگر به تماشای گلها رفت و به آنها گفت: -شما سرِ سوزنی به گل من نمیمانید و هنوز هیچی نیستید. نه کسی شما را اهلی کرده نه شما کسی را. درست همان جوری هستید که روباه من بود: روباهی بود مثل صدهزار روباه دیگر. او را دوست خودم کردم و حالا تو همهی عالم تک است.
|
||||
گلها حسابی از رو رفتند.
|
||||
شهریار کوچولو دوباره درآمد که: -خوشگلید اما خالی هستید. برایتان نمیشود مُرد. گفتوگو ندارد که گلِ مرا هم فلان رهگذر میبیند مثل شما. اما او به تنهایی از همهی شما سر است چون فقط اوست که آبش دادهام، چون فقط اوست که زیر حبابش گذاشتهام، چون فقط اوست که با تجیر برایش حفاظ درست کردهام، چون فقط اوست که حشراتش را کشتهام (جز دو سهتایی که میبایست شبپره بشوند)، چون فقط اوست که پای گِلِهگزاریها یا خودنماییها و حتا گاهی پای بُغ کردن و هیچی نگفتنهاش نشستهام، چون او گلِ من است.
|
||||
و برگشت پیش روباه.
|
||||
گفت: -خدانگهدار!
|
||||
روباه گفت: -خدانگهدار!... و اما رازی که گفتم خیلی ساده است:
|
||||
جز با دل هیچی را چنان که باید نمیشود دید. نهاد و گوهر را چشمِ سَر نمیبیند.
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -نهاد و گوهر را چشمِ سَر نمیبیند.
|
||||
-ارزش گل تو به قدرِ عمری است که به پاش صرف کردهای.
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -به قدر عمری است که به پاش صرف کردهام.
|
||||
روباه گفت: -انسانها این حقیقت را فراموش کردهاند اما تو نباید فراموشش کنی. تو تا زندهای نسبت به چیزی که اهلی کردهای مسئولی. تو مسئول گُلِتی...
|
||||
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -من مسئول گُلمَم.
|
||||
|
||||
۲۲
|
||||
شهریار کوچولو گفت: -سلام.
|
||||
سوزنبان گفت: -سلام.
|
||||
شهریار کوچولو گفت: -تو چه کار میکنی اینجا؟
|
||||
سوزنبان گفت: -مسافرها را به دستههای هزارتایی تقسیم میکنم و قطارهایی را که میبَرَدشان گاهی به سمت راست میفرستم گاهی به سمت چپ. و همان دم سریعالسیری با چراغهای روشن و غرّشی رعدوار اتاقک سوزنبانی را به لرزه انداخت.
|
||||
-عجب عجلهای دارند! پیِ چی میروند؟
|
||||
سوزنبان گفت: -از خودِ آتشکارِ لکوموتیف هم بپرسی نمیداند!
|
||||
سریعالسیر دیگری با چراغهای روشن غرّید و در جهت مخالف گذشت .
|
||||
شهریار کوچولو پرسید: -برگشتند که؟
|
||||
سوزنبان گفت: -اینها اولیها نیستند. آنها رفتند اینها برمیگردند.
|
||||
-جایی را که بودند خوش نداشتند؟
|
||||
سوزنبان گفت: -آدمیزاد هیچ وقت جایی را که هست خوش ندارد.
|
||||
و رعدِ سریعالسیرِ نورانیِ ثالثی غرّید.
|
||||
شهریار کوچولو پرسید: -اینها دارند مسافرهای اولی را دنبال میکنند؟
|
||||
سوزنبان گفت: -اینها هیچ چیزی را دنبال نمیکنند. آن تو یا خوابشان میبَرَد یا دهندره میکنند. فقط بچههاند که دماغشان را فشار میدهند به شیشهها.
|
||||
شهریار کوچولو گفت: -فقط بچههاند که میدانند پیِ چی میگردند. بچههاند که کُلّی وقت صرف یک عروسک پارچهای میکنند و عروسک برایشان آن قدر اهمیت به هم میرساند که اگر یکی آن را ازشان کِش برود میزنند زیر گریه...
|
||||
سوزنبان گفت: -بخت، یارِ بچههاست.
|
||||
|
||||
۲۳
|
||||
شهریار کوچولو گفت: -سلام!
|
||||
پیلهور گفت: -سلام.
|
||||
این بابا فروشندهی حَبهای ضد تشنگی بود. خریدار هفتهای یک حب میانداخت بالا و دیگر تشنگی بی تشنگی.
|
||||
شهریار کوچولو پرسید: -اینها را میفروشی که چی؟
|
||||
پیلهور گفت: -باعث صرفهجویی کُلّی وقت است. کارشناسهای خبره نشستهاند دقیقا حساب کردهاند که با خوردن این حبها هفتهای پنجاه و سه دقیقه وقت صرفهجویی میشود.
|
||||
-خب، آن وقت آن پنجاه و سه دقیقه را چه کار میکنند؟
|
||||
ـ هر چی دلشان خواست...
|
||||
|
||||
چشمه
|
||||
شهریار کوچولو تو دلش گفت: «من اگر پنجاه و سه دقیقه وقتِ زیادی داشته باشم خوشخوشک به طرفِ یک چشمه میروم...»
|
||||
|
||||
۲۴
|
||||
هشتمین روزِ خرابی هواپیمام تو کویر بود که، در حال نوشیدنِ آخرین چکّهی ذخیرهی آبم به قضیهی پیلهوره گوش داده بودم. به شهریار کوچولو گفتم:
|
||||
-خاطرات تو راستی راستی زیباند اما من هنوز از پسِ تعمیر هواپیما برنیامدهام، یک چکه آب هم ندارم. و راستی که من هم اگر میتوانستم خوشخوشک به طرف چشمهای بروم سعادتی احساس میکردم که نگو!
|
||||
درآمد که: -دوستم روباه...
|
||||
گفتم: -آقا کوچولو، دورِ روباه را قلم بگیر!
|
||||
-واسه چی؟
|
||||
-واسه این که تشنگی کارمان را می سازد. واسه این!
|
||||
از استدلال من چیزی حالیش نشد و در جوابم گفت:
|
||||
-حتا اگر آدم دَمِ مرگ باشد هم داشتن یک دوست عالی است. من که از داشتن یک دوستِ روباه خیلی خوشحالم...
|
||||
به خودم گفتم نمیتواند میزان خطر را تخمین بزند: آخر او هیچ وقت نه تشنهاش میشود نه گشنهاش. یه ذره آفتاب بسش است...
|
||||
اما او به من نگاه کرد و در جواب فکرم گفت: -من هم تشنهم است... بگردیم یک چاه پیدا کنیم...
|
||||
از سرِ خستگی حرکتی کردم: -این جوری تو کویرِ برهوت رو هوا پیِ چاه گشتن احمقانه است.
|
||||
و با وجود این به راه افتادیم.
|
||||
|
||||
پس از ساعتها که در سکوت راه رفتیم شب شد و ستارهها یکی یکی درآمدند. من که از زور تشنگی تب کرده بودم انگار آنها را خواب میدیدم. حرفهای شهریار کوچولو تو ذهنم میرقصید.
|
||||
ازش پرسیدم: -پس تو هم تشنهات هست، ها؟
|
||||
اما او به سوآلِ من جواب نداد فقط در نهایت سادگی گفت: -آب ممکن است برای دلِ من هم خوب باشد...
|
||||
از حرفش چیزی دستگیرم نشد اما ساکت ماندم. میدانستم از او نباید حرف کشید.
|
||||
خسته شده بود. گرفت نشست. من هم کنارش نشستم. پس از مدتی سکوت گفت:
|
||||
-قشنگیِ ستارهها واسه خاطرِ گلی است که ما نمیبینیمش...
|
||||
گفتم: -همین طور است
|
||||
و بدون حرف در مهتاب غرق تماشای چین و شکنهای شن شدم.
|
||||
باز گفت: -کویر زیباست.
|
||||
|
||||
و حق با او بود. من همیشه عاشق کویر بودهام. آدم بالای تودهای شن لغزان مینشیند، هیچی نمیبیند و هیچی نمیشنود اما با وجود این چیزی توی سکوت برقبرق میزند.
|
||||
شهریار کوچولو گفت: -چیزی که کویر را زیبا میکند این است که یک جایی یک چاه قایم کرده...
|
||||
از اینکه ناگهان به راز آن درخشش اسرارآمیزِ شن پی بردم حیرتزده شدم. بچگیهام تو خانهی کهنهسازی مینشستیم که معروف بود تو آن گنجی چال کردهاند. البته نگفته پیداست که هیچ وقت کسی آن را پیدا نکرد و شاید حتا اصلا کسی دنبالش نگشت اما فکرش همهی اهل خانه را تردماغ میکرد: «خانهی ما تهِ دلش رازی پنهان کرده بود...»
|
||||
گفتم: -آره. چه خانه باشد چه ستاره، چه کویر، چیزی که اسباب زیباییاش میشود نامریی است!
|
||||
گفت: -خوشحالم که با روباه من توافق داری.
|
||||
|
||||
چون خوابش برده بود بغلش کردم و راه افتادم. دست و دلم میلرزید.انگار چیز شکستنیِ بسیار گرانبهایی را روی دست میبردم. حتا به نظرم میآمد که تو تمام عالم چیزی شکستنیتر از آن هم به نظر نمیرسد. تو روشنی مهتاب به آن پیشانی رنگپریده و آن چشمهای بسته و آن طُرّههای مو که باد میجنباند نگاه کردم و تو دلم گفتم: «آن چه میبینم صورت ظاهری بیشتر نیست. مهمترش را با چشم نمیشود دید...»
|
||||
باز، چون دهان نیمهبازش طرح کمرنگِ نیمهلبخندی را داشت به خود گفتم: «چیزی که تو شهریار کوچولوی خوابیده مرا به این شدت متاثر میکند وفاداری اوست به یک گل: او تصویرِ گل سرخی است که مثل شعلهی چراغی حتا در خوابِ ناز هم که هست تو وجودش میدرخشد...» و آن وقت او را باز هم شکنندهتر دیدم. حس کردم باید خیلی مواظبش باشم: به شعلهی چراغی میمانست که یک وزش باد هم میتوانست خاموشش کند.
|
||||
و همان طور در حال راه رفتن بود که دمدمهی سحر چاه را پیداکردم.
|
||||
|
||||
۲۵
|
||||
شهریار کوچولو درآمد که: -آدمها!... میچپند تو قطارهای تندرو اما نمیدانند دنبال چی میگردند. این است که بنامیکنند دور خودشان چرخکزدن.
|
||||
و بعد گفت: -این هم کار نشد...
|
||||
چاهی که بهاش رسیدهبودیم اصلا به چاههای کویری نمیمانست. چاه کویری یک چالهی ساده است وسط شنها. این یکی به چاههای واحهای میمانست اما آن دوروبر واحهای نبود و من فکر کردم دارم خواب میبینم.
|
||||
گفتم: -عجیب است! قرقره و سطل و تناب، همهچیز روبهراه است.
|
||||
خندید تناب را گرفت و قرقره را به کار انداخت
|
||||
|
||||
شهریار کوچولو در حالِ کشیدنِ آب از چاه
|
||||
و قرقره مثل بادنمای کهنهای که تا مدتها پس از خوابیدنِ باد مینالد به نالهدرآمد.
|
||||
گفت: -میشنوی؟ ما داریم این چاه را از خواب بیدار میکنیم و او دارد برایمان آواز میخواند...
|
||||
دلم نمیخواست او تلاش و تقلا کند. بش گفتم: -بدهش به من. برای تو زیادی سنگین است.
|
||||
سطل را آرام تا طوقهی چاه آوردم بالا و آنجا کاملا در تعادل نگهش داشتم. از حاصل کار شاد بودم. خسته و شاد. آواز قرقره را همانطور تو گوشم داشتم و تو آب که هنوز میلرزید لرزش خورشید را میدیدم.
|
||||
گفت: -بده من، که تشنهی این آبم.
|
||||
ومن تازه توانستم بفهمم پی چه چیز میگشته!
|
||||
|
||||
سطل را تا لبهایش بالا بردم. با چشمهای بسته نوشید. آبی بود به شیرینیِ عیدی. این آب به کُلّی چیزی بود سوایِ هرگونه خوردنی. زاییدهی راه رفتنِ زیر ستارهها و سرود قرقره و تقلای بازوهای من بود. مثل یک چشم روشنی برای دل خوب بود. پسر بچه که بودم هم، چراغ درخت عید و موسیقیِ نماز نیمهشب عید کریسمس و لطف لبخندهها عیدیی را که بم میدادند درست به همین شکل آن همه جلا و جلوه میبخشید.
|
||||
گفت: -مردم سیارهی تو ور میدارند پنج هزار تا گل را تو یک گلستان میکارند، و آن یک دانهای را که پِیَش میگردند آن وسط پیدا نمیکنند...
|
||||
گفتم: -پیدایش نمیکنند.
|
||||
-با وجود این، چیزی که پیَش میگردند ممکن است فقط تو یک گل یا تو یک جرعه آب پیدا بشود...
|
||||
جواب دادم: -گفتوگو ندارد.
|
||||
باز گفت: -گیرم چشمِ سَر کور است، باید با چشم دل پیاش گشت.
|
||||
من هم سیراب شده بودم. راحت نفس میکشیدم. وقتی آفتاب درمیآید شن به رنگ عسل است. من هم از این رنگ عسلی لذت میبردم. چرا میبایست در زحمت باشم...
|
||||
شهریار کوچولو که باز گرفته بود کنار من نشسته بود با لطف بم گفت: -هِی! قولت قول باشد ها!
|
||||
-کدام قول؟
|
||||
-یادت است؟ یک پوزهبند برای بَرّهام... آخر من مسئول گلمَم!
|
||||
طرحهای اولیهام را از جیب درآوردم. نگاهشان کرد و خندانخندان گفت: -بائوبابهات یک خرده شبیه کلم شده.
|
||||
ای وای! مرا بگو که آنقدر به بائوبابهام مینازیدم.
|
||||
-روباهت... گوشهاش بیشتر به شاخ میماند... زیادی درازند!
|
||||
و باز زد زیر خنده.
|
||||
-آقا کوچولو داری بیانصافی میکنی. من جز بوآهای بسته و بوآهای باز چیزی بلد نبودم بکشم که.
|
||||
گفت: -خب، مهم نیست. عوضش بچهها سرشان تو حساب است.
|
||||
با مداد یک پوزهبند کشیدم دادم دستش و با دلِ فشرده گفتم:
|
||||
-تو خیالاتی به سر داری که من ازشان بیخبرم...
|
||||
اما جواب مرا نداد. بم گفت: -میدانی؟ فردا سالِ به زمین آمدنِ من است.
|
||||
بعد پس از لحظهای سکوت دوباره گفت: -همین نزدیکیها پایین آمدم.
|
||||
و سرخ شد.
|
||||
|
||||
و من از نو بی این که بدانم چرا غم عجیبی احساس کردم. با وجود این سوآلی به ذهنم رسید: -پس هشت روز پیش، آن روز صبح که تو تک و تنها هزار میل دورتر از هر آبادی وسطِ کویر به من برخوردی اتفاقی نبود: داشتی برمیگشتی به همان جایی که پایینآمدی...
|
||||
دوباره سرخ شد
|
||||
و من با دودلی به دنبال حرفم گفتم:
|
||||
-شاید به مناسبت همین سالگرد؟...
|
||||
باز سرخ شد. او هیچ وقت به سوآلهایی که ازش میشد جواب نمیداد اما وقتی کسی سرخ میشود معنیش این است که «بله»، مگر نه؟
|
||||
بهاش گفتم: -آخر، من ترسم برداشته...
|
||||
اما او حرفم را برید:
|
||||
-دیگر تو باید بروی به کارت برسی. باید بروی سراغ موتورت. من همینجا منتظرت میمانم. فردا عصر برگرد...
|
||||
|
||||
منتها من خاطر جمع نبودم. به یاد روباه افتادم: اگر آدم گذاشت اهلیش کنند بفهمینفهمی خودش را به این خطر انداخته که کارش به گریهکردن بکشد.
|
||||
|
||||
۲۶
|
||||
کنار چاه دیوارِ سنگی مخروبهای بود. فردا عصر که از سرِ کار برگشتم از دور دیدم که آن بالا نشسته پاها را آویزان کرده،
|
||||
|
||||
شهریار کوچولو نشسته بر دیوارِ سنگی و مار در پایینِ آن
|
||||
و شنیدم که میگوید:
|
||||
-پس یادت نمیآید؟ درست این نقطه نبود ها!
|
||||
لابد صدای دیگری بهاش جوابی داد، چون شهریار کوچولو در رَدِّ حرفش گفت:
|
||||
-چرا چرا! روزش که درست همین امروز است گیرم محلش این جا نیست...
|
||||
راهم را به طرف دیوار ادامه دادم. هنوز نه کسی به چشم خورده بود نه صدای کسی را شنیده بودم اما شهریار کوچولو باز در جواب درآمد که:
|
||||
-... آره، معلوم است. خودت میتوانی ببینی رَدِّ پاهایم روی شن از کجا شروع میشود.
|
||||
همان جا منتظرم باش، تاریک که شد میآیم.
|
||||
بیست متری دیوار بودم و هنوز چیزی نمیدیدم. پس از مختصر مکثی دوباره گفت:
|
||||
-زهرت خوب هست؟ مطمئنی درد و زجرم را کِش نمیدهد؟
|
||||
با دل فشرده از راه ماندم اما هنوز از موضوع سر در نیاورده بودم.
|
||||
گفت: -خب، حالا دیگر برو. دِ برو. میخواهم بیایم پایین!
|
||||
|
||||
آن وقت من نگاهم را به پایین به پای دیوار انداختم و از جا جستم! یکی از آن مارهای زردی که تو سی ثانیه کَلَکِ آدم را میکنند، به طرف شهریار کوچولو قد راست کرده بود. من همان طور که به دنبال تپانچه دست به جیبم میبردم پا گذاشتم به دو، اما ماره از سر و صدای من مثل فوارهای که بنشیند آرام روی شن جاری شد و بی آن که چندان عجلهای از خودش نشان دهد باصدای خفیف فلزی لای سنگها خزید.
|
||||
من درست به موقع به دیوار رسیدم و طفلکی شهریار کوچولو را که رنگش مثل برف پریده بود تو هوا بغل کردم.
|
||||
-این دیگر چه حکایتی است! حالا دیگر با مارها حرف میزنی؟
|
||||
شال زردش را که مدام به گردن داشت باز کردم به شقیقههایش آب زدم و جرعهای بهاش نوشاندم. اما حالا دیگر اصلا جرات نمی کردم ازش چیزی بپرسم. با وقار به من نگاه کرد و دستش را دور گردنم انداخت. حس کردم قلبش مثل قلب پرندهای میزند که تیر خوردهاست و دارد میمیرد.
|
||||
گفت: -از این که کم و کسرِ لوازم ماشینت را پیدا کردی خوشحالم. حالا میتوانی برگردی خانهات...
|
||||
-تو از کجا فهمیدی؟
|
||||
درست همان دم لبواکردهبودم بش خبر بدهم که علیرغم همهی نومیدیها تو کارم موفق شدهام!
|
||||
به سوآلهای من هیچ جوابی نداد اما گفت: -آخر من هم امروز بر میگردم خانهام...
|
||||
و بعد غمزده درآمد که: -گیرم راه من خیلی دورتر است... خیلی سختتر است...
|
||||
|
||||
حس میکردم اتفاق فوقالعادهای دارد میافتد. گرفتمش تو بغلم. عین یک بچهی کوچولو. با وجود این به نظرم میآمد که او دارد به گردابی فرو میرود و برای نگه داشتنش از من کاری ساخته نیست... نگاه متینش به دوردستهای دور راه کشیده بود.
|
||||
گفت: بَرِّهات را دارم. جعبههه را هم واسه برههه دارم. پوزهبنده را هم دارم.
|
||||
و با دلِ گرفته لبخندی زد.
|
||||
مدت درازی صبر کردم. حس کردم کمکمَک تنش دوباره دارد گرم میشود.
|
||||
-عزیز کوچولوی من، وحشت کردی...
|
||||
-امشب وحشت خیلی بیشتری چشم بهراهم است.
|
||||
|
||||
دوباره از احساسِ واقعهای جبران ناپذیر یخ زدم. این فکر که دیگر هیچ وقت غشغش خندهی او را نخواهم شنید برایم سخت تحملناپذیر بود. خندهی او برای من به چشمهای در دلِ کویر میمانست.
|
||||
-کوچولوئَکِ من، دلم میخواهد باز هم غشغشِ خندهات را بشنوم.
|
||||
اما بهام گفت: -امشب درست میشود یک سال و اخترَکَم درست بالای همان نقطهای میرسد که پارسال به زمین آمدم.
|
||||
-کوچولوئک، این قضیهی مار و میعاد و ستاره یک خواب آشفته بیشتر نیست. مگر نه؟
|
||||
به سوال من جوابی نداد اما گفت: -چیزی که مهم است با چشمِ سَر دیده نمیشود.
|
||||
-مسلم است.
|
||||
-در مورد گل هم همینطور است: اگر گلی را دوست داشته باشی که تو یک ستارهی دیگر است، شب تماشای آسمان چه لطفی پیدا میکند: همهی ستارهها غرق گل میشوند!
|
||||
-مسلم است...
|
||||
-در مورد آب هم همینطور است. آبی که تو به من دادی به خاطر قرقره و ریسمان درست به یک موسیقی میمانست... یادت که هست... چه خوب بود.
|
||||
-مسلم است...
|
||||
-شببهشب ستارهها را نگاه میکنی. اخترک من کوچولوتر از آن است که بتوانم جایش را نشانت بدهم. اما چه بهتر! آن هم برای تو میشود یکی از ستارهها؛ و آن وقت تو دوست داری همهی ستارهها را تماشا کنی... همهشان میشوند دوستهای تو... راستی میخواهم هدیهای بت بدهم...
|
||||
و غش غش خندید.
|
||||
-آخ، کوچولوئک، کوچولوئک! من عاشقِ شنیدنِ این خندهام!
|
||||
-هدیهی من هم درست همین است... درست مثل مورد آب.
|
||||
-چی میخواهی بگویی؟
|
||||
-همهی مردم ستاره دارند اما همهی ستارهها یکجور نیست: واسه آنهایی که به سفر میروند حکم راهنما را دارند واسه بعضی دیگر فقط یک مشت روشناییِ سوسوزناند. برای بعضی که اهل دانشند هر ستاره یک معما است واسه آن بابای تاجر طلا بود. اما این ستارهها همهشان زبان به کام کشیده و خاموشند. فقط تو یکی ستارههایی خواهی داشت که تنابندهای مِثلش را ندارد.
|
||||
-چی میخواهی بگویی؟
|
||||
-نه این که من تو یکی از ستارههام؟ نه این که من تو یکی از آنها میخندم؟... خب، پس هر شب که به آسمان نگاه میکنی برایت مثل این خواهد بود که همهی ستارهها میخندند. پس تو ستارههایی خواهی داشت که بلدند بخندند!
|
||||
و باز خندید.
|
||||
-و خاطرت که تسلا پیدا کرد (خب بالاخره آدمیزاد یک جوری تسلا پیدا میکند دیگر) از آشنایی با من خوشحال میشوی. دوست همیشگی من باقی میمانی و دلت میخواهد با من بخندی و پارهای وقتهام واسه تفریح پنجرهی اتاقت را وا میکنی... دوستانت از اینکه میبینند تو به آسمان نگاه میکنی و میخندی حسابی تعجب میکنند آن وقت تو بهشان میگویی: «آره، ستارهها همیشه مرا خنده میاندازند!» و آنوقت آنها یقینشان میشود که تو پاک عقلت را از دست دادهای. جان! میبینی چه کَلَکی بهات زدهام...
|
||||
و باز زد زیر خنده.
|
||||
-به آن میماند که عوضِ ستاره یک مشت زنگوله بت داده باشم که بلدند بخندند...
|
||||
دوباره خندید و بعد حالتی جدی به خودش گرفت:
|
||||
-نه، من تنهات نمیگذارم.
|
||||
|
||||
شهریار کوچولو تنها
|
||||
|
||||
-ظاهر آدمی را پیدا میکنم که دارد درد میکشد... یک خرده هم مثل آدمی میشوم که دارد جان میکند. رو هم رفته این جوریها است. نیا که این را نبینی. چه زحمتی است بیخود؟
|
||||
-تنهات نمیگذارم.
|
||||
اندوهزده بود.
|
||||
-این را بیشتر از بابت ماره میگویم که، نکند یکهو تو را هم بگزد. مارها خیلی خبیثند. حتا واسه خنده هم ممکن است آدم را نیش بزنند.
|
||||
-تنهات نمیگذارم.
|
||||
منتها یک چیز باعث خاطر جمعیش شد:
|
||||
-گر چه، بار دوم که بخواهند بگزند دیگر زهر ندارند.
|
||||
شب متوجه راه افتادنش نشدم. بی سر و صدا گریخت.
|
||||
وقتی خودم را بهاش رساندم با قیافهی مصمم و قدمهای محکم پیش میرفت. همین قدر گفت: -اِ! اینجایی؟
|
||||
و دستم را گرفت.
|
||||
اما باز بیقرار شد وگفت: -اشتباه کردی آمدی. رنج میبری. گرچه حقیقت این نیست، اما ظاهرِ یک مرده را پیدا میکنم.
|
||||
من ساکت ماندم.
|
||||
-خودت درک میکنی. راه خیلی دور است. نمیتوانم این جسم را با خودم ببرم. خیلی سنگین است.
|
||||
من ساکت ماندم.
|
||||
-گیرم عینِ پوستِ کهنهای میشود که دورش انداخته باشند؛ پوست کهنه که غصه ندارد، ها؟
|
||||
من ساکت ماندم.
|
||||
کمی دلسرد شد اما باز هم سعی کرد:
|
||||
-خیلی با مزه میشود، نه؟ من هم به ستارهها نگاه میکنم. همشان به صورت چاههایی در میآیند با قرقرههای زنگ زده. همهی ستارهها بم آب میدهند بخورم...
|
||||
من ساکت ماندم.
|
||||
-خیلی با مزه میشود. نه؟ تو صاحب هزار کرور زنگوله میشوی من صاحب هزار کرور فواره...
|
||||
او هم ساکت شد، چرا که داشت گریه میکرد...
|
||||
-خب، همین جاست. بگذار چند قدم خودم تنهایی بروم.
|
||||
و گرفت نشست، چرا که میترسید.
|
||||
|
||||
شهریار کوچولو نشسته
|
||||
|
||||
میدانی؟... گلم را میگویم... آخر من مسئولشم. تازه چه قدر هم لطیف است و چه قدر هم ساده و بیشیلهپیله. برای آن که جلو همهی عالم از خودش دفاع کند همهاش چی دارد مگر؟ چهارتا خار پِرپِرَک!
|
||||
|
||||
من هم گرفتم نشستم. دیگر نمیتوانستم سر پا بند بشوم.
|
||||
گفت: -همین... همهاش همین و بس...
|
||||
باز هم کمی دودلی نشان داد اما بالاخره پا شد و قدمی به جلو رفت. من قادر به حرکت نبودم.
|
||||
|
||||
کنار قوزکِ پایش جرقهی زردی جست و... فقط همین! یک دم بیحرکت ماند. فریادی نزد. مثل درختی که بیفتد آرامآرام به زمین افتاد که به وجود شن از آن هم صدایی بلند نشد.
|
||||
|
||||
شهریار کوچولو در حالی که آرامآرام به زمین میافتد
|
||||
۲۷
|
||||
شش سال گذشته است و من هنوز بابت این قضیه جایی لبترنکردهام. دوستانم از این که مرا دوباره زنده میدیدند سخت شاد شدند. من غمزده بودم اما به آنها میگفتم اثر خستگی است.
|
||||
حالا کمی تسلای خاطر پیدا کردهام. یعنی نه کاملا... اما این را خوب میدانم که او به اخترکش برگشته. چون آفتاب که زد پیکرش را پیدا نکردم. پیکری هم نبود که چندان وزنی داشته باشد... و شبها دوست دارم به ستارهها گوش بدهم. عین هزار زنگولهاند.
|
||||
اما موضوع خیلی مهمی که هست، من پاک یادم رفت به پوزهبندی که برای شهریار کوچولو کشیدم تسمهی چرمی اضافه کنم و او ممکن نیست بتواند آن را به پوزهی بَرّه ببندد. این است که از خودم میپرسم: «یعنی تو اخترکش چه اتفاقی افتاده؟ نکند برههه گل را چریده باشد؟...»
|
||||
گاه به خودم میگویم: «حتما نه، شهریار کوچولو هر شب گلش را زیر حباب شیشهای میگذارد و هوای برهاش را هم دارد...» آن وقت است که خیالم راحت میشود و ستارهها همه به شیرینی میخندند.
|
||||
گاه به خودم میگویم: «همین کافی است که آدم یک بار حواسش نباشد... آمدیم و یک شب حباب یادش رفت یا بَرّه شب نصفشبی بیسروصدا از جعبه زد بیرون...» آن وقت است که زنگولهها همه تبدیل به اشک میشوند!...
|
||||
|
||||
یک راز خیلی خیلی بزرگ این جا هست: برای شما هم که او را دوست دارید، مثل من هیچ چیزِ عالم مهمتر از دانستن این نیست که تو فلان نقطهای که نمیدانیم، فلان برهای که نمیشماسیم گل سرخی را چریده یا نچریده...
|
||||
|
||||
خب. آسمان را نگاه کنید و بپرسید: «بَرّه گل را چریده یا نچریده؟» و آن وقت با چشمهای خودتان تفاوتش را ببینید...
|
||||
|
||||
و محال است آدم بزرگها روحشان خبردار بشود که این موضوع چه قدر مهم است!
|
||||
|
||||
بدونِ شهریار کوچولو
|
||||
در نظر من این زیباترین و حزنانگیزترین منظرهی عالم است. این همان منظرهی دو صفحه پیش است گیرم آن را دوباره کشیدهام که بهتر نشانتان بدهم: «ظهور شهریار کوچولو بر زمین در این جا بود؛ و بعد در همین جا هم بود که ناپدید شد».
|
||||
|
||||
آن قدر به دقت این منظره را نگاه کنید که مطمئن بشوید اگر روزی تو آفریقا گذرتان به کویر صحرا افتاد حتما آن را خواهید شناخت. و اگر پاداد و گذارتان به آن جا افتاد به التماس ازتان میخواهم که عجله به خرج ندهید و درست زیر ستاره چند لحظهای توقف کنید. آن وقت اگر بچهای به طرفتان آمد، اگر خندید، اگر موهایش طلایی بود، اگر وقتی ازش سوالی کردید جوابی نداد، لابد حدس میزنید که کیست. در آن صورت لطف کنید و نگذارید من این جور افسرده خاطر بمانم:
|
||||
بی درنگ بردارید به من بنویسید که او برگشته.
|
||||
|
200
src/Makefile.am
200
src/Makefile.am
|
@ -12,9 +12,17 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
|
|||
TESTS =
|
||||
check_PROGRAMS =
|
||||
|
||||
EXTRA_DIST += harfbuzz.cc
|
||||
EXTRA_DIST += meson.build
|
||||
EXTRA_DIST += fix_get_types.py
|
||||
|
||||
# Convenience targets:
|
||||
lib: $(BUILT_SOURCES) libharfbuzz.la
|
||||
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
|
||||
tiny:
|
||||
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Os -DHB_TINY $(CPPFLAGS)" libs
|
||||
tinyz:
|
||||
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Oz -DHB_TINY $(CPPFLAGS)" libs
|
||||
|
||||
lib_LTLIBRARIES = libharfbuzz.la
|
||||
|
||||
|
@ -28,10 +36,6 @@ HBSOURCES = $(HB_BASE_sources)
|
|||
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
|
||||
HBHEADERS = $(HB_BASE_headers)
|
||||
|
||||
if HAVE_FALLBACK
|
||||
HBSOURCES += $(HB_FALLBACK_sources)
|
||||
endif
|
||||
|
||||
if HAVE_PTHREAD
|
||||
HBCFLAGS += $(PTHREAD_CFLAGS)
|
||||
HBNONPCLIBS += $(PTHREAD_LIBS)
|
||||
|
@ -48,12 +52,7 @@ endif
|
|||
if HAVE_FREETYPE
|
||||
HBCFLAGS += $(FREETYPE_CFLAGS)
|
||||
HBLIBS += $(FREETYPE_LIBS)
|
||||
# XXX
|
||||
# The following creates a recursive dependency on FreeType if FreeType is
|
||||
# built with HarfBuzz support enabled. Newer pkg-config handles that just
|
||||
# fine but pkg-config 0.26 as shipped in Ubuntu 14.04 crashes. Remove
|
||||
# in a year or two, or otherwise work around it...
|
||||
#HBDEPS += $(FREETYPE_DEPS)
|
||||
HBDEPS += $(FREETYPE_DEPS)
|
||||
HBSOURCES += $(HB_FT_sources)
|
||||
HBHEADERS += $(HB_FT_headers)
|
||||
endif
|
||||
|
@ -80,6 +79,13 @@ HBSOURCES += $(HB_DIRECTWRITE_sources)
|
|||
HBHEADERS += $(HB_DIRECTWRITE_headers)
|
||||
endif
|
||||
|
||||
if HAVE_GDI
|
||||
HBCFLAGS += $(GDI_CXXFLAGS)
|
||||
HBNONPCLIBS += $(GDI_LIBS)
|
||||
HBSOURCES += $(HB_GDI_sources)
|
||||
HBHEADERS += $(HB_GDI_headers)
|
||||
endif
|
||||
|
||||
if HAVE_CORETEXT
|
||||
HBCFLAGS += $(CORETEXT_CFLAGS)
|
||||
HBNONPCLIBS += $(CORETEXT_LIBS)
|
||||
|
@ -87,17 +93,6 @@ HBSOURCES += $(HB_CORETEXT_sources)
|
|||
HBHEADERS += $(HB_CORETEXT_headers)
|
||||
endif
|
||||
|
||||
if HAVE_UCDN
|
||||
SUBDIRS += hb-ucdn
|
||||
HBCFLAGS += -I$(srcdir)/hb-ucdn
|
||||
HBLIBS += hb-ucdn/libhb-ucdn.la
|
||||
HBSOURCES += $(HB_UCDN_sources)
|
||||
hb-ucdn/libhb-ucdn.la: ucdn
|
||||
ucdn:
|
||||
@$(MAKE) $(AM_MAKEFLAGS) -C hb-ucdn
|
||||
endif
|
||||
DIST_SUBDIRS += hb-ucdn
|
||||
|
||||
|
||||
BUILT_SOURCES += \
|
||||
hb-version.h
|
||||
|
@ -155,6 +150,7 @@ cmake_DATA = harfbuzz-config.cmake
|
|||
EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
|
||||
|
||||
lib_LTLIBRARIES += libharfbuzz-subset.la
|
||||
libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS)
|
||||
libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources)
|
||||
libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS)
|
||||
|
@ -258,36 +254,44 @@ GENERATORS = \
|
|||
gen-indic-table.py \
|
||||
gen-os2-unicode-ranges.py \
|
||||
gen-tag-table.py \
|
||||
gen-ucd-table.py \
|
||||
gen-use-table.py \
|
||||
gen-vowel-constraints.py \
|
||||
$(NULL)
|
||||
EXTRA_DIST += $(GENERATORS)
|
||||
|
||||
unicode-tables: arabic-table indic-table tag-table use-table emoji-table
|
||||
unicode-tables: \
|
||||
arabic-table \
|
||||
emoji-table \
|
||||
indic-table \
|
||||
tag-table \
|
||||
ucd-table \
|
||||
use-table \
|
||||
emoji-table \
|
||||
$(NULL)
|
||||
|
||||
arabic-table: gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-arabic-table.hh \
|
||||
|| ($(RM) $(srcdir)/hb-ot-shape-complex-arabic-table.hh; false)
|
||||
|
||||
indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
|
||||
|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
|
||||
|
||||
tag-table: gen-tag-table.py languagetags language-subtag-registry
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
|
||||
|| ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
|
||||
|
||||
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)
|
||||
indic-table: gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-indic-table.cc \
|
||||
|| ($(RM) $(srcdir)/hb-ot-shape-complex-indic-table.cc; false)
|
||||
tag-table: gen-tag-table.py languagetags language-subtag-registry
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-tag-table.hh \
|
||||
|| ($(RM) $(srcdir)/hb-ot-tag-table.hh; false)
|
||||
ucd-table: gen-ucd-table.py ucd.nounihan.grouped.zip hb-common.h
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ucd-table.hh \
|
||||
|| ($(RM) $(srcdir)/hb-ucd-table.hh; false)
|
||||
use-table: gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-use-table.cc \
|
||||
|| ($(RM) $(srcdir)/hb-ot-shape-complex-use-table.cc; false)
|
||||
vowel-constraints: gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
|
||||
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \
|
||||
|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false)
|
||||
|
||||
|
||||
built-sources: $(BUILT_SOURCES)
|
||||
|
||||
|
@ -306,13 +310,31 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
|
|||
$(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
harfbuzz.cc: Makefile.sources
|
||||
$(AM_V_GEN) \
|
||||
for f in \
|
||||
$(HB_BASE_sources) \
|
||||
$(HB_GLIB_sources) \
|
||||
$(HB_FT_sources) \
|
||||
$(HB_GRAPHITE2_sources) \
|
||||
$(HB_UNISCRIBE_sources) \
|
||||
$(HB_GDI_sources) \
|
||||
$(HB_DIRECTWRITE_sources) \
|
||||
$(HB_CORETEXT_sources) \
|
||||
; do echo '#include "'$$f'"'; done | \
|
||||
grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
|
||||
|| ($(RM) $(srcdir)/harfbuzz.cc; false)
|
||||
BUILT_SOURCES += harfbuzz.cc
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
main \
|
||||
test \
|
||||
test-buffer-serialize \
|
||||
test-name-table \
|
||||
test-size-params \
|
||||
test-would-substitute \
|
||||
test-ot-meta \
|
||||
test-ot-name \
|
||||
test-ot-glyphname \
|
||||
test-gpos-size-params \
|
||||
test-gsub-would-substitute \
|
||||
$(NULL)
|
||||
bin_PROGRAMS =
|
||||
|
||||
|
@ -328,42 +350,25 @@ 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_ot_meta_SOURCES = test-ot-meta.cc
|
||||
test_ot_meta_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_meta_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_ot_name_SOURCES = test-ot-name.cc
|
||||
test_ot_name_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_name_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)
|
||||
test_ot_glyphname_SOURCES = test-ot-glyphname.cc
|
||||
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
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
|
||||
test_gpos_size_params_SOURCES = test-gpos-size-params.cc
|
||||
test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
|
||||
test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
dist_check_SCRIPTS = \
|
||||
check-c-linkage-decls.sh \
|
||||
check-externs.sh \
|
||||
check-header-guards.sh \
|
||||
check-includes.sh \
|
||||
check-static-inits.sh \
|
||||
check-symbols.sh \
|
||||
$(NULL)
|
||||
TESTS += $(dist_check_SCRIPTS)
|
||||
|
||||
if !WITH_LIBSTDCXX
|
||||
dist_check_SCRIPTS += \
|
||||
check-libstdc++.sh \
|
||||
$(NULL)
|
||||
endif
|
||||
test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
|
||||
test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
check_PROGRAMS += \
|
||||
dump-indic-data \
|
||||
|
@ -384,7 +389,7 @@ dump_use_data_SOURCES = dump-use-data.cc hb-ot-shape-complex-use-table.cc
|
|||
dump_use_data_CPPFLAGS = $(HBCFLAGS)
|
||||
dump_use_data_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
COMPILED_TESTS = test-algs test-iter test-ot-tag test-unicode-ranges
|
||||
COMPILED_TESTS = test-algs test-array test-iter test-meta test-number test-ot-tag test-unicode-ranges test-bimap
|
||||
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
|
||||
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
check_PROGRAMS += $(COMPILED_TESTS)
|
||||
|
@ -394,10 +399,22 @@ test_algs_SOURCES = test-algs.cc hb-static.cc
|
|||
test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_algs_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_array_SOURCES = test-array.cc
|
||||
test_array_CPPFLAGS = $(HBCFLAGS)
|
||||
test_array_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_iter_SOURCES = test-iter.cc hb-static.cc
|
||||
test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_iter_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_meta_SOURCES = test-meta.cc hb-static.cc
|
||||
test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_meta_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_number_SOURCES = test-number.cc hb-number.cc
|
||||
test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_number_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_ot_tag_SOURCES = hb-ot-tag.cc
|
||||
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
@ -406,8 +423,29 @@ test_unicode_ranges_SOURCES = test-unicode-ranges.cc
|
|||
test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_bimap_SOURCES = test-bimap.cc hb-static.cc
|
||||
test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
dist_check_SCRIPTS = \
|
||||
check-c-linkage-decls.sh \
|
||||
check-externs.sh \
|
||||
check-header-guards.sh \
|
||||
check-includes.sh \
|
||||
check-static-inits.sh \
|
||||
check-symbols.sh \
|
||||
$(NULL)
|
||||
TESTS += $(dist_check_SCRIPTS)
|
||||
|
||||
if !WITH_LIBSTDCXX
|
||||
dist_check_SCRIPTS += \
|
||||
check-libstdc++.sh \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
srcdir="$(srcdir)" \
|
||||
builddir="$(builddir)" \
|
||||
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
|
||||
HBSOURCES="$(HBSOURCES)" \
|
||||
HBHEADERS="$(HBHEADERS)" \
|
||||
|
@ -417,7 +455,16 @@ if HAVE_INTROSPECTION
|
|||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?!
|
||||
INTROSPECTION_SCANNER_ARGS = -I$(srcdir) -n hb --identifier-prefix=hb_ --warn-all
|
||||
INTROSPECTION_SCANNER_ARGS = \
|
||||
-I$(srcdir) \
|
||||
--warn-all --verbose \
|
||||
--namespace=HarfBuzz \
|
||||
--nsversion=0.0 \
|
||||
--symbol-prefix=hb \
|
||||
--symbol-prefix=hb_gobject \
|
||||
--identifier-prefix=hb_ \
|
||||
--pkg-export=harfbuzz-gobject \
|
||||
--c-include=hb-gobject.h
|
||||
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
|
||||
INTROSPECTION_SCANNER_ENV = CC="$(CC)"
|
||||
|
||||
|
@ -434,6 +481,7 @@ HarfBuzz_0_0_gir_CFLAGS = \
|
|||
-DHB_AAT_H_IN \
|
||||
-DHB_GOBJECT_H \
|
||||
-DHB_GOBJECT_H_IN \
|
||||
-DHAVE_GOBJECT \
|
||||
-DHB_EXTERN= \
|
||||
$(NULL)
|
||||
HarfBuzz_0_0_gir_LIBS = \
|
||||
|
|
|
@ -10,6 +10,7 @@ HB_BASE_sources = \
|
|||
hb-aat-layout-kerx-table.hh \
|
||||
hb-aat-layout-lcar-table.hh \
|
||||
hb-aat-layout-morx-table.hh \
|
||||
hb-aat-layout-opbd-table.hh \
|
||||
hb-aat-layout-trak-table.hh \
|
||||
hb-aat-layout.cc \
|
||||
hb-aat-layout.hh \
|
||||
|
@ -31,10 +32,14 @@ HB_BASE_sources = \
|
|||
hb-cff1-interp-cs.hh \
|
||||
hb-cff2-interp-cs.hh \
|
||||
hb-common.cc \
|
||||
hb-config.hh \
|
||||
hb-debug.hh \
|
||||
hb-dispatch.hh \
|
||||
hb-draw.cc \
|
||||
hb-draw.hh \
|
||||
hb-face.cc \
|
||||
hb-face.hh \
|
||||
hb-fallback-shape.cc \
|
||||
hb-font.cc \
|
||||
hb-font.hh \
|
||||
hb-iter.hh \
|
||||
|
@ -42,15 +47,19 @@ HB_BASE_sources = \
|
|||
hb-machinery.hh \
|
||||
hb-map.cc \
|
||||
hb-map.hh \
|
||||
hb-bimap.hh \
|
||||
hb-meta.hh \
|
||||
hb-mutex.hh \
|
||||
hb-null.hh \
|
||||
hb-number.cc \
|
||||
hb-number.hh \
|
||||
hb-object.hh \
|
||||
hb-open-file.hh \
|
||||
hb-open-type.hh \
|
||||
hb-ot-cff-common.hh \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-ot-cff1-table.hh \
|
||||
hb-ot-cff1-std-str.hh \
|
||||
hb-ot-cff2-table.cc \
|
||||
hb-ot-cff2-table.hh \
|
||||
hb-ot-cmap-table.hh \
|
||||
|
@ -62,6 +71,7 @@ HB_BASE_sources = \
|
|||
hb-ot-color.cc \
|
||||
hb-ot-face.cc \
|
||||
hb-ot-face.hh \
|
||||
hb-ot-face-table-list.hh \
|
||||
hb-ot-font.cc \
|
||||
hb-ot-gasp-table.hh \
|
||||
hb-ot-glyf-table.hh \
|
||||
|
@ -84,7 +94,11 @@ HB_BASE_sources = \
|
|||
hb-ot-math-table.hh \
|
||||
hb-ot-math.cc \
|
||||
hb-ot-maxp-table.hh \
|
||||
hb-ot-name-language.cc \
|
||||
hb-ot-meta-table.hh \
|
||||
hb-ot-meta.cc \
|
||||
hb-ot-metrics.cc \
|
||||
hb-ot-metrics.hh \
|
||||
hb-ot-name-language-static.hh \
|
||||
hb-ot-name-language.hh \
|
||||
hb-ot-name-table.hh \
|
||||
hb-ot-name.cc \
|
||||
|
@ -125,6 +139,7 @@ HB_BASE_sources = \
|
|||
hb-ot-tag.cc \
|
||||
hb-ot-var-avar-table.hh \
|
||||
hb-ot-var-fvar-table.hh \
|
||||
hb-ot-var-gvar-table.hh \
|
||||
hb-ot-var-hvar-table.hh \
|
||||
hb-ot-var-mvar-table.hh \
|
||||
hb-ot-var.cc \
|
||||
|
@ -144,18 +159,20 @@ HB_BASE_sources = \
|
|||
hb-shaper.hh \
|
||||
hb-static.cc \
|
||||
hb-string-array.hh \
|
||||
hb-ucd-table.hh \
|
||||
hb-ucd.cc \
|
||||
hb-unicode-emoji-table.hh \
|
||||
hb-unicode.cc \
|
||||
hb-unicode.hh \
|
||||
hb-utf.hh \
|
||||
hb-vector.hh \
|
||||
hb-warning.cc \
|
||||
hb.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_BASE_RAGEL_GENERATED_sources = \
|
||||
hb-buffer-deserialize-json.hh \
|
||||
hb-buffer-deserialize-text.hh \
|
||||
hb-number-parser.hh \
|
||||
hb-ot-shape-complex-indic-machine.hh \
|
||||
hb-ot-shape-complex-khmer-machine.hh \
|
||||
hb-ot-shape-complex-myanmar-machine.hh \
|
||||
|
@ -164,6 +181,7 @@ HB_BASE_RAGEL_GENERATED_sources = \
|
|||
HB_BASE_RAGEL_sources = \
|
||||
hb-buffer-deserialize-json.rl \
|
||||
hb-buffer-deserialize-text.rl \
|
||||
hb-number-parser.rl \
|
||||
hb-ot-shape-complex-indic-machine.rl \
|
||||
hb-ot-shape-complex-khmer-machine.rl \
|
||||
hb-ot-shape-complex-myanmar-machine.rl \
|
||||
|
@ -177,6 +195,7 @@ HB_BASE_headers = \
|
|||
hb-buffer.h \
|
||||
hb-common.h \
|
||||
hb-deprecated.h \
|
||||
hb-draw.h \
|
||||
hb-face.h \
|
||||
hb-font.h \
|
||||
hb-map.h \
|
||||
|
@ -185,6 +204,8 @@ HB_BASE_headers = \
|
|||
hb-ot-font.h \
|
||||
hb-ot-layout.h \
|
||||
hb-ot-math.h \
|
||||
hb-ot-meta.h \
|
||||
hb-ot-metrics.h \
|
||||
hb-ot-name.h \
|
||||
hb-ot-shape.h \
|
||||
hb-ot-var.h \
|
||||
|
@ -197,10 +218,6 @@ HB_BASE_headers = \
|
|||
hb.h \
|
||||
$(NULL)
|
||||
|
||||
HB_FALLBACK_sources = \
|
||||
hb-fallback-shape.cc \
|
||||
$(NULL)
|
||||
|
||||
# Optional Sources and Headers with external deps
|
||||
|
||||
HB_FT_sources = hb-ft.cc
|
||||
|
@ -220,18 +237,20 @@ HB_CORETEXT_headers = hb-coretext.h
|
|||
HB_DIRECTWRITE_sources = hb-directwrite.cc
|
||||
HB_DIRECTWRITE_headers = hb-directwrite.h
|
||||
|
||||
HB_GDI_sources = hb-gdi.cc
|
||||
HB_GDI_headers = hb-gdi.h
|
||||
|
||||
HB_UNISCRIBE_sources = hb-uniscribe.cc
|
||||
HB_UNISCRIBE_headers = hb-uniscribe.h
|
||||
|
||||
# Additional supplemental sources
|
||||
HB_UCDN_sources = hb-ucdn.cc
|
||||
|
||||
# Sources for libharfbuzz-gobject and libharfbuzz-icu
|
||||
HB_ICU_sources = hb-icu.cc
|
||||
HB_ICU_headers = hb-icu.h
|
||||
|
||||
# Sources for libharfbuzz-subset
|
||||
HB_SUBSET_sources = \
|
||||
hb-number.cc \
|
||||
hb-number.hh \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-ot-cff2-table.cc \
|
||||
hb-static.cc \
|
||||
|
@ -241,9 +260,6 @@ HB_SUBSET_sources = \
|
|||
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 \
|
||||
|
|
|
@ -22,8 +22,7 @@ fi
|
|||
|
||||
tested=false
|
||||
# harfbuzz-icu links to libstdc++ because icu does.
|
||||
# harfbuzz-subset uses libstdc++.
|
||||
for soname in harfbuzz harfbuzz-gobject; do
|
||||
for soname in harfbuzz harfbuzz-subset harfbuzz-gobject; do
|
||||
for suffix in so dylib; do
|
||||
so=$libs/lib$soname.$suffix
|
||||
if ! test -f "$so"; then continue; fi
|
||||
|
|
|
@ -4,7 +4,7 @@ LC_ALL=C
|
|||
export LC_ALL
|
||||
|
||||
test -z "$srcdir" && srcdir=.
|
||||
test -z "$libs" && libs=.libs
|
||||
test -z "$builddir" && builddir=.
|
||||
stat=0
|
||||
|
||||
if which objdump 2>/dev/null >/dev/null; then
|
||||
|
@ -14,18 +14,21 @@ else
|
|||
exit 77
|
||||
fi
|
||||
|
||||
OBJS=$libs/*.o
|
||||
OBJS=$(find $builddir/ -name '*.o')
|
||||
if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then
|
||||
echo "check-static-inits.sh: object files not found; skipping test"
|
||||
exit 77
|
||||
fi
|
||||
|
||||
tested=false
|
||||
|
||||
echo "Checking that no object file has static initializers"
|
||||
for obj in $OBJS; do
|
||||
if objdump -t "$obj" | grep '[.][cd]tors' | grep -v '\<00*\>'; then
|
||||
echo "Ouch, $obj has static initializers/finalizers"
|
||||
stat=1
|
||||
fi
|
||||
tested=true
|
||||
done
|
||||
|
||||
echo "Checking that no object file has lazy static C++ constructors/destructors or other such stuff"
|
||||
|
@ -35,6 +38,12 @@ for obj in $OBJS; do
|
|||
echo "Ouch, $obj has lazy static C++ constructors/destructors or other such stuff"
|
||||
stat=1
|
||||
fi
|
||||
tested=true
|
||||
done
|
||||
|
||||
if ! $tested; then
|
||||
echo "check-static-inits.sh: no objects found; skipping test"
|
||||
exit 77
|
||||
fi
|
||||
|
||||
exit $stat
|
||||
|
|
|
@ -4,10 +4,11 @@ LC_ALL=C
|
|||
export LC_ALL
|
||||
|
||||
test -z "$srcdir" && srcdir=.
|
||||
test -z "$builddir" && builddir=.
|
||||
test -z "$libs" && libs=.libs
|
||||
stat=0
|
||||
|
||||
IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_flush\|llvm_.*'
|
||||
IGNORED_SYMBOLS='_fini\|_init\|_fdata\|_ftext\|_fbss\|__bss_start\|__bss_start__\|__bss_end__\|_edata\|_end\|_bss_end__\|__end__\|__gcov_.*\|llvm_.*'
|
||||
|
||||
if which nm 2>/dev/null >/dev/null; then
|
||||
:
|
||||
|
@ -26,7 +27,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 ' [BCDGIRST] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`
|
||||
|
||||
prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
|
||||
|
||||
|
@ -36,7 +37,7 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
|
|||
stat=1
|
||||
fi
|
||||
|
||||
def=$soname.def
|
||||
def=$builddir/$soname.def
|
||||
if ! test -f "$def"; then
|
||||
echo "'$def' not found; skipping"
|
||||
else
|
||||
|
@ -47,9 +48,9 @@ for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
|
|||
# cheat: copy the last line from the def file!
|
||||
tail -n1 "$def"
|
||||
} | c++filt | diff "$def" - >&2 || stat=1
|
||||
fi
|
||||
|
||||
tested=true
|
||||
tested=true
|
||||
fi
|
||||
done
|
||||
done
|
||||
if ! $tested; then
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Suggested setup to use the script:
|
||||
# (on the root of the project)
|
||||
# $ NOCONFIGURE=1 ./autogen.sh && mkdir build && cd build
|
||||
# $ ../configure --with-freetype --with-glib --with-gobject --with-cairo
|
||||
# $ make -j5 && cd ..
|
||||
# $ src/dev-run.sh [FONT-FILE] [TEXT]
|
||||
#
|
||||
# Or, using cmake:
|
||||
# $ cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild
|
||||
# $ src/dev-run.sh [FONT-FILE] [TEXT]
|
||||
#
|
||||
# If you want to open the result rendering using a GUI app,
|
||||
# $ src/dev-run.sh open [FONT-FILE] [TEXT]
|
||||
#
|
||||
# And if you are using iTerm2, you can use the script like this,
|
||||
# $ src/dev-run.sh img [FONT-FILE] [TEXT]
|
||||
#
|
||||
|
||||
[ $# = 0 ] && echo Usage: "src/dev-run.sh [FONT-FILE] [TEXT]" && exit
|
||||
command -v entr >/dev/null 2>&1 || { echo >&2 "This script needs `entr` be installed"; exit 1; }
|
||||
|
||||
|
||||
GDB=gdb
|
||||
# if gdb doesn't exist, hopefully lldb exist
|
||||
command -v $GDB >/dev/null 2>&1 || export GDB="lldb"
|
||||
|
||||
|
||||
[ $1 = "open" ] && openimg=1 && shift
|
||||
OPEN=xdg-open
|
||||
[ "$(uname)" == "Darwin" ] && OPEN=open
|
||||
|
||||
|
||||
[ $1 = "img" ] && img=1 && shift
|
||||
# http://iterm2.com/documentation-images.html
|
||||
osc="\033]"
|
||||
if [[ $TERM == screen* ]]; then osc="\033Ptmux;\033\033]"; fi
|
||||
st="\a"
|
||||
if [[ $TERM == screen* ]]; then st="\a"; fi
|
||||
|
||||
|
||||
tmp=tmp.png
|
||||
[ -f 'build/build.ninja' ] && CMAKENINJA=TRUE
|
||||
# or "fswatch -0 . -e build/ -e .git"
|
||||
find src/ | entr printf '\0' | while read -d ""; do
|
||||
clear
|
||||
yes = | head -n`tput cols` | tr -d '\n'
|
||||
if [[ $CMAKENINJA ]]; then
|
||||
ninja -Cbuild hb-shape hb-view && {
|
||||
build/hb-shape $@
|
||||
if [ $openimg ]; then
|
||||
build/hb-view $@ -O png -o $tmp
|
||||
$OPEN $tmp
|
||||
elif [ $img ]; then
|
||||
build/hb-view $@ -O png -o $tmp
|
||||
printf "\n${osc}1337;File=;inline=1:`cat $tmp | base64`${st}\n"
|
||||
else
|
||||
build/hb-view $@
|
||||
fi
|
||||
}
|
||||
else
|
||||
make -Cbuild/src -j5 -s lib && {
|
||||
build/util/hb-shape $@
|
||||
if [ $openimg ]; then
|
||||
build/util/hb-view $@ -O png -o $tmp
|
||||
$OPEN $tmp
|
||||
elif [ $img ]; then
|
||||
build/util/hb-view $@ -O png -o $tmp
|
||||
printf "\n${osc}1337;File=;inline=1:`cat $tmp | base64`${st}\n"
|
||||
else
|
||||
build/util/hb-view $@
|
||||
fi
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
read -n 1 -p "[C]heck, [D]ebug, [R]estart, [Q]uit? " answer
|
||||
case "$answer" in
|
||||
c|C )
|
||||
if [[ $CMAKENINJA ]]; then
|
||||
CTEST_OUTPUT_ON_FAILURE=1 CTEST_PARALLEL_LEVEL=5 ninja -Cbuild test
|
||||
else
|
||||
make -Cbuild -j5 check && .ci/fail.sh
|
||||
fi
|
||||
;;
|
||||
d|D )
|
||||
if [[ $CMAKENINJA ]]; then
|
||||
echo "Not supported on cmake builds yet"
|
||||
else
|
||||
build/libtool --mode=execute $GDB -- build/util/hb-shape $@
|
||||
fi
|
||||
;;
|
||||
r|R )
|
||||
src/dev-run.sh $@
|
||||
;;
|
||||
* )
|
||||
exit
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,15 @@
|
|||
import re
|
||||
import argparse
|
||||
|
||||
if __name__=='__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('input')
|
||||
parser.add_argument('output')
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.input, 'r') as inp:
|
||||
with open(args.output, 'w') as out:
|
||||
for l in inp.readlines():
|
||||
l = re.sub('_t_get_type', '_get_type', l)
|
||||
l = re.sub('_T \(', ' (', l)
|
||||
out.write(l)
|
|
@ -1,11 +1,15 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import io, os.path, sys
|
||||
|
||||
if len (sys.argv) != 4:
|
||||
print ("usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt", file=sys.stderr)
|
||||
print ("""usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
|
||||
|
||||
Input files, as of Unicode 12:
|
||||
* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt
|
||||
""", file=sys.stderr)
|
||||
sys.exit (1)
|
||||
|
||||
files = [io.open (x, encoding='utf-8') for x in sys.argv[1:]]
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import io, os, re, sys
|
||||
|
||||
|
@ -15,10 +13,35 @@ for h in header_paths:
|
|||
if h.endswith (".h"):
|
||||
with io.open (h, encoding='utf-8') as f: headers_content.append (f.read ())
|
||||
|
||||
symbols = "\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M)))
|
||||
symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))
|
||||
if '--experimental-api' not in sys.argv:
|
||||
# Move these to harfbuzz-sections.txt when got stable
|
||||
experimental_symbols = \
|
||||
"""hb_font_draw_glyph
|
||||
hb_draw_funcs_t
|
||||
hb_draw_close_path_func_t
|
||||
hb_draw_cubic_to_func_t
|
||||
hb_draw_line_to_func_t
|
||||
hb_draw_move_to_func_t
|
||||
hb_draw_quadratic_to_func_t
|
||||
hb_draw_funcs_create
|
||||
hb_draw_funcs_destroy
|
||||
hb_draw_funcs_is_immutable
|
||||
hb_draw_funcs_make_immutable
|
||||
hb_draw_funcs_reference
|
||||
hb_draw_funcs_set_close_path_func
|
||||
hb_draw_funcs_set_cubic_to_func
|
||||
hb_draw_funcs_set_line_to_func
|
||||
hb_draw_funcs_set_move_to_func
|
||||
hb_draw_funcs_set_quadratic_to_func
|
||||
hb_font_get_var_coords_design
|
||||
hb_ot_layout_closure_lookups
|
||||
hb_ot_layout_closure_features""".splitlines ()
|
||||
symbols = [x for x in symbols if x not in experimental_symbols]
|
||||
symbols = "\n".join (symbols)
|
||||
|
||||
result = symbols if os.environ.get('PLAIN_LIST', '') else """EXPORTS
|
||||
%s
|
||||
LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('.def', ''))
|
||||
LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('src/', '').replace ('.def', ''))
|
||||
|
||||
with open (output_file, "w") as f: f.write (result)
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
import sys
|
||||
import os.path
|
||||
from collections import OrderedDict
|
||||
import packTab
|
||||
|
||||
if len (sys.argv) != 2:
|
||||
print("usage: ./gen-emoji-table.py emoji-data.txt", file=sys.stderr)
|
||||
print("""usage: ./gen-emoji-table.py emoji-data.txt
|
||||
|
||||
Input file, as of Unicode 12:
|
||||
* https://www.unicode.org/Public/emoji/12.0/emoji-data.txt""", file=sys.stderr)
|
||||
sys.exit (1)
|
||||
|
||||
f = open(sys.argv[1])
|
||||
|
@ -52,14 +55,19 @@ print ()
|
|||
print ('#include "hb-unicode.hh"')
|
||||
print ()
|
||||
|
||||
for typ,s in ranges.items():
|
||||
for typ, s in ranges.items():
|
||||
if typ != "Extended_Pictographic": continue
|
||||
|
||||
arr = dict()
|
||||
for start,end in s:
|
||||
for i in range(start,end):
|
||||
arr[i] = 1
|
||||
|
||||
sol = packTab.pack_table(arr, 0, compression=3)
|
||||
code = packTab.Code('_hb_emoji')
|
||||
sol.genCode(code, 'is_'+typ)
|
||||
code.print_c(linkage='static inline')
|
||||
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 */")
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import io, sys
|
||||
|
||||
if len (sys.argv) != 4:
|
||||
print ("usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt", file=sys.stderr)
|
||||
print ("""usage: ./gen-indic-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt Blocks.txt
|
||||
|
||||
Input files, as of Unicode 12:
|
||||
* https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt""", file=sys.stderr)
|
||||
sys.exit (1)
|
||||
|
||||
ALLOWED_SINGLES = [0x00A0, 0x25CC]
|
||||
|
@ -98,6 +101,10 @@ for h in headers:
|
|||
print (" * %s" % (l.strip()))
|
||||
print (" */")
|
||||
print ()
|
||||
print ('#include "hb.hh"')
|
||||
print ()
|
||||
print ('#ifndef HB_NO_OT_SHAPE')
|
||||
print ()
|
||||
print ('#include "hb-ot-shape-complex-indic.hh"')
|
||||
print ()
|
||||
|
||||
|
@ -129,8 +136,8 @@ what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
|
|||
what_short = ["ISC", "IMC"]
|
||||
print ('#pragma GCC diagnostic push')
|
||||
print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
|
||||
cat_defs = []
|
||||
for i in range (2):
|
||||
print ()
|
||||
vv = sorted (values[i].keys ())
|
||||
for v in vv:
|
||||
v_no_and = v.replace ('_And_', '_')
|
||||
|
@ -142,10 +149,17 @@ for i in range (2):
|
|||
raise Exception ("Duplicate short value alias", v, all_shorts[i][s])
|
||||
all_shorts[i][s] = v
|
||||
short[i][v] = s
|
||||
print ("#define %s_%s %s_%s %s/* %3d chars; %s */" %
|
||||
(what_short[i], s, what[i], v.upper (),
|
||||
' '* ((48-1 - len (what[i]) - 1 - len (v)) // 8),
|
||||
values[i][v], v))
|
||||
cat_defs.append ((what_short[i] + '_' + s, what[i] + '_' + v.upper (), str (values[i][v]), v))
|
||||
|
||||
maxlen_s = max ([len (c[0]) for c in cat_defs])
|
||||
maxlen_l = max ([len (c[1]) for c in cat_defs])
|
||||
maxlen_n = max ([len (c[2]) for c in cat_defs])
|
||||
for s in what_short:
|
||||
print ()
|
||||
for c in [c for c in cat_defs if s in c[0]]:
|
||||
print ("#define %s %s /* %s chars; %s */" %
|
||||
(c[0].ljust (maxlen_s), c[1].ljust (maxlen_l), c[2].rjust (maxlen_n), c[3]))
|
||||
print ()
|
||||
print ('#pragma GCC diagnostic pop')
|
||||
print ()
|
||||
print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
|
||||
|
@ -245,12 +259,14 @@ print ("}")
|
|||
print ()
|
||||
print ("#undef _")
|
||||
for i in range (2):
|
||||
print
|
||||
print ()
|
||||
vv = sorted (values[i].keys ())
|
||||
for v in vv:
|
||||
print ("#undef %s_%s" %
|
||||
(what_short[i], short[i][v]))
|
||||
print ()
|
||||
print ('#endif')
|
||||
print ()
|
||||
print ("/* == End of generated table == */")
|
||||
|
||||
# Maintain at least 30% occupancy in the table */
|
||||
|
|
|
@ -1,20 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
|
||||
# Input is a tab seperated list of unicode ranges from the otspec
|
||||
# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1).
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
|
||||
|
||||
import io
|
||||
import re
|
||||
import sys
|
||||
|
||||
try:
|
||||
reload(sys)
|
||||
sys.setdefaultencoding('utf-8')
|
||||
except NameError:
|
||||
pass # Python 3
|
||||
|
||||
print ("""static OS2Range _hb_os2_unicode_ranges[] =
|
||||
{""")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Generator of the mapping from OpenType tags to BCP 47 tags and vice
|
||||
versa.
|
||||
|
@ -18,18 +18,11 @@ first BCP 47 tag happens to be the chosen disambiguated tag. In that
|
|||
case, the fallback behavior will choose the right tag anyway.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
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'))
|
||||
from html.parser import HTMLParser
|
||||
def write (s):
|
||||
sys.stdout.flush ()
|
||||
sys.stdout.buffer.write (s.encode ('utf-8'))
|
||||
import io
|
||||
import itertools
|
||||
import re
|
||||
|
@ -37,16 +30,16 @@ import sys
|
|||
import unicodedata
|
||||
|
||||
if len (sys.argv) != 3:
|
||||
print ('usage: ./gen-tag-table.py languagetags language-subtag-registry', file=sys.stderr)
|
||||
print ('''usage: ./gen-tag-table.py languagetags language-subtag-registry
|
||||
|
||||
Input files, as of Unicode 12:
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
|
||||
* https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry''', file=sys.stderr)
|
||||
sys.exit (1)
|
||||
|
||||
try:
|
||||
from html import unescape
|
||||
def html_unescape (parser, entity):
|
||||
return unescape (entity)
|
||||
except ImportError:
|
||||
def html_unescape (parser, entity):
|
||||
return parser.unescape (entity)
|
||||
from html import unescape
|
||||
def html_unescape (parser, entity):
|
||||
return unescape (entity)
|
||||
|
||||
def expect (condition, message=None):
|
||||
if not condition:
|
||||
|
@ -54,7 +47,7 @@ def expect (condition, message=None):
|
|||
raise AssertionError
|
||||
raise AssertionError (message)
|
||||
|
||||
# from http://www-01.sil.org/iso639-3/iso-639-3.tab
|
||||
# from https://www-01.sil.org/iso639-3/iso-639-3.tab
|
||||
ISO_639_3_TO_1 = {
|
||||
'aar': 'aa',
|
||||
'abk': 'ab',
|
||||
|
@ -754,7 +747,7 @@ ot.add_language ('und-Syre', 'SYRE')
|
|||
ot.add_language ('und-Syrj', 'SYRJ')
|
||||
ot.add_language ('und-Syrn', 'SYRN')
|
||||
|
||||
bcp_47.names['xst'] = u"Silt'e"
|
||||
bcp_47.names['xst'] = "Silt'e"
|
||||
bcp_47.scopes['xst'] = ' (retired code)'
|
||||
bcp_47.macrolanguages['xst'] = {'stv', 'wle'}
|
||||
|
||||
|
@ -861,7 +854,7 @@ def hb_tag (tag):
|
|||
Returns:
|
||||
A snippet of C++ representing ``tag``.
|
||||
"""
|
||||
return u"HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
|
||||
return "HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
|
||||
|
||||
def get_variant_set (name):
|
||||
"""Return a set of variant language names from a name.
|
||||
|
@ -873,7 +866,7 @@ def get_variant_set (name):
|
|||
Returns:
|
||||
A set of normalized language names.
|
||||
"""
|
||||
return set (unicodedata.normalize ('NFD', n.replace ('\u2019', u"'"))
|
||||
return set (unicodedata.normalize ('NFD', n.replace ('\u2019', "'"))
|
||||
.encode ('ASCII', 'ignore')
|
||||
.strip ()
|
||||
for n in re.split ('[\n(),]', name) if n)
|
||||
|
@ -895,20 +888,18 @@ def language_name_intersection (a, b):
|
|||
def get_matching_language_name (intersection, candidates):
|
||||
return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c))))
|
||||
|
||||
maximum_tags = 0
|
||||
def same_tag (bcp_47_tag, ot_tags):
|
||||
return len (bcp_47_tag) == 3 and len (ot_tags) == 1 and bcp_47_tag == ot_tags[0].lower ()
|
||||
|
||||
for language, tags in sorted (ot.from_bcp_47.items ()):
|
||||
if language == '' or '-' in language:
|
||||
continue
|
||||
print (' {\"%s\",\t{' % language, end='')
|
||||
maximum_tags = max (maximum_tags, len (tags))
|
||||
tag_count = len (tags)
|
||||
commented_out = same_tag (language, tags)
|
||||
for i, tag in enumerate (tags, start=1):
|
||||
if i > 1:
|
||||
print ('\t\t ', end='')
|
||||
print (hb_tag (tag), end='')
|
||||
if i == tag_count:
|
||||
print ('}}', end='')
|
||||
print (',\t/* ', end='')
|
||||
print ('%s{\"%s\",\t%s},' % ('/*' if commented_out else ' ', language, hb_tag (tag)), end='')
|
||||
if commented_out:
|
||||
print ('*/', end='')
|
||||
print ('\t/* ', end='')
|
||||
bcp_47_name = bcp_47.names.get (language, '')
|
||||
bcp_47_name_candidates = bcp_47_name.split ('\n')
|
||||
intersection = language_name_intersection (bcp_47_name, ot.names[tag])
|
||||
|
@ -923,8 +914,6 @@ for language, tags in sorted (ot.from_bcp_47.items ()):
|
|||
|
||||
print ('};')
|
||||
print ()
|
||||
print ('static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == %iu, "");' % maximum_tags)
|
||||
print ()
|
||||
|
||||
print ('/**')
|
||||
print (' * hb_ot_tags_from_complex_language:')
|
||||
|
@ -1051,7 +1040,8 @@ print (' * @tag: A language tag.')
|
|||
print (' *')
|
||||
print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to')
|
||||
print (' * many language tags) and the best tag is not the alphabetically first, or if')
|
||||
print (' * the best tag consists of multiple subtags.')
|
||||
print (' * the best tag consists of multiple subtags, or if the best tag does not appear')
|
||||
print (' * in #ot_languages.')
|
||||
print (' *')
|
||||
print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,')
|
||||
print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.')
|
||||
|
@ -1102,7 +1092,8 @@ def verify_disambiguation_dict ():
|
|||
'%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag))
|
||||
elif ot_tag not in disambiguation:
|
||||
disambiguation[ot_tag] = macrolanguages[0]
|
||||
if disambiguation[ot_tag] == sorted (primary_tags)[0] and '-' not in disambiguation[ot_tag]:
|
||||
different_primary_tags = sorted (t for t in primary_tags if not same_tag (t, ot.from_bcp_47.get (t)))
|
||||
if different_primary_tags and disambiguation[ot_tag] == different_primary_tags[0] and '-' not in disambiguation[ot_tag]:
|
||||
del disambiguation[ot_tag]
|
||||
for ot_tag in disambiguation.keys ():
|
||||
expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag)
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import io, os.path, sys, re
|
||||
import logging
|
||||
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
|
||||
|
||||
if len (sys.argv) not in (2, 3):
|
||||
print("""usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]
|
||||
|
||||
Input file, as of Unicode 12:
|
||||
* https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip""", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# https://github.com/harfbuzz/packtab
|
||||
import packTab
|
||||
import packTab.ucdxml
|
||||
|
||||
logging.info('Loading UCDXML...')
|
||||
ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
|
||||
ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)
|
||||
|
||||
hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
|
||||
|
||||
logging.info('Preparing data tables...')
|
||||
|
||||
gc = [u['gc'] for u in ucd]
|
||||
ccc = [int(u['ccc']) for u in ucd]
|
||||
bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
|
||||
#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass)
|
||||
#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr)
|
||||
|
||||
sc = [u['sc'] for u in ucd]
|
||||
|
||||
dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
|
||||
if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
|
||||
ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
|
||||
|
||||
assert not any(v for v in dm.values() if len(v) not in (1,2))
|
||||
dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
|
||||
assert all((v[0] >> 16) in (0,2) for v in dm1)
|
||||
dm1_p0_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 0]
|
||||
dm1_p2_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 2]
|
||||
dm1_order = {v:i+1 for i,v in enumerate(dm1)}
|
||||
|
||||
dm2 = sorted((v+(i if i not in ce and not ccc[i] else 0,), v)
|
||||
for i,v in dm.items() if len(v) == 2)
|
||||
|
||||
filt = lambda v: ((v[0] & 0xFFFFF800) == 0x0000 and
|
||||
(v[1] & 0xFFFFFF80) == 0x0300 and
|
||||
(v[2] & 0xFFF0C000) == 0x0000)
|
||||
dm2_u32_array = [v for v in dm2 if filt(v[0])]
|
||||
dm2_u64_array = [v for v in dm2 if not filt(v[0])]
|
||||
assert dm2_u32_array + dm2_u64_array == dm2
|
||||
dm2_u32_array = ["HB_CODEPOINT_ENCODE3_11_7_14 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u32_array]
|
||||
dm2_u64_array = ["HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u64_array]
|
||||
|
||||
l = 1 + len(dm1_p0_array) + len(dm1_p2_array)
|
||||
dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}
|
||||
|
||||
dm_order = {None: 0}
|
||||
dm_order.update(dm1_order)
|
||||
dm_order.update(dm2_order)
|
||||
|
||||
gc_order = dict()
|
||||
for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
|
||||
'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
|
||||
'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',)):
|
||||
gc_order[i] = v
|
||||
gc_order[v] = i
|
||||
|
||||
sc_order = dict()
|
||||
sc_array = []
|
||||
sc_re = re.compile(r"\b(HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
|
||||
for line in open(hb_common_h):
|
||||
m = sc_re.search (line)
|
||||
if not m: continue
|
||||
name = m.group(1)
|
||||
tag = ''.join(m.group(i) for i in range(2, 6))
|
||||
i = len(sc_array)
|
||||
sc_order[tag] = i
|
||||
sc_order[i] = tag
|
||||
sc_array.append(name)
|
||||
|
||||
DEFAULT = 1
|
||||
COMPACT = 3
|
||||
SLOPPY = 5
|
||||
|
||||
|
||||
logging.info('Generating output...')
|
||||
print("/* == Start of generated table == */")
|
||||
print("/*")
|
||||
print(" * The following table is generated by running:")
|
||||
print(" *")
|
||||
print(" * ./gen-ucd-table.py ucd.nounihan.grouped.xml")
|
||||
print(" *")
|
||||
print(" * on file with this description:", ucdxml.description)
|
||||
print(" */")
|
||||
print()
|
||||
print("#ifndef HB_UCD_TABLE_HH")
|
||||
print("#define HB_UCD_TABLE_HH")
|
||||
print()
|
||||
print('#include "hb.hh"')
|
||||
print()
|
||||
|
||||
code = packTab.Code('_hb_ucd')
|
||||
sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
|
||||
dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
|
||||
dm1_p2_array, _ = code.addArray('uint16_t', 'dm1_p2_map', dm1_p2_array)
|
||||
dm2_u32_array, _ = code.addArray('uint32_t', 'dm2_u32_map', dm2_u32_array)
|
||||
dm2_u64_array, _ = code.addArray('uint64_t', 'dm2_u64_map', dm2_u64_array)
|
||||
code.print_c(linkage='static inline')
|
||||
|
||||
datasets = [
|
||||
('gc', gc, 'Cn', gc_order),
|
||||
('ccc', ccc, 0, None),
|
||||
('bmg', bmg, 0, None),
|
||||
('sc', sc, 'Zzzz', sc_order),
|
||||
('dm', dm, None, dm_order),
|
||||
]
|
||||
|
||||
for compression in (DEFAULT, COMPACT, SLOPPY):
|
||||
logging.info(' Compression=%d:' % compression)
|
||||
print()
|
||||
if compression == DEFAULT:
|
||||
print('#ifndef HB_OPTIMIZE_SIZE')
|
||||
elif compression == COMPACT:
|
||||
print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
|
||||
else:
|
||||
print('#else')
|
||||
print()
|
||||
|
||||
if compression == SLOPPY:
|
||||
for i in range(len(gc)):
|
||||
if (i % 128) and gc[i] == 'Cn':
|
||||
gc[i] = gc[i - 1]
|
||||
for i in range(len(gc) - 2, -1, -1):
|
||||
if ((i + 1) % 128) and gc[i] == 'Cn':
|
||||
gc[i] = gc[i + 1]
|
||||
for i in range(len(sc)):
|
||||
if (i % 128) and sc[i] == 'Zzzz':
|
||||
sc[i] = sc[i - 1]
|
||||
for i in range(len(sc) - 2, -1, -1):
|
||||
if ((i + 1) % 128) and sc[i] == 'Zzzz':
|
||||
sc[i] = sc[i + 1]
|
||||
|
||||
|
||||
code = packTab.Code('_hb_ucd')
|
||||
|
||||
for name,data,default,mapping in datasets:
|
||||
sol = packTab.pack_table(data, default, mapping=mapping, compression=compression)
|
||||
logging.info(' Dataset=%-8s FullCost=%d' % (name, sol.fullCost))
|
||||
sol.genCode(code, name)
|
||||
|
||||
code.print_c(linkage='static inline')
|
||||
|
||||
print()
|
||||
|
||||
print('#endif')
|
||||
print()
|
||||
|
||||
print()
|
||||
print("#endif /* HB_UCD_TABLE_HH */")
|
||||
print()
|
||||
print("/* == End of generated table == */")
|
||||
logging.info('Done.')
|
|
@ -1,13 +1,17 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# flake8: noqa
|
||||
|
||||
from __future__ import print_function, division, absolute_import
|
||||
|
||||
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)
|
||||
print ("""usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt UnicodeData.txt Blocks.txt
|
||||
|
||||
Input file, as of Unicode 12:
|
||||
* https://unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/IndicPositionalCategory.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt""", file=sys.stderr)
|
||||
sys.exit (1)
|
||||
|
||||
BLACKLISTED_BLOCKS = ["Thai", "Lao"]
|
||||
|
@ -47,8 +51,22 @@ 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][0x1B61] = defaults[0]
|
||||
data[0][0x1B63] = defaults[0]
|
||||
data[0][0x1B64] = defaults[0]
|
||||
data[0][0x1B65] = defaults[0]
|
||||
data[0][0x1B66] = defaults[0]
|
||||
data[0][0x1B67] = defaults[0]
|
||||
data[0][0x1B69] = defaults[0]
|
||||
data[0][0x1B6A] = defaults[0]
|
||||
data[0][0x2060] = defaults[0]
|
||||
# TODO https://github.com/roozbehp/unicode-data/issues/9
|
||||
# TODO https://github.com/harfbuzz/harfbuzz/pull/1685
|
||||
data[0][0x1B5B] = 'Consonant_Placeholder'
|
||||
data[0][0x1B5C] = 'Consonant_Placeholder'
|
||||
data[0][0x1B5F] = 'Consonant_Placeholder'
|
||||
data[0][0x1B62] = 'Consonant_Placeholder'
|
||||
data[0][0x1B68] = 'Consonant_Placeholder'
|
||||
# TODO https://github.com/harfbuzz/harfbuzz/issues/1035
|
||||
data[0][0x11C44] = 'Consonant_Placeholder'
|
||||
data[0][0x11C45] = 'Consonant_Placeholder'
|
||||
# TODO https://github.com/harfbuzz/harfbuzz/pull/1399
|
||||
|
@ -133,18 +151,13 @@ property_names = [
|
|||
'Overstruck',
|
||||
]
|
||||
|
||||
try:
|
||||
basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
|
||||
class PropertyValue(object):
|
||||
def __init__(self, name_):
|
||||
self.name = name_
|
||||
def __str__(self):
|
||||
return self.name
|
||||
def __eq__(self, other):
|
||||
return self.name == (other if isinstance(other, basestring) else other.name)
|
||||
return self.name == (other if isinstance(other, str) else other.name)
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
def __hash__(self):
|
||||
|
@ -171,7 +184,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, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
|
||||
(UGC == Po and not U in [0x104B, 0x104E, 0x1B5B, 0x1B5C, 0x1B5F, 0x2022, 0x111C8, 0x11A3F, 0x11A45, 0x11C44, 0x11C45]) or
|
||||
False # SPEC-DRAFT-OUTDATED! U == 0x002D
|
||||
)
|
||||
def is_BASE_NUM(U, UISC, UGC):
|
||||
|
@ -183,15 +196,15 @@ def is_BASE_OTHER(U, UISC, UGC):
|
|||
def is_CGJ(U, UISC, UGC):
|
||||
return U == 0x034F
|
||||
def is_CONS_FINAL(U, UISC, UGC):
|
||||
# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
|
||||
return ((UISC == Consonant_Final and UGC != Lo) or
|
||||
UISC == Consonant_Initial_Postfixed or
|
||||
UISC == Consonant_Succeeding_Repha)
|
||||
def is_CONS_FINAL_MOD(U, UISC, UGC):
|
||||
#SPEC-DRAFT return UISC in [Consonant_Final_Modifier, Syllable_Modifier]
|
||||
return UISC == Syllable_Modifier
|
||||
def is_CONS_MED(U, UISC, UGC):
|
||||
return UISC == Consonant_Medial and UGC != Lo
|
||||
# Consonant_Initial_Postfixed is new in Unicode 11; not in the spec.
|
||||
return (UISC == Consonant_Medial and UGC != Lo or
|
||||
UISC == Consonant_Initial_Postfixed)
|
||||
def is_CONS_MOD(U, UISC, UGC):
|
||||
return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
|
||||
def is_CONS_SUB(U, UISC, UGC):
|
||||
|
@ -200,7 +213,9 @@ 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] and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
|
||||
return (UISC in [Virama, Invisible_Stacker]
|
||||
and not is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC)
|
||||
and not is_SAKOT(U, UISC, UGC))
|
||||
def is_HALANT_OR_VOWEL_MODIFIER(U, UISC, UGC):
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/1102
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/1379
|
||||
|
@ -216,6 +231,7 @@ def is_Word_Joiner(U, UISC, UGC):
|
|||
def is_OTHER(U, UISC, UGC):
|
||||
#SPEC-OUTDATED return UGC == Zs # or any other SCRIPT_COMMON characters
|
||||
return (UISC == Other
|
||||
and not is_SYM(U, UISC, UGC)
|
||||
and not is_SYM_MOD(U, UISC, UGC)
|
||||
and not is_CGJ(U, UISC, UGC)
|
||||
and not is_Word_Joiner(U, UISC, UGC)
|
||||
|
@ -225,20 +241,22 @@ def is_Reserved(U, UISC, UGC):
|
|||
return UGC == 'Cn'
|
||||
def is_REPHA(U, UISC, UGC):
|
||||
return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
|
||||
def is_SAKOT(U, UISC, UGC):
|
||||
return U == 0x1A60
|
||||
def is_SYM(U, UISC, UGC):
|
||||
if U == 0x25CC: return False #SPEC-DRAFT
|
||||
#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
|
||||
return UGC in [So, Sc]
|
||||
return UGC in [So, Sc] and U not in [0x1B62, 0x1B68]
|
||||
def is_SYM_MOD(U, UISC, UGC):
|
||||
return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
|
||||
def is_VARIATION_SELECTOR(U, UISC, UGC):
|
||||
return 0xFE00 <= U <= 0xFE0F
|
||||
def is_VOWEL(U, UISC, UGC):
|
||||
# https://github.com/roozbehp/unicode-data/issues/6
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/376
|
||||
return (UISC == Pure_Killer or
|
||||
(UGC != Lo and UISC in [Vowel, Vowel_Dependent] and U not in [0xAA29]))
|
||||
def is_VOWEL_MOD(U, UISC, UGC):
|
||||
# https://github.com/roozbehp/unicode-data/issues/6
|
||||
# https://github.com/harfbuzz/harfbuzz/issues/376
|
||||
return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
|
||||
(UGC != Lo and (UISC == Bindu or U in [0xAA29])))
|
||||
|
||||
|
@ -264,6 +282,7 @@ use_mapping = {
|
|||
'Rsv': is_Reserved,
|
||||
'R': is_REPHA,
|
||||
'S': is_SYM,
|
||||
'Sk': is_SAKOT,
|
||||
'SM': is_SYM_MOD,
|
||||
'VS': is_VARIATION_SELECTOR,
|
||||
'V': is_VOWEL,
|
||||
|
@ -305,7 +324,11 @@ use_positions = {
|
|||
'H': None,
|
||||
'HVM': None,
|
||||
'B': None,
|
||||
'FM': None,
|
||||
'FM': {
|
||||
'Abv': [Top],
|
||||
'Blw': [Bottom],
|
||||
'Pst': [Not_Applicable],
|
||||
},
|
||||
'SUB': None,
|
||||
}
|
||||
|
||||
|
@ -344,15 +367,9 @@ def map_to_use(data):
|
|||
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
|
||||
if U == 0x1CED: UISC = Tone_Mark
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/issues/525
|
||||
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]
|
||||
|
@ -365,6 +382,9 @@ def map_to_use(data):
|
|||
# TODO: In USE's override list but not in Unicode 12.0
|
||||
if U == 0x103C: UIPC = Left
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/2012
|
||||
if U == 0x1C29: UIPC = Left
|
||||
|
||||
# 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
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
|
||||
|
@ -401,6 +421,10 @@ for h in headers:
|
|||
print (" * %s" % (l.strip()))
|
||||
print (" */")
|
||||
print ()
|
||||
print ('#include "hb.hh"')
|
||||
print ()
|
||||
print ('#ifndef HB_NO_OT_SHAPE')
|
||||
print ()
|
||||
print ('#include "hb-ot-shape-complex-use.hh"')
|
||||
print ()
|
||||
|
||||
|
@ -515,6 +539,8 @@ for k,v in sorted(use_positions.items()):
|
|||
tag = k + suf
|
||||
print ("#undef %s" % tag)
|
||||
print ()
|
||||
print ()
|
||||
print ('#endif')
|
||||
print ("/* == End of generated table == */")
|
||||
|
||||
# Maintain at least 50% occupancy in the table */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""Generator of the function to prohibit certain vowel sequences.
|
||||
|
||||
|
@ -6,26 +6,23 @@ It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted
|
|||
circles into sequences prohibited by the USE script development spec.
|
||||
This function should be used as the ``preprocess_text`` of an
|
||||
``hb_ot_complex_shaper_t``.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
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'))
|
||||
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)
|
||||
print ("""usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
|
||||
|
||||
Input file, as of Unicode 12:
|
||||
* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt""", file=sys.stderr)
|
||||
sys.exit (1)
|
||||
|
||||
with io.open (sys.argv[2], encoding='utf-8') as f:
|
||||
|
@ -84,7 +81,8 @@ class ConstraintSet (object):
|
|||
else:
|
||||
self._c[first] = ConstraintSet (rest)
|
||||
|
||||
def _indent (self, depth):
|
||||
@staticmethod
|
||||
def _indent (depth):
|
||||
return (' ' * depth).replace (' ', '\t')
|
||||
|
||||
def __str__ (self, index=0, depth=4):
|
||||
|
@ -92,17 +90,20 @@ class ConstraintSet (object):
|
|||
indent = self._indent (depth)
|
||||
if isinstance (self._c, list):
|
||||
if len (self._c) == 0:
|
||||
assert index == 2, 'Cannot use `matched` for this constraint; the general case has not been implemented'
|
||||
s.append ('{}matched = true;\n'.format (indent))
|
||||
elif len (self._c) == 1:
|
||||
assert index == 1, 'Cannot use `matched` for this constraint; the general case has not been implemented'
|
||||
s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or ''))
|
||||
else:
|
||||
s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index))
|
||||
s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), len (self._c)))
|
||||
s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index or ''))
|
||||
if index:
|
||||
s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), index + 1))
|
||||
for i, cp in enumerate (self._c[1:], start=1):
|
||||
s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format (
|
||||
self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
|
||||
s.append ('{}{{\n'.format (indent))
|
||||
for i in range (len (self._c)):
|
||||
for i in range (index + 1):
|
||||
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))
|
||||
|
@ -128,7 +129,12 @@ class ConstraintSet (object):
|
|||
|
||||
constraints = {}
|
||||
with io.open (sys.argv[1], encoding='utf-8') as f:
|
||||
constraints_header = [f.readline ().strip () for i in range (2)]
|
||||
constraints_header = []
|
||||
while True:
|
||||
line = f.readline ().strip ()
|
||||
if line == '#':
|
||||
break
|
||||
constraints_header.append(line)
|
||||
for line in f:
|
||||
j = line.find ('#')
|
||||
if j >= 0:
|
||||
|
@ -147,7 +153,7 @@ print ('/* == Start of generated functions == */')
|
|||
print ('/*')
|
||||
print (' * The following functions are generated by running:')
|
||||
print (' *')
|
||||
print (' * %s use Scripts.txt' % sys.argv[0])
|
||||
print (' * %s ms-use/IndicShapingInvalidCluster.txt Scripts.txt' % sys.argv[0])
|
||||
print (' *')
|
||||
print (' * on files with these headers:')
|
||||
print (' *')
|
||||
|
@ -157,6 +163,11 @@ print (' *')
|
|||
for line in scripts_header:
|
||||
print (' * %s' % line.strip ())
|
||||
print (' */')
|
||||
|
||||
print ()
|
||||
print ('#include "hb.hh"')
|
||||
print ()
|
||||
print ('#ifndef HB_NO_OT_SHAPE')
|
||||
print ()
|
||||
print ('#include "hb-ot-shape-complex-vowel-constraints.hh"')
|
||||
print ()
|
||||
|
@ -180,6 +191,9 @@ print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB
|
|||
print ('\t\t\t\t hb_buffer_t *buffer,')
|
||||
print ('\t\t\t\t hb_font_t *font HB_UNUSED)')
|
||||
print ('{')
|
||||
print ('#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS')
|
||||
print (' return;')
|
||||
print ('#endif')
|
||||
print (' if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
|
||||
print (' return;')
|
||||
print ()
|
||||
|
@ -220,4 +234,6 @@ print (' }')
|
|||
print ('}')
|
||||
|
||||
print ()
|
||||
print ()
|
||||
print ('#endif')
|
||||
print ('/* == End of generated functions == */')
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#include "hb-aat-layout.cc"
|
||||
#include "hb-aat-map.cc"
|
||||
#include "hb-blob.cc"
|
||||
#include "hb-buffer-serialize.cc"
|
||||
#include "hb-buffer.cc"
|
||||
#include "hb-common.cc"
|
||||
#include "hb-draw.cc"
|
||||
#include "hb-face.cc"
|
||||
#include "hb-fallback-shape.cc"
|
||||
#include "hb-font.cc"
|
||||
#include "hb-map.cc"
|
||||
#include "hb-number.cc"
|
||||
#include "hb-ot-cff1-table.cc"
|
||||
#include "hb-ot-cff2-table.cc"
|
||||
#include "hb-ot-color.cc"
|
||||
#include "hb-ot-face.cc"
|
||||
#include "hb-ot-font.cc"
|
||||
#include "hb-ot-layout.cc"
|
||||
#include "hb-ot-map.cc"
|
||||
#include "hb-ot-math.cc"
|
||||
#include "hb-ot-meta.cc"
|
||||
#include "hb-ot-metrics.cc"
|
||||
#include "hb-ot-name.cc"
|
||||
#include "hb-ot-shape-complex-arabic.cc"
|
||||
#include "hb-ot-shape-complex-default.cc"
|
||||
#include "hb-ot-shape-complex-hangul.cc"
|
||||
#include "hb-ot-shape-complex-hebrew.cc"
|
||||
#include "hb-ot-shape-complex-indic-table.cc"
|
||||
#include "hb-ot-shape-complex-indic.cc"
|
||||
#include "hb-ot-shape-complex-khmer.cc"
|
||||
#include "hb-ot-shape-complex-myanmar.cc"
|
||||
#include "hb-ot-shape-complex-thai.cc"
|
||||
#include "hb-ot-shape-complex-use-table.cc"
|
||||
#include "hb-ot-shape-complex-use.cc"
|
||||
#include "hb-ot-shape-complex-vowel-constraints.cc"
|
||||
#include "hb-ot-shape-fallback.cc"
|
||||
#include "hb-ot-shape-normalize.cc"
|
||||
#include "hb-ot-shape.cc"
|
||||
#include "hb-ot-tag.cc"
|
||||
#include "hb-ot-var.cc"
|
||||
#include "hb-set.cc"
|
||||
#include "hb-shape-plan.cc"
|
||||
#include "hb-shape.cc"
|
||||
#include "hb-shaper.cc"
|
||||
#include "hb-static.cc"
|
||||
#include "hb-ucd.cc"
|
||||
#include "hb-unicode.cc"
|
||||
#include "hb-glib.cc"
|
||||
#include "hb-ft.cc"
|
||||
#include "hb-graphite2.cc"
|
||||
#include "hb-uniscribe.cc"
|
||||
#include "hb-gdi.cc"
|
||||
#include "hb-directwrite.cc"
|
||||
#include "hb-coretext.cc"
|
|
@ -65,7 +65,7 @@ struct FontDescriptor
|
|||
protected:
|
||||
Tag tag; /* The 4-byte table tag name. */
|
||||
union {
|
||||
Fixed value; /* The value for the descriptor tag. */
|
||||
HBFixed value; /* The value for the descriptor tag. */
|
||||
HBUINT32 nalfType; /* If the tag is `nalf`, see non_alphabetic_value_t */
|
||||
} u;
|
||||
public:
|
||||
|
@ -80,10 +80,10 @@ struct fdsc
|
|||
Weight = HB_TAG ('w','g','h','t'),
|
||||
/* Percent weight relative to regular weight.
|
||||
* (defaul value: 1.0) */
|
||||
Width = HB_TAG ('w','d','t','h'),
|
||||
Width = HB_TAG ('w','d','t','h'),
|
||||
/* Percent width relative to regular width.
|
||||
* (default value: 1.0) */
|
||||
Slant = HB_TAG ('s','l','n','t'),
|
||||
Slant = HB_TAG ('s','l','n','t'),
|
||||
/* Angle of slant in degrees, where positive
|
||||
* is clockwise from straight up.
|
||||
* (default value: 0.0) */
|
||||
|
@ -108,7 +108,7 @@ struct fdsc
|
|||
}
|
||||
|
||||
protected:
|
||||
Fixed version; /* Version number of the font descriptors
|
||||
HBFixed version; /* Version number of the font descriptors
|
||||
* table (0x00010000 for the current version). */
|
||||
LArrayOf<FontDescriptor>
|
||||
descriptors; /* List of tagged-coordinate pairs style descriptors
|
||||
|
|
|
@ -66,7 +66,7 @@ struct ankr
|
|||
{
|
||||
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
|
||||
if (!offset)
|
||||
return Null(Anchor);
|
||||
return Null (Anchor);
|
||||
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
|
||||
return anchors[i];
|
||||
}
|
||||
|
@ -81,9 +81,9 @@ struct ankr
|
|||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Version number (set to zero) */
|
||||
HBUINT16 version; /* Version number (set to zero) */
|
||||
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > >
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
|
||||
lookupTable; /* Offset to the table's lookup table */
|
||||
LNNOffsetTo<HBUINT8>
|
||||
anchorData; /* Offset to the glyph data table */
|
||||
|
|
|
@ -82,7 +82,7 @@ struct BaselineTableFormat2Part
|
|||
}
|
||||
|
||||
protected:
|
||||
GlyphID stdGlyph; /* The specific glyph index number in this
|
||||
HBGlyphID stdGlyph; /* The specific glyph index number in this
|
||||
* font that is used to set the baseline values.
|
||||
* This is the standard glyph.
|
||||
* This glyph must contain a set of control points
|
||||
|
@ -105,7 +105,7 @@ struct BaselineTableFormat3Part
|
|||
}
|
||||
|
||||
protected:
|
||||
GlyphID stdGlyph; /* ditto */
|
||||
HBGlyphID stdGlyph; /* ditto */
|
||||
HBUINT16 ctlPoints[32]; /* ditto */
|
||||
Lookup<HBUINT16>
|
||||
lookupTable; /* Lookup table that maps glyphs to their
|
||||
|
|
|
@ -93,8 +93,8 @@ struct LookupSegmentSingle
|
|||
return_trace (c->check_struct (this) && value.sanitize (c, base));
|
||||
}
|
||||
|
||||
GlyphID last; /* Last GlyphID in this segment */
|
||||
GlyphID first; /* First GlyphID in this segment */
|
||||
HBGlyphID last; /* Last GlyphID in this segment */
|
||||
HBGlyphID first; /* First GlyphID in this segment */
|
||||
T value; /* The lookup value (only one) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4 + T::static_size);
|
||||
|
@ -125,7 +125,7 @@ struct LookupFormat2
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
VarSizedBinSearchArrayOf<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). */
|
||||
|
@ -153,18 +153,18 @@ struct LookupSegmentArray
|
|||
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
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1, user_data));
|
||||
valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
|
||||
}
|
||||
|
||||
GlyphID last; /* Last GlyphID in this segment */
|
||||
GlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T> >
|
||||
HBGlyphID last; /* Last GlyphID in this segment */
|
||||
HBGlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T>>
|
||||
valuesZ; /* A 16-bit offset from the start of
|
||||
* the table to the data. */
|
||||
public:
|
||||
|
@ -196,7 +196,7 @@ struct LookupFormat4
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 4 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
|
||||
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). */
|
||||
|
@ -222,7 +222,7 @@ struct LookupSingle
|
|||
return_trace (c->check_struct (this) && value.sanitize (c, base));
|
||||
}
|
||||
|
||||
GlyphID glyph; /* Last GlyphID */
|
||||
HBGlyphID glyph; /* Last GlyphID */
|
||||
T value; /* The lookup value (only one) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (2 + T::static_size);
|
||||
|
@ -253,7 +253,7 @@ struct LookupFormat6
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 6 */
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T>>
|
||||
entries; /* The actual entries, sorted by glyph index. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, entries);
|
||||
|
@ -284,7 +284,7 @@ struct LookupFormat8
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 8 */
|
||||
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
|
||||
* glyph minus the value of firstGlyph plus 1). */
|
||||
UnsizedArrayOf<T>
|
||||
|
@ -303,7 +303,7 @@ struct LookupFormat10
|
|||
const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
|
||||
return Null(T);
|
||||
return Null (T);
|
||||
|
||||
const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
|
||||
|
||||
|
@ -326,7 +326,7 @@ struct LookupFormat10
|
|||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 8 */
|
||||
HBUINT16 valueSize; /* Byte size of each value. */
|
||||
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
|
||||
* glyph minus the value of firstGlyph plus 1). */
|
||||
UnsizedArrayOf<HBUINT8>
|
||||
|
@ -358,7 +358,7 @@ struct Lookup
|
|||
case 10: return u.format10.get_value_or_null (glyph_id);
|
||||
default:
|
||||
const T *v = get_value (glyph_id, num_glyphs);
|
||||
return v ? *v : Null(T);
|
||||
return v ? *v : Null (T);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,7 +419,7 @@ struct Lookup
|
|||
/* 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> > {
|
||||
struct Null<AAT::Lookup<T>> {
|
||||
static AAT::Lookup<T> const & get_null ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
|
||||
};
|
||||
|
@ -510,7 +510,7 @@ struct StateTable
|
|||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
|
||||
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
@ -576,7 +576,7 @@ struct StateTable
|
|||
if (unlikely (stop > states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = states; stop < p; p--)
|
||||
num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
|
||||
num_entries = hb_max (num_entries, *(p - 1) + 1);
|
||||
state_neg = min_state;
|
||||
}
|
||||
}
|
||||
|
@ -597,7 +597,7 @@ struct StateTable
|
|||
if (unlikely (stop < states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
|
||||
num_entries = MAX<unsigned int> (num_entries, *p + 1);
|
||||
num_entries = hb_max (num_entries, *p + 1);
|
||||
state_pos = max_state + 1;
|
||||
}
|
||||
}
|
||||
|
@ -611,8 +611,8 @@ struct StateTable
|
|||
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
|
||||
{
|
||||
int newState = new_state (p->newState);
|
||||
min_state = MIN (min_state, newState);
|
||||
max_state = MAX (max_state, newState);
|
||||
min_state = hb_min (min_state, newState);
|
||||
max_state = hb_max (max_state, newState);
|
||||
}
|
||||
entry = num_entries;
|
||||
}
|
||||
|
@ -631,7 +631,7 @@ struct StateTable
|
|||
classTable; /* Offset to the class table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
|
||||
stateArrayTable;/* Offset to the state array. */
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
|
||||
entryTable; /* Offset to the entry array. */
|
||||
|
||||
public:
|
||||
|
@ -658,7 +658,7 @@ struct ClassTable
|
|||
return_trace (c->check_struct (this) && classArray.sanitize (c));
|
||||
}
|
||||
protected:
|
||||
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
|
||||
* firstGlyph). */
|
||||
public:
|
||||
|
@ -678,7 +678,7 @@ struct ObsoleteTypes
|
|||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
|
||||
return (offset - ((const char *) array - (const char *) base)) / T::static_size;
|
||||
}
|
||||
template <typename T>
|
||||
static unsigned int byteOffsetToIndex (unsigned int offset,
|
||||
|
@ -825,7 +825,7 @@ struct hb_aat_apply_context_t :
|
|||
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)));
|
||||
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
|
||||
|
||||
HB_INTERNAL ~hb_aat_apply_context_t ();
|
||||
|
||||
|
|
|
@ -47,17 +47,16 @@ struct SettingName
|
|||
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
|
||||
hb_aat_layout_feature_selector_info_t get_info (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;
|
||||
return {
|
||||
nameIndex,
|
||||
(hb_aat_layout_feature_selector_t) (unsigned int) setting,
|
||||
default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
|
||||
? (hb_aat_layout_feature_selector_t) (setting + 1)
|
||||
: default_selector,
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
@ -117,9 +116,10 @@ struct FeatureName
|
|||
|
||||
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);
|
||||
+ settings_table.sub_array (start_offset, selectors_count)
|
||||
| hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
|
||||
| hb_sink (hb_array (selectors, *selectors_count))
|
||||
;
|
||||
}
|
||||
return settings_table.length;
|
||||
}
|
||||
|
@ -129,6 +129,11 @@ struct FeatureName
|
|||
|
||||
hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
|
||||
|
||||
bool is_exclusive () const { return featureFlags & Exclusive; }
|
||||
|
||||
/* A FeatureName with no settings is meaningless */
|
||||
bool has_data () const { return nSettings; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
@ -139,7 +144,7 @@ struct FeatureName
|
|||
protected:
|
||||
HBUINT16 feature; /* Feature type. */
|
||||
HBUINT16 nSettings; /* The number of records in the setting name array. */
|
||||
LOffsetTo<UnsizedArrayOf<SettingName>, false>
|
||||
LNNOffsetTo<UnsizedArrayOf<SettingName>>
|
||||
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
|
||||
|
@ -162,21 +167,21 @@ struct feat
|
|||
unsigned int *count,
|
||||
hb_aat_layout_feature_type_t *features) const
|
||||
{
|
||||
unsigned int feature_count = featureNameCount;
|
||||
if (count && *count)
|
||||
if (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;
|
||||
+ namesZ.as_array (featureNameCount).sub_array (start_offset, count)
|
||||
| hb_map (&FeatureName::get_feature_type)
|
||||
| hb_sink (hb_array (features, *count))
|
||||
;
|
||||
}
|
||||
return featureNameCount;
|
||||
}
|
||||
|
||||
bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const
|
||||
{ return get_feature (feature_type).has_data (); }
|
||||
|
||||
const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
|
||||
{
|
||||
return namesZ.bsearch (featureNameCount, feature_type);
|
||||
}
|
||||
{ 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 (); }
|
||||
|
@ -209,7 +214,7 @@ struct feat
|
|||
SortedUnsizedArrayOf<FeatureName>
|
||||
namesZ; /* The feature name array. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
DEFINE_SIZE_ARRAY (12, namesZ);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
|
|
@ -51,10 +51,10 @@ struct ActionSubrecordHeader
|
|||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
HBUINT16 actionClass; /* The JustClass value associated with this
|
||||
HBUINT16 actionClass; /* The JustClass value associated with this
|
||||
* ActionSubrecord. */
|
||||
HBUINT16 actionType; /* The type of postcompensation action. */
|
||||
HBUINT16 actionLength; /* Length of this ActionSubrecord record, which
|
||||
HBUINT16 actionType; /* The type of postcompensation action. */
|
||||
HBUINT16 actionLength; /* Length of this ActionSubrecord record, which
|
||||
* must be a multiple of 4. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (6);
|
||||
|
@ -70,11 +70,11 @@ struct DecompositionAction
|
|||
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
Fixed lowerLimit; /* If the distance factor is less than this value,
|
||||
HBFixed lowerLimit; /* If the distance factor is less than this value,
|
||||
* then the ligature is decomposed. */
|
||||
Fixed upperLimit; /* If the distance factor is greater than this value,
|
||||
HBFixed upperLimit; /* If the distance factor is greater than this value,
|
||||
* then the ligature is decomposed. */
|
||||
HBUINT16 order; /* Numerical order in which this ligature will
|
||||
HBUINT16 order; /* Numerical order in which this ligature will
|
||||
* be decomposed; you may want infrequent ligatures
|
||||
* to decompose before more frequent ones. The ligatures
|
||||
* on the line of text will decompose in increasing
|
||||
|
@ -100,7 +100,7 @@ struct UnconditionalAddGlyphAction
|
|||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
GlyphID addGlyph; /* Glyph that should be added if the distance factor
|
||||
HBGlyphID addGlyph; /* Glyph that should be added if the distance factor
|
||||
* is growing. */
|
||||
|
||||
public:
|
||||
|
@ -118,14 +118,14 @@ struct ConditionalAddGlyphAction
|
|||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
Fixed substThreshold; /* Distance growth factor (in ems) at which
|
||||
HBFixed substThreshold; /* Distance growth factor (in ems) at which
|
||||
* this glyph is replaced and the growth factor
|
||||
* recalculated. */
|
||||
GlyphID addGlyph; /* Glyph to be added as kashida. If this value is
|
||||
HBGlyphID addGlyph; /* Glyph to be added as kashida. If this value is
|
||||
* 0xFFFF, no extra glyph will be added. Note that
|
||||
* generally when a glyph is added, justification
|
||||
* will need to be redone. */
|
||||
GlyphID substGlyph; /* Glyph to be substituted for this glyph if the
|
||||
HBGlyphID substGlyph; /* Glyph to be substituted for this glyph if the
|
||||
* growth factor equals or exceeds the value of
|
||||
* substThreshold. */
|
||||
public:
|
||||
|
@ -143,16 +143,16 @@ struct DuctileGlyphAction
|
|||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
|
||||
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
|
||||
* This would normally be 0x64756374 ('duct'),
|
||||
* but you may use any axis the font contains. */
|
||||
Fixed minimumLimit; /* The lowest value for the ductility axis tha
|
||||
HBFixed minimumLimit; /* The lowest value for the ductility axis tha
|
||||
* still yields an acceptable appearance. Normally
|
||||
* this will be 1.0. */
|
||||
Fixed noStretchValue; /* This is the default value that corresponds to
|
||||
HBFixed noStretchValue; /* This is the default value that corresponds to
|
||||
* no change in appearance. Normally, this will
|
||||
* be 1.0. */
|
||||
Fixed maximumLimit; /* The highest value for the ductility axis that
|
||||
HBFixed maximumLimit; /* The highest value for the ductility axis that
|
||||
* still yields an acceptable appearance. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (22);
|
||||
|
@ -169,8 +169,8 @@ struct RepeatedAddGlyphAction
|
|||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBUINT16 flags; /* Currently unused; set to 0. */
|
||||
GlyphID glyph; /* Glyph that should be added if the distance factor
|
||||
HBUINT16 flags; /* Currently unused; set to 0. */
|
||||
HBGlyphID glyph; /* Glyph that should be added if the distance factor
|
||||
* is growing. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (10);
|
||||
|
@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
|
|||
};
|
||||
|
||||
protected:
|
||||
Fixed beforeGrowLimit;/* The ratio by which the advance width of the
|
||||
HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
|
||||
* glyph is permitted to grow on the left or top side. */
|
||||
Fixed beforeShrinkLimit;
|
||||
HBFixed beforeShrinkLimit;
|
||||
/* The ratio by which the advance width of the
|
||||
* glyph is permitted to shrink on the left or top side. */
|
||||
Fixed afterGrowLimit; /* The ratio by which the advance width of the glyph
|
||||
HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
|
||||
* is permitted to shrink on the left or top side. */
|
||||
Fixed afterShrinkLimit;
|
||||
HBFixed afterShrinkLimit;
|
||||
/* The ratio by which the advance width of the glyph
|
||||
* is at most permitted to shrink on the right or
|
||||
* bottom side. */
|
||||
|
@ -309,7 +309,7 @@ struct WidthDeltaPair
|
|||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
};
|
||||
|
||||
|
||||
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
|
||||
|
||||
struct JustificationCategory
|
||||
|
@ -361,7 +361,7 @@ struct JustificationHeader
|
|||
OffsetTo<JustificationCategory>
|
||||
justClassTable; /* Offset to the justification category state table. */
|
||||
OffsetTo<WidthDeltaCluster>
|
||||
wdcTable; /* Offset from start of justification table to start
|
||||
wdcTable; /* Offset from start of justification table to start
|
||||
* of the subtable containing the width delta factors
|
||||
* for the glyphs in your font.
|
||||
*
|
||||
|
@ -371,8 +371,8 @@ struct JustificationHeader
|
|||
* 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
|
||||
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. */
|
||||
|
||||
|
@ -397,7 +397,7 @@ struct just
|
|||
protected:
|
||||
FixedVersion<>version; /* Version of the justification table
|
||||
* (0x00010000u for version 1.0). */
|
||||
HBUINT16 format; /* Format of the justification table (set to 0). */
|
||||
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
|
||||
|
|
|
@ -82,8 +82,8 @@ struct KernPair
|
|||
}
|
||||
|
||||
protected:
|
||||
GlyphID left;
|
||||
GlyphID right;
|
||||
HBGlyphID left;
|
||||
HBGlyphID right;
|
||||
FWORD value;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (6);
|
||||
|
@ -251,7 +251,7 @@ struct KerxSubTableFormat1
|
|||
|
||||
if (Format1EntryT::performAction (entry) && depth)
|
||||
{
|
||||
unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
|
||||
unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
|
||||
|
||||
unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
|
||||
kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
|
||||
|
@ -392,7 +392,7 @@ struct KerxSubTableFormat2
|
|||
|
||||
const UnsizedArrayOf<FWORD> &arrayZ = this+array;
|
||||
unsigned int kern_idx = l + r;
|
||||
kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ);
|
||||
kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
|
||||
const FWORD *v = &arrayZ[kern_idx];
|
||||
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
|
||||
|
||||
|
@ -712,18 +712,18 @@ struct KerxSubTableFormat6
|
|||
{
|
||||
struct Long
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT32> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
|
||||
} l;
|
||||
struct Short
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT16> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
|
||||
} s;
|
||||
} u;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > vector;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
|
||||
};
|
||||
|
@ -733,8 +733,8 @@ struct KerxSubTableHeader
|
|||
{
|
||||
typedef ExtendedTypes Types;
|
||||
|
||||
unsigned int tuple_count () const { return tupleCount; }
|
||||
bool is_horizontal () const { return !(coverage & Vertical); }
|
||||
unsigned tuple_count () const { return tupleCount; }
|
||||
bool is_horizontal () const { return !(coverage & Vertical); }
|
||||
|
||||
enum Coverage
|
||||
{
|
||||
|
@ -771,17 +771,17 @@ struct KerxSubTable
|
|||
unsigned int get_size () const { return u.header.length; }
|
||||
unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.format0));
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 4: return_trace (c->dispatch (u.format4));
|
||||
case 6: return_trace (c->dispatch (u.format6));
|
||||
case 0: return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 4: return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
|
||||
case 6: return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
@ -830,7 +830,7 @@ struct KerxTable
|
|||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (st->get_type () == 1)
|
||||
return true;
|
||||
return true;
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
}
|
||||
return false;
|
||||
|
@ -845,7 +845,7 @@ struct KerxTable
|
|||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (st->u.header.coverage & st->u.header.CrossStream)
|
||||
return true;
|
||||
return true;
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
}
|
||||
return false;
|
||||
|
@ -862,7 +862,7 @@ struct KerxTable
|
|||
{
|
||||
if ((st->u.header.coverage & (st->u.header.Variation | st->u.header.CrossStream)) ||
|
||||
!st->u.header.is_horizontal ())
|
||||
continue;
|
||||
continue;
|
||||
v += st->get_kerning (left, right);
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
}
|
||||
|
@ -883,7 +883,7 @@ struct KerxTable
|
|||
bool reverse;
|
||||
|
||||
if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
|
||||
goto skip;
|
||||
goto skip;
|
||||
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
|
||||
goto skip;
|
||||
|
@ -897,8 +897,8 @@ struct KerxTable
|
|||
if (!seenCrossStream &&
|
||||
(st->u.header.coverage & st->u.header.CrossStream))
|
||||
{
|
||||
/* Attach all glyphs into a chain. */
|
||||
seenCrossStream = true;
|
||||
/* Attach all glyphs into a chain. */
|
||||
seenCrossStream = true;
|
||||
hb_glyph_position_t *pos = c->buffer->pos;
|
||||
unsigned int count = c->buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
|
|
|
@ -38,6 +38,80 @@ namespace AAT {
|
|||
|
||||
typedef ArrayOf<HBINT16> LigCaretClassEntry;
|
||||
|
||||
struct lcarFormat0
|
||||
{
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */,
|
||||
const void *base) const
|
||||
{
|
||||
const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
|
||||
font->face->get_num_glyphs ());
|
||||
const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
|
||||
for (unsigned int i = 0; i < arr.length; ++i)
|
||||
caret_array[i] = font->em_scale_dir (arr[i], direction);
|
||||
}
|
||||
return array.len;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<LigCaretClassEntry>>
|
||||
lookupTable; /* data Lookup table associating glyphs */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct lcarFormat1
|
||||
{
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */,
|
||||
const void *base) const
|
||||
{
|
||||
const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
|
||||
font->face->get_num_glyphs ());
|
||||
const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
|
||||
for (unsigned int i = 0; i < arr.length; ++i)
|
||||
{
|
||||
hb_position_t x = 0, y = 0;
|
||||
font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
|
||||
caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
|
||||
}
|
||||
}
|
||||
return array.len;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<LigCaretClassEntry>>
|
||||
lookupTable; /* data Lookup table associating glyphs */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct lcar
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
|
||||
|
@ -49,41 +123,36 @@ struct lcar
|
|||
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)
|
||||
switch (format)
|
||||
{
|
||||
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;
|
||||
}
|
||||
case 0: return u.format0.get_lig_carets (font, direction, glyph, start_offset,
|
||||
caret_count, caret_array, this);
|
||||
case 1: return u.format1.get_lig_carets (font, direction, glyph, start_offset,
|
||||
caret_count, caret_array, this);
|
||||
default:if (caret_count) *caret_count = 0; return 0;
|
||||
}
|
||||
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)));
|
||||
if (unlikely (!c->check_struct (this) || version.major != 1))
|
||||
return_trace (false);
|
||||
|
||||
switch (format) {
|
||||
case 0: return_trace (u.format0.sanitize (c, this));
|
||||
case 1: return_trace (u.format1.sanitize (c, this));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the ligature caret table */
|
||||
HBUINT16 format; /* Format of the ligature caret table. */
|
||||
Lookup<OffsetTo<LigCaretClassEntry> >
|
||||
lookup; /* data Lookup table associating glyphs */
|
||||
|
||||
union {
|
||||
lcarFormat0 format0;
|
||||
lcarFormat0 format1;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
|
|
@ -88,7 +88,7 @@ struct RearrangementSubtable
|
|||
start = buffer->idx;
|
||||
|
||||
if (flags & MarkLast)
|
||||
end = MIN (buffer->idx + 1, buffer->len);
|
||||
end = hb_min (buffer->idx + 1, buffer->len);
|
||||
|
||||
if ((flags & Verb) && start < end)
|
||||
{
|
||||
|
@ -117,14 +117,14 @@ struct RearrangementSubtable
|
|||
};
|
||||
|
||||
unsigned int m = map[flags & Verb];
|
||||
unsigned int l = MIN<unsigned int> (2, m >> 4);
|
||||
unsigned int r = MIN<unsigned int> (2, m & 0x0F);
|
||||
unsigned int l = hb_min (2u, m >> 4);
|
||||
unsigned int r = hb_min (2u, m & 0x0F);
|
||||
bool reverse_l = 3 == (m >> 4);
|
||||
bool reverse_r = 3 == (m & 0x0F);
|
||||
|
||||
if (end - start >= l + r)
|
||||
{
|
||||
buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, end);
|
||||
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
@ -226,7 +226,7 @@ struct ContextualSubtable
|
|||
hb_buffer_t *buffer = driver->buffer;
|
||||
|
||||
if (buffer->idx == buffer->len && !mark_set)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
|
||||
}
|
||||
|
@ -238,48 +238,48 @@ struct ContextualSubtable
|
|||
/* Looks like CoreText applies neither mark nor current substitution for
|
||||
* end-of-text if mark was not explicitly set. */
|
||||
if (buffer->idx == buffer->len && !mark_set)
|
||||
return;
|
||||
return;
|
||||
|
||||
const GlyphID *replacement;
|
||||
const HBGlyphID *replacement;
|
||||
|
||||
replacement = nullptr;
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry.data.markIndex != 0xFFFF)
|
||||
{
|
||||
const Lookup<GlyphID> &lookup = subs[entry.data.markIndex];
|
||||
const Lookup<HBGlyphID> &lookup = subs[entry.data.markIndex];
|
||||
replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
|
||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||
const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
|
||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||
replacement = nullptr;
|
||||
}
|
||||
if (replacement)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->info[mark].codepoint = *replacement;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
replacement = nullptr;
|
||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||
unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry.data.currentIndex != 0xFFFF)
|
||||
{
|
||||
const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex];
|
||||
const Lookup<HBGlyphID> &lookup = subs[entry.data.currentIndex];
|
||||
replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
|
||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||
const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
|
||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||
replacement = nullptr;
|
||||
|
@ -304,7 +304,7 @@ struct ContextualSubtable
|
|||
bool mark_set;
|
||||
unsigned int mark;
|
||||
const ContextualSubtable *table;
|
||||
const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
|
||||
const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
|
||||
};
|
||||
|
||||
bool apply (hb_aat_apply_context_t *c) const
|
||||
|
@ -337,9 +337,9 @@ struct ContextualSubtable
|
|||
const EntryData &data = entries[i].data;
|
||||
|
||||
if (data.markIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.markIndex);
|
||||
if (data.currentIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
|
||||
}
|
||||
|
||||
return_trace (substitutionTables.sanitize (c, this, num_lookups));
|
||||
|
@ -348,7 +348,7 @@ struct ContextualSubtable
|
|||
protected:
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
NNOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT>
|
||||
NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
|
||||
substitutionTables;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (20);
|
||||
|
@ -488,7 +488,7 @@ struct LigatureSubtable
|
|||
|
||||
unsigned int ligature_idx = 0;
|
||||
unsigned int action;
|
||||
do
|
||||
do
|
||||
{
|
||||
if (unlikely (!cursor))
|
||||
{
|
||||
|
@ -520,7 +520,7 @@ struct LigatureSubtable
|
|||
if (action & (LigActionStore | LigActionLast))
|
||||
{
|
||||
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
|
||||
const GlyphID &ligatureData = ligature[ligature_idx];
|
||||
const HBGlyphID &ligatureData = ligature[ligature_idx];
|
||||
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
|
||||
hb_codepoint_t lig = ligatureData;
|
||||
|
||||
|
@ -554,7 +554,7 @@ struct LigatureSubtable
|
|||
const LigatureSubtable *table;
|
||||
const UnsizedArrayOf<HBUINT32> &ligAction;
|
||||
const UnsizedArrayOf<HBUINT16> &component;
|
||||
const UnsizedArrayOf<GlyphID> &ligature;
|
||||
const UnsizedArrayOf<HBGlyphID> &ligature;
|
||||
unsigned int match_length;
|
||||
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
||||
};
|
||||
|
@ -586,7 +586,7 @@ struct LigatureSubtable
|
|||
ligAction; /* Offset to the ligature action table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
|
||||
component; /* Offset to the component table. */
|
||||
NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
|
||||
ligature; /* Offset to the actual ligature lists. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (28);
|
||||
|
@ -606,7 +606,7 @@ struct NoncontextualSubtable
|
|||
unsigned int count = c->buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
|
||||
const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
|
||||
if (replacement)
|
||||
{
|
||||
info[i].codepoint = *replacement;
|
||||
|
@ -624,7 +624,7 @@ struct NoncontextualSubtable
|
|||
}
|
||||
|
||||
protected:
|
||||
Lookup<GlyphID> substitute;
|
||||
Lookup<HBGlyphID> substitute;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
@ -726,7 +726,7 @@ struct InsertionSubtable
|
|||
{
|
||||
unsigned int count = (flags & MarkedInsertCount);
|
||||
unsigned int start = entry.data.markedInsertIndex;
|
||||
const GlyphID *glyphs = &insertionAction[start];
|
||||
const HBGlyphID *glyphs = &insertionAction[start];
|
||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
|
||||
|
||||
bool before = flags & MarkedInsertBefore;
|
||||
|
@ -744,7 +744,7 @@ struct InsertionSubtable
|
|||
|
||||
buffer->move_to (end + count);
|
||||
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
}
|
||||
|
||||
if (flags & SetMark)
|
||||
|
@ -754,7 +754,7 @@ struct InsertionSubtable
|
|||
{
|
||||
unsigned int count = (flags & CurrentInsertCount) >> 5;
|
||||
unsigned int start = entry.data.currentInsertIndex;
|
||||
const GlyphID *glyphs = &insertionAction[start];
|
||||
const HBGlyphID *glyphs = &insertionAction[start];
|
||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
|
||||
|
||||
bool before = flags & CurrentInsertBefore;
|
||||
|
@ -793,7 +793,7 @@ struct InsertionSubtable
|
|||
private:
|
||||
hb_aat_apply_context_t *c;
|
||||
unsigned int mark;
|
||||
const UnsizedArrayOf<GlyphID> &insertionAction;
|
||||
const UnsizedArrayOf<HBGlyphID> &insertionAction;
|
||||
};
|
||||
|
||||
bool apply (hb_aat_apply_context_t *c) const
|
||||
|
@ -819,7 +819,7 @@ struct InsertionSubtable
|
|||
protected:
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
|
||||
insertionAction; /* Byte offset from stateHeader to the start of
|
||||
* the insertion glyph table. */
|
||||
public:
|
||||
|
@ -883,17 +883,17 @@ struct ChainSubtable
|
|||
Insertion = 5
|
||||
};
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion));
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
@ -948,8 +948,10 @@ struct Chain
|
|||
hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
|
||||
hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
|
||||
retry:
|
||||
const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
|
||||
if (info && info->setting == setting)
|
||||
// Check whether this type/setting pair was requested in the map, and if so, apply its flags.
|
||||
// (The search here only looks at the type and setting fields of feature_info_t.)
|
||||
hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
|
||||
if (map->features.bsearch (info))
|
||||
{
|
||||
flags &= feature.disableFlags;
|
||||
flags |= feature.enableFlags;
|
||||
|
@ -969,19 +971,19 @@ struct Chain
|
|||
void apply (hb_aat_apply_context_t *c,
|
||||
hb_mask_t flags) const
|
||||
{
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
bool reverse;
|
||||
|
||||
if (!(subtable->subFeatureFlags & flags))
|
||||
goto skip;
|
||||
goto skip;
|
||||
|
||||
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
|
||||
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
|
||||
bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
|
||||
goto skip;
|
||||
goto skip;
|
||||
|
||||
/* Buffer contents is always in logical direction. Determine if
|
||||
* we need to reverse before applying this subtable. We reverse
|
||||
|
@ -1016,22 +1018,22 @@ struct Chain
|
|||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||
|
||||
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
|
||||
goto skip;
|
||||
goto skip;
|
||||
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
c->buffer->reverse ();
|
||||
|
||||
subtable->apply (c);
|
||||
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
c->buffer->reverse ();
|
||||
|
||||
(void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
|
||||
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
|
||||
skip:
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
c->set_lookup_index (c->lookup_index + 1);
|
||||
}
|
||||
}
|
||||
|
@ -1049,13 +1051,13 @@ struct Chain
|
|||
if (!c->check_array (featureZ.arrayZ, featureCount))
|
||||
return_trace (false);
|
||||
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (!subtable->sanitize (c))
|
||||
return_trace (false);
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -1080,10 +1082,10 @@ struct Chain
|
|||
* The 'mort'/'morx' Table
|
||||
*/
|
||||
|
||||
template <typename Types>
|
||||
template <typename Types, hb_tag_t TAG>
|
||||
struct mortmorx
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
|
||||
static constexpr hb_tag_t tableTag = TAG;
|
||||
|
||||
bool has_data () const { return version != 0; }
|
||||
|
||||
|
@ -1095,7 +1097,7 @@ struct mortmorx
|
|||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
map->chain_flags.push (chain->compile_flags (mapper));
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1109,7 +1111,7 @@ struct mortmorx
|
|||
{
|
||||
chain->apply (c, c->plan->aat_map.chain_flags[i]);
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1125,7 +1127,7 @@ struct mortmorx
|
|||
{
|
||||
if (!chain->sanitize (c, version))
|
||||
return_trace (false);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -1143,14 +1145,8 @@ struct mortmorx
|
|||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
struct morx : mortmorx<ExtendedTypes>
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
|
||||
};
|
||||
struct mort : mortmorx<ObsoleteTypes>
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
|
||||
};
|
||||
struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
|
||||
struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
|
||||
|
||||
|
||||
} /* namespace AAT */
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_OPBD_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* opbd -- Optical Bounds
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
|
||||
*/
|
||||
#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
struct OpticalBounds
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
FWORD leftSide;
|
||||
FWORD topSide;
|
||||
FWORD rightSide;
|
||||
FWORD bottomSide;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct opbdFormat0
|
||||
{
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents, const void *base) const
|
||||
{
|
||||
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
|
||||
if (!bounds_offset) return false;
|
||||
const OpticalBounds &bounds = base+*bounds_offset;
|
||||
|
||||
if (extents)
|
||||
*extents = {
|
||||
font->em_scale_x (bounds.leftSide),
|
||||
font->em_scale_y (bounds.topSide),
|
||||
font->em_scale_x (bounds.rightSide),
|
||||
font->em_scale_y (bounds.bottomSide)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<OpticalBounds>>
|
||||
lookupTable; /* Lookup table associating glyphs with the four
|
||||
* int16 values for the left-side, top-side,
|
||||
* right-side, and bottom-side optical bounds. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct opbdFormat1
|
||||
{
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents, const void *base) const
|
||||
{
|
||||
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
|
||||
if (!bounds_offset) return false;
|
||||
const OpticalBounds &bounds = base+*bounds_offset;
|
||||
|
||||
hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
|
||||
if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
|
||||
{
|
||||
if (extents)
|
||||
*extents = {left, top, right, bottom};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<OpticalBounds>>
|
||||
lookupTable; /* Lookup table associating glyphs with the four
|
||||
* int16 values for the left-side, top-side,
|
||||
* right-side, and bottom-side optical bounds. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct opbd
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
|
||||
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
|
||||
case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this) || version.major != 1))
|
||||
return_trace (false);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (u.format0.sanitize (c, this));
|
||||
case 1: return_trace (u.format1.sanitize (c, this));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the optical bounds
|
||||
* table (0x00010000 for the current version). */
|
||||
HBUINT16 format; /* Format of the optical bounds table.
|
||||
* Format 0 indicates distance and Format 1 indicates
|
||||
* control point. */
|
||||
union {
|
||||
opbdFormat0 format0;
|
||||
opbdFormat1 format1;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */
|
|
@ -62,11 +62,11 @@ struct TrackTableEntry
|
|||
}
|
||||
|
||||
protected:
|
||||
Fixed track; /* Track value for this record. */
|
||||
HBFixed track; /* Track value for this record. */
|
||||
NameID trackNameID; /* The 'name' table index for this track.
|
||||
* (a short word or phrase like "loose"
|
||||
* or "very tight") */
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD> >
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD>>
|
||||
valuesZ; /* Offset from start of tracking table to
|
||||
* per-size tracking values for this track. */
|
||||
|
||||
|
@ -82,7 +82,7 @@ struct TrackData
|
|||
const void *base) const
|
||||
{
|
||||
unsigned int sizes = nSizes;
|
||||
hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
|
||||
float s0 = size_table[idx].to_float ();
|
||||
float s1 = size_table[idx + 1].to_float ();
|
||||
|
@ -93,13 +93,6 @@ struct TrackData
|
|||
|
||||
int get_tracking (const void *base, float ptem) const
|
||||
{
|
||||
/* CoreText points are CSS pixels (96 per inch),
|
||||
* NOT typographic points (72 per inch).
|
||||
*
|
||||
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
|
||||
*/
|
||||
float csspx = ptem * 96.f / 72.f;
|
||||
|
||||
/*
|
||||
* Choose track.
|
||||
*/
|
||||
|
@ -127,14 +120,14 @@ struct TrackData
|
|||
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);
|
||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
unsigned int size_index;
|
||||
for (size_index = 0; size_index < sizes - 1; size_index++)
|
||||
if (size_table[size_index].to_float () >= csspx)
|
||||
break;
|
||||
if (size_table[size_index].to_float () >= ptem)
|
||||
break;
|
||||
|
||||
return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||
*trackTableEntry, base));
|
||||
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
|
||||
*trackTableEntry, base));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
@ -148,7 +141,7 @@ struct TrackData
|
|||
protected:
|
||||
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
|
||||
HBUINT16 nSizes; /* Number of point sizes included in this table. */
|
||||
LOffsetTo<UnsizedArrayOf<Fixed>, false>
|
||||
LNNOffsetTo<UnsizedArrayOf<HBFixed>>
|
||||
sizeTable; /* Offset from start of the tracking table to
|
||||
* Array[nSizes] of size values.. */
|
||||
UnsizedArrayOf<TrackTableEntry>
|
||||
|
@ -183,7 +176,7 @@ struct trak
|
|||
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
{
|
||||
if (!(buffer->info[start].mask & trak_mask)) continue;
|
||||
if (!(buffer->info[start].mask & trak_mask)) continue;
|
||||
buffer->pos[start].x_advance += advance_to_add;
|
||||
buffer->pos[start].x_offset += offset_to_add;
|
||||
}
|
||||
|
@ -196,7 +189,7 @@ struct trak
|
|||
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
{
|
||||
if (!(buffer->info[start].mask & trak_mask)) continue;
|
||||
if (!(buffer->info[start].mask & trak_mask)) continue;
|
||||
buffer->pos[start].y_advance += advance_to_add;
|
||||
buffer->pos[start].y_offset += offset_to_add;
|
||||
}
|
||||
|
@ -217,8 +210,8 @@ struct trak
|
|||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version of the tracking table
|
||||
* (0x00010000u for version 1.0). */
|
||||
HBUINT16 format; /* Format of the tracking table (set to 0). */
|
||||
* (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). */
|
||||
|
|
|
@ -25,9 +25,8 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#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"
|
||||
|
@ -40,6 +39,42 @@
|
|||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_apply_context_t
|
||||
*/
|
||||
|
||||
/* Note: This context is used for kerning, even without AAT, hence the condition. */
|
||||
#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
|
||||
|
||||
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)
|
||||
{
|
||||
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_; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-aat-layout
|
||||
* @title: hb-aat-layout
|
||||
|
@ -50,6 +85,8 @@
|
|||
**/
|
||||
|
||||
|
||||
#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
|
||||
|
||||
/* Table data courtesy of Apple. Converted from mnemonics to integers
|
||||
* when moving to this file. */
|
||||
static const hb_aat_feature_mapping_t feature_mappings[] =
|
||||
|
@ -135,44 +172,12 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
|
|||
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);
|
||||
return hb_sorted_array (feature_mappings).bsearch (tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_apply_context_t
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
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_; }
|
||||
|
||||
#ifndef HB_NO_AAT
|
||||
|
||||
/*
|
||||
* mort/morx/kerx/trak
|
||||
|
@ -311,14 +316,6 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
|||
trak.apply (&c);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
@ -382,3 +379,6 @@ hb_aat_layout_feature_type_get_selector_infos (hb_face_t
|
|||
{
|
||||
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -85,7 +85,7 @@ typedef enum
|
|||
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_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
} hb_aat_layout_feature_type_t;
|
||||
|
||||
/**
|
||||
|
@ -424,7 +424,7 @@ typedef enum
|
|||
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_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
} hb_aat_layout_feature_selector_t;
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "hb.hh"
|
||||
|
||||
#include "hb-ot-shape.hh"
|
||||
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
struct hb_aat_feature_mapping_t
|
||||
{
|
||||
|
@ -39,14 +39,8 @@ struct hb_aat_feature_mapping_t
|
|||
hb_aat_layout_feature_selector_t selectorToEnable;
|
||||
hb_aat_layout_feature_selector_t selectorToDisable;
|
||||
|
||||
HB_INTERNAL static int cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
hb_tag_t key = * (unsigned int *) key_;
|
||||
const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
|
||||
return key < entry->otFeatureTag ? -1 :
|
||||
key > entry->otFeatureTag ? 1 :
|
||||
0;
|
||||
}
|
||||
int cmp (hb_tag_t key) const
|
||||
{ return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; }
|
||||
};
|
||||
|
||||
HB_INTERNAL const hb_aat_feature_mapping_t *
|
||||
|
@ -77,9 +71,5 @@ 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 */
|
||||
|
|
|
@ -50,7 +50,7 @@ struct FTStringRange
|
|||
}
|
||||
|
||||
protected:
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
tag; /* Offset from the start of the table to
|
||||
* the beginning of the string */
|
||||
HBUINT16 length; /* String length (in bytes) */
|
||||
|
|
|
@ -26,28 +26,55 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
|
||||
#include "hb-aat-map.hh"
|
||||
|
||||
#include "hb-aat-layout.hh"
|
||||
#include "hb-aat-layout-feat-table.hh"
|
||||
|
||||
|
||||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
||||
unsigned int value)
|
||||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
|
||||
{
|
||||
if (!face->table.feat->has_data ()) return;
|
||||
|
||||
if (tag == HB_TAG ('a','a','l','t'))
|
||||
{
|
||||
if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
|
||||
return;
|
||||
feature_info_t *info = features.push();
|
||||
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
|
||||
info->setting = (hb_aat_layout_feature_selector_t) value;
|
||||
info->seq = features.length;
|
||||
info->is_exclusive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
|
||||
if (!mapping) return;
|
||||
|
||||
const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
|
||||
if (!feature->has_data ())
|
||||
{
|
||||
/* Special case: Chain::compile_flags will fall back to the deprecated version of
|
||||
* small-caps if necessary, so we need to check for that possibility.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/2307 */
|
||||
if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
|
||||
mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
|
||||
{
|
||||
feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
|
||||
if (!feature->has_data ()) return;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
feature_info_t *info = features.push();
|
||||
info->type = mapping->aatFeatureType;
|
||||
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
|
||||
info->seq = features.length;
|
||||
info->is_exclusive = feature->is_exclusive ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -59,10 +86,17 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
|
|||
features.qsort ();
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 1; i < features.length; i++)
|
||||
if (features[i].type != features[j].type)
|
||||
if (features[i].type != features[j].type ||
|
||||
/* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
|
||||
* respectively, so we mask out the low-order bit when checking for "duplicates"
|
||||
* (selectors referring to the same feature setting) here. */
|
||||
(!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
|
||||
features[++j] = features[i];
|
||||
features.shrink (j + 1);
|
||||
}
|
||||
|
||||
hb_aat_layout_compile_map (this, &m);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -64,19 +64,24 @@ struct hb_aat_map_builder_t
|
|||
{
|
||||
hb_aat_layout_feature_type_t type;
|
||||
hb_aat_layout_feature_selector_t setting;
|
||||
bool is_exclusive;
|
||||
unsigned seq; /* For stable sorting only. */
|
||||
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
const feature_info_t *a = (const feature_info_t *) pa;
|
||||
const feature_info_t *b = (const feature_info_t *) pb;
|
||||
return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
|
||||
(a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
|
||||
if (a->type != b->type) return (a->type < b->type ? -1 : 1);
|
||||
if (!a->is_exclusive &&
|
||||
(a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1);
|
||||
return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
|
||||
}
|
||||
|
||||
int cmp (hb_aat_layout_feature_type_t ty) const
|
||||
/* compares type & setting only, not is_exclusive flag or seq number */
|
||||
int cmp (const feature_info_t& f) const
|
||||
{
|
||||
return (type != ty) ? (type < ty ? -1 : 1) : 0;
|
||||
return (f.type != type) ? (f.type < type ? -1 : 1) :
|
||||
(f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
852
src/hb-algs.hh
852
src/hb-algs.hh
File diff suppressed because it is too large
Load Diff
231
src/hb-array.hh
231
src/hb-array.hh
|
@ -42,19 +42,21 @@ 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 () : arrayZ (nullptr), length (0), backwards_length (0) {}
|
||||
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
template <unsigned int length_>
|
||||
hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
|
||||
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,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_with_fallback_t<hb_array_t, Type&> (),
|
||||
arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -70,15 +72,25 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
|||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
backwards_length += n;
|
||||
arrayZ += n;
|
||||
}
|
||||
void __rewind__ (unsigned n)
|
||||
{
|
||||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
if (unlikely (n > backwards_length))
|
||||
n = backwards_length;
|
||||
length += n;
|
||||
backwards_length -= n;
|
||||
arrayZ -= n;
|
||||
}
|
||||
unsigned __len__ () const { return length; }
|
||||
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
|
||||
* it's best if we can just compare arrayZ, though comparing contents is still fast,
|
||||
* but also would require that Type has operator==. As such, we optimize this operator
|
||||
* for range-based for loop and just compare arrayZ. No need to compare length, as we
|
||||
* assume we're only compared to .end(). */
|
||||
bool operator != (const hb_array_t& o) const
|
||||
{ return arrayZ != o.arrayZ; }
|
||||
|
||||
/* Extra operators.
|
||||
*/
|
||||
|
@ -87,14 +99,21 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
|||
template <typename T> operator T * () const { return arrayZ; }
|
||||
|
||||
HB_INTERNAL bool operator == (const hb_array_t &o) const;
|
||||
HB_INTERNAL uint32_t hash () const;
|
||||
|
||||
uint32_t hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++) {
|
||||
current = current * 31 + hb_hash (this->arrayZ[i]);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare, Sort, and Search.
|
||||
*/
|
||||
|
||||
/* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
|
||||
int cmp (const hb_array_t<Type> &a) const
|
||||
int cmp (const hb_array_t &a) const
|
||||
{
|
||||
if (length != a.length)
|
||||
return (int) a.length - (int) length;
|
||||
|
@ -102,8 +121,8 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
|||
}
|
||||
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;
|
||||
hb_array_t *a = (hb_array_t *) pa;
|
||||
hb_array_t *b = (hb_array_t *) pb;
|
||||
return b->cmp (*a);
|
||||
}
|
||||
|
||||
|
@ -129,30 +148,48 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
|||
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
|
||||
{
|
||||
if (likely (length))
|
||||
::qsort (arrayZ, length, this->item_size, cmp_);
|
||||
hb_qsort (arrayZ, length, this->get_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);
|
||||
hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
|
||||
return hb_sorted_array_t<Type> (*this);
|
||||
}
|
||||
void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
end = MIN (end, length);
|
||||
end = hb_min (end, length);
|
||||
assert (start <= end);
|
||||
if (likely (start < end))
|
||||
::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
|
||||
hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Other methods.
|
||||
*/
|
||||
|
||||
unsigned int get_size () const { return length * this->item_size; }
|
||||
unsigned int get_size () const { return length * this->get_item_size (); }
|
||||
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
|
||||
/*
|
||||
* Reverse the order of items in this array in the range [start, end).
|
||||
*/
|
||||
void reverse (unsigned start = 0, unsigned end = -1)
|
||||
{
|
||||
start = hb_min (start, length);
|
||||
end = hb_min (end, length);
|
||||
|
||||
if (end < start + 2)
|
||||
return;
|
||||
|
||||
for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
|
||||
Type temp = arrayZ[rhs];
|
||||
arrayZ[rhs] = arrayZ[lhs];
|
||||
arrayZ[lhs] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
|
||||
{
|
||||
if (!start_offset && !seg_count)
|
||||
return *this;
|
||||
|
@ -163,16 +200,45 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
|||
else
|
||||
count -= start_offset;
|
||||
if (seg_count)
|
||||
count = *seg_count = MIN (count, *seg_count);
|
||||
return hb_array_t<Type> (arrayZ + start_offset, count);
|
||||
count = *seg_count = hb_min (count, *seg_count);
|
||||
return hb_array_t (arrayZ + start_offset, count);
|
||||
}
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{ return sub_array (start_offset, &seg_count); }
|
||||
|
||||
hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
|
||||
|
||||
template <typename T,
|
||||
unsigned P = sizeof (Type),
|
||||
hb_enable_if (P == 1)>
|
||||
const T *as () const
|
||||
{ return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
|
||||
|
||||
template <typename T,
|
||||
unsigned P = sizeof (Type),
|
||||
hb_enable_if (P == 1)>
|
||||
bool check_range (const T *p, unsigned int size = T::static_size) const
|
||||
{
|
||||
return arrayZ <= ((const char *) p)
|
||||
&& ((const char *) p) <= arrayZ + length
|
||||
&& (unsigned int) (arrayZ + length - (const char *) p) >= size;
|
||||
}
|
||||
|
||||
/* Only call if you allocated the underlying array using malloc() or similar. */
|
||||
void free ()
|
||||
{ ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
|
||||
|
||||
template <typename hb_serialize_context_t>
|
||||
hb_array_t copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto* out = c->start_embed (arrayZ);
|
||||
if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
|
||||
return_trace (hb_array_t (out, length));
|
||||
}
|
||||
|
||||
template <typename hb_sanitize_context_t>
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return c->check_array (arrayZ, length); }
|
||||
|
@ -184,6 +250,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
|||
public:
|
||||
Type *arrayZ;
|
||||
unsigned int length;
|
||||
unsigned int backwards_length;
|
||||
};
|
||||
template <typename T> inline hb_array_t<T>
|
||||
hb_array (T *array, unsigned int length)
|
||||
|
@ -204,23 +271,37 @@ 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;
|
||||
typedef hb_iter_t<hb_sorted_array_t, 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_) {}
|
||||
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
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_t<hb_sorted_array_t, Type&> (),
|
||||
hb_array_t<Type> (o) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ hb_array_t<Type> (*this) = o; return *this; }
|
||||
|
||||
/* Iterator implementation. */
|
||||
bool operator != (const hb_sorted_array_t& o) const
|
||||
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
|
||||
|
||||
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
|
||||
{ return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
|
||||
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{ return sub_array (start_offset, &seg_count); }
|
||||
|
||||
hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
|
||||
|
||||
template <typename T>
|
||||
Type *bsearch (const T &x, Type *not_found = nullptr)
|
||||
{
|
||||
|
@ -235,26 +316,18 @@ struct hb_sorted_array_t :
|
|||
}
|
||||
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
|
||||
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
{
|
||||
int min = 0, max = (int) this->length - 1;
|
||||
const Type *array = this->arrayZ;
|
||||
while (min <= max)
|
||||
unsigned pos;
|
||||
|
||||
if (bsearch_impl (x, &pos))
|
||||
{
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
int c = array[mid].cmp (x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
if (i)
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
if (i)
|
||||
*i = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
switch (not_found)
|
||||
|
@ -267,14 +340,22 @@ struct hb_sorted_array_t :
|
|||
break;
|
||||
|
||||
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
|
||||
if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
*i = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename T>
|
||||
bool bsearch_impl (const T &x, unsigned *pos) const
|
||||
{
|
||||
return hb_bsearch_impl (pos,
|
||||
x,
|
||||
this->arrayZ,
|
||||
this->length,
|
||||
sizeof (Type),
|
||||
_hb_cmp_method<T, Type>);
|
||||
}
|
||||
};
|
||||
template <typename T> inline hb_sorted_array_t<T>
|
||||
hb_sorted_array (T *array, unsigned int length)
|
||||
|
@ -286,27 +367,35 @@ hb_sorted_array (T (&array_)[length_])
|
|||
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
|
||||
;
|
||||
if (o.length != this->length) return false;
|
||||
for (unsigned int i = 0; i < this->length; i++) {
|
||||
if (this->arrayZ[i] != o.arrayZ[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <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)
|
||||
;
|
||||
|
||||
/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
|
||||
|
||||
template <>
|
||||
inline uint32_t hb_array_t<const char>::hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++)
|
||||
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
|
||||
return current;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t hb_array_t<const unsigned char>::hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++)
|
||||
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
typedef hb_array_t<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 */
|
||||
|
|
|
@ -107,7 +107,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
|||
|
||||
static inline void _hb_memory_barrier ()
|
||||
{
|
||||
#if !defined(MemoryBarrier)
|
||||
#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier. */
|
||||
LONG dummy = 0;
|
||||
InterlockedExchange (&dummy, 1);
|
||||
|
@ -212,25 +212,19 @@ static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
|
|||
static_assert ((sizeof (long) == sizeof (void *)), "");
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT)
|
||||
|
||||
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
#elif defined(HB_NO_MT)
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier() do {} while (0)
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#else /* HB_NO_MT */
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
#else
|
||||
|
||||
#error "Could not find any system to define atomic_int macros."
|
||||
#error "Check hb-atomic.hh for possible resolutions."
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -283,7 +277,7 @@ struct hb_atomic_int_t
|
|||
template <typename P>
|
||||
struct hb_atomic_ptr_t
|
||||
{
|
||||
typedef hb_remove_pointer (P) T;
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
void init (T* v_ = nullptr) { set_relaxed (v_); }
|
||||
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright © 2019 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
#ifndef HB_BIMAP_HH
|
||||
#define HB_BIMAP_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-map.hh"
|
||||
|
||||
/* Bi-directional map */
|
||||
struct hb_bimap_t
|
||||
{
|
||||
hb_bimap_t () { init (); }
|
||||
~hb_bimap_t () { fini (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
forw_map.init ();
|
||||
back_map.init ();
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
forw_map.fini ();
|
||||
back_map.fini ();
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
forw_map.reset ();
|
||||
back_map.reset ();
|
||||
}
|
||||
|
||||
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
|
||||
|
||||
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
|
||||
{
|
||||
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
|
||||
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
|
||||
forw_map.set (lhs, rhs);
|
||||
back_map.set (rhs, lhs);
|
||||
}
|
||||
|
||||
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
|
||||
hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
|
||||
|
||||
hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
|
||||
bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
|
||||
|
||||
void del (hb_codepoint_t lhs)
|
||||
{
|
||||
back_map.del (get (lhs));
|
||||
forw_map.del (lhs);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
forw_map.clear ();
|
||||
back_map.clear ();
|
||||
}
|
||||
|
||||
bool is_empty () const { return get_population () == 0; }
|
||||
|
||||
unsigned int get_population () const { return forw_map.get_population (); }
|
||||
|
||||
protected:
|
||||
hb_map_t forw_map;
|
||||
hb_map_t back_map;
|
||||
};
|
||||
|
||||
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
|
||||
struct hb_inc_bimap_t : hb_bimap_t
|
||||
{
|
||||
hb_inc_bimap_t () { init (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
hb_bimap_t::init ();
|
||||
next_value = 0;
|
||||
}
|
||||
|
||||
/* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
|
||||
* Return the rhs value as the result.
|
||||
*/
|
||||
hb_codepoint_t add (hb_codepoint_t lhs)
|
||||
{
|
||||
hb_codepoint_t rhs = forw_map[lhs];
|
||||
if (rhs == HB_MAP_VALUE_INVALID)
|
||||
{
|
||||
rhs = next_value++;
|
||||
set (lhs, rhs);
|
||||
}
|
||||
return rhs;
|
||||
}
|
||||
|
||||
hb_codepoint_t skip ()
|
||||
{ return next_value++; }
|
||||
|
||||
hb_codepoint_t get_next_value () const
|
||||
{ return next_value; }
|
||||
|
||||
void add_set (const hb_set_t *set)
|
||||
{
|
||||
hb_codepoint_t i = HB_SET_VALUE_INVALID;
|
||||
while (hb_set_next (set, &i)) add (i);
|
||||
}
|
||||
|
||||
/* Create an identity map. */
|
||||
bool identity (unsigned int size)
|
||||
{
|
||||
clear ();
|
||||
for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
|
||||
return !in_error ();
|
||||
}
|
||||
|
||||
protected:
|
||||
static int cmp_id (const void* a, const void* b)
|
||||
{ return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; }
|
||||
|
||||
public:
|
||||
/* Optional: after finished adding all mappings in a random order,
|
||||
* reassign rhs to lhs so that they are in the same order. */
|
||||
void sort ()
|
||||
{
|
||||
hb_codepoint_t count = get_population ();
|
||||
hb_vector_t <hb_codepoint_t> work;
|
||||
work.resize (count);
|
||||
|
||||
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
|
||||
work[rhs] = back_map[rhs];
|
||||
|
||||
work.qsort (cmp_id);
|
||||
|
||||
clear ();
|
||||
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
|
||||
set (work[rhs], rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int next_value;
|
||||
};
|
||||
|
||||
#endif /* HB_BIMAP_HH */
|
|
@ -25,18 +25,6 @@
|
|||
* Red Hat Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1308
|
||||
* http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
* https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
|
||||
*/
|
||||
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-blob.hh"
|
||||
|
||||
|
@ -48,7 +36,6 @@
|
|||
#endif /* HAVE_SYS_MMAN_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
@ -155,7 +142,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
|||
hb_blob_make_immutable (parent);
|
||||
|
||||
blob = hb_blob_create (parent->data + offset,
|
||||
MIN (length, parent->length - offset),
|
||||
hb_min (length, parent->length - offset),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
hb_blob_reference (parent),
|
||||
_hb_blob_destroy);
|
||||
|
@ -202,7 +189,7 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob)
|
|||
hb_blob_t *
|
||||
hb_blob_get_empty ()
|
||||
{
|
||||
return const_cast<hb_blob_t *> (&Null(hb_blob_t));
|
||||
return const_cast<hb_blob_t *> (&Null (hb_blob_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -487,6 +474,7 @@ hb_blob_t::try_make_writable ()
|
|||
* Mmap
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_OPEN
|
||||
#ifdef HAVE_MMAP
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
|
@ -579,7 +567,7 @@ fail_without_close:
|
|||
HANDLE fd;
|
||||
unsigned int size = strlen (file_name) + 1;
|
||||
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
|
||||
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
|
||||
if (unlikely (!wchar_file_name)) goto fail_without_close;
|
||||
mbstowcs (wchar_file_name, file_name, size);
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
{
|
||||
|
@ -591,7 +579,7 @@ fail_without_close:
|
|||
ceparams.lpSecurityAttributes = nullptr;
|
||||
ceparams.hTemplateFile = nullptr;
|
||||
fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ,
|
||||
OPEN_EXISTING, &ceparams);
|
||||
OPEN_EXISTING, &ceparams);
|
||||
}
|
||||
#else
|
||||
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
|
@ -613,14 +601,14 @@ fail_without_close:
|
|||
file->length = (unsigned long) GetFileSize (fd, nullptr);
|
||||
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
#endif
|
||||
if (unlikely (file->mapping == nullptr)) goto fail;
|
||||
if (unlikely (!file->mapping)) goto fail;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
|
||||
#else
|
||||
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
#endif
|
||||
if (unlikely (file->contents == nullptr)) goto fail;
|
||||
if (unlikely (!file->contents)) goto fail;
|
||||
|
||||
CloseHandle (fd);
|
||||
return hb_blob_create (file->contents, file->length,
|
||||
|
@ -638,10 +626,10 @@ fail_without_close:
|
|||
It's used as a fallback for systems without mmap or to read from pipes */
|
||||
unsigned long len = 0, allocated = BUFSIZ * 16;
|
||||
char *data = (char *) malloc (allocated);
|
||||
if (unlikely (data == nullptr)) return hb_blob_get_empty ();
|
||||
if (unlikely (!data)) return hb_blob_get_empty ();
|
||||
|
||||
FILE *fp = fopen (file_name, "rb");
|
||||
if (unlikely (fp == nullptr)) goto fread_fail_without_close;
|
||||
if (unlikely (!fp)) goto fread_fail_without_close;
|
||||
|
||||
while (!feof (fp))
|
||||
{
|
||||
|
@ -652,7 +640,7 @@ fail_without_close:
|
|||
can cover files like that but lets limit our fallback reader */
|
||||
if (unlikely (allocated > (2 << 28))) goto fread_fail;
|
||||
char *new_data = (char *) realloc (data, allocated);
|
||||
if (unlikely (new_data == nullptr)) goto fread_fail;
|
||||
if (unlikely (!new_data)) goto fread_fail;
|
||||
data = new_data;
|
||||
}
|
||||
|
||||
|
@ -668,7 +656,7 @@ fail_without_close:
|
|||
}
|
||||
|
||||
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
|
||||
(hb_destroy_func_t) free);
|
||||
(hb_destroy_func_t) free);
|
||||
|
||||
fread_fail:
|
||||
fclose (fp);
|
||||
|
@ -676,3 +664,4 @@ fread_fail_without_close:
|
|||
free (data);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
#endif /* !HB_NO_OPEN */
|
||||
|
|
|
@ -71,6 +71,9 @@ hb_blob_create (const char *data,
|
|||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name);
|
||||
|
||||
/* Always creates with MEMORY_MODE_READONLY.
|
||||
* Even if the parent blob is writable, we don't
|
||||
* want the user of the sub-blob to be able to
|
||||
|
@ -123,9 +126,6 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
|
|||
HB_EXTERN char *
|
||||
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_BLOB_H */
|
||||
|
|
|
@ -54,13 +54,9 @@ struct hb_blob_t
|
|||
HB_INTERNAL bool try_make_writable_inplace ();
|
||||
HB_INTERNAL bool try_make_writable_inplace_unix ();
|
||||
|
||||
hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); }
|
||||
template <typename Type>
|
||||
const Type* as () const
|
||||
{
|
||||
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); }
|
||||
const Type* as () const { return as_bytes ().as<Type> (); }
|
||||
|
||||
public:
|
||||
hb_object_header_t header;
|
||||
|
@ -81,7 +77,7 @@ struct hb_blob_t
|
|||
template <typename P>
|
||||
struct hb_blob_ptr_t
|
||||
{
|
||||
typedef hb_remove_pointer (P) 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_; }
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_BUFFER_SERIALIZE
|
||||
|
||||
#include "hb-buffer.hh"
|
||||
|
||||
|
||||
|
@ -85,7 +89,7 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
|
|||
const char *
|
||||
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
|
||||
{
|
||||
switch (format)
|
||||
switch ((unsigned) format)
|
||||
{
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
|
||||
|
@ -131,41 +135,41 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
|||
hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
|
||||
*p++ = '"';
|
||||
for (char *q = g; *q; q++) {
|
||||
if (*q == '"')
|
||||
if (*q == '"')
|
||||
*p++ = '\\';
|
||||
*p++ = *q;
|
||||
}
|
||||
*p++ = '"';
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
pos[i].x_advance, pos[i].y_advance));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
extents.x_bearing, extents.y_bearing));
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
extents.width, extents.height));
|
||||
}
|
||||
|
||||
|
@ -224,37 +228,37 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
|||
p += strlen (p);
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
if (x+pos[i].x_offset || y+pos[i].y_offset)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
{
|
||||
*p++ = '+';
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
if (pos[i].y_advance)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
}
|
||||
|
||||
unsigned int l = p - b;
|
||||
|
@ -375,43 +379,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
static bool
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
uint32_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend || pend - p != end - pp)
|
||||
int v;
|
||||
const char *p = pp;
|
||||
if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
static bool
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
int32_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend || pend - p != end - pp)
|
||||
unsigned int v;
|
||||
const char *p = pp;
|
||||
if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
|
@ -484,3 +469,6 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -324,7 +324,7 @@ hb_buffer_t::clear_positions ()
|
|||
out_len = 0;
|
||||
out_info = info;
|
||||
|
||||
memset (pos, 0, sizeof (pos[0]) * len);
|
||||
hb_memset (pos, 0, sizeof (pos[0]) * len);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -438,13 +438,6 @@ hb_buffer_t::set_masks (hb_mask_t value,
|
|||
if (!mask)
|
||||
return;
|
||||
|
||||
if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
info[i].mask = (info[i].mask & not_mask) | value;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
|
||||
|
@ -455,27 +448,13 @@ void
|
|||
hb_buffer_t::reverse_range (unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
if (end - start < 2)
|
||||
return;
|
||||
|
||||
for (i = start, j = end - 1; i < j; i++, j--) {
|
||||
hb_glyph_info_t t;
|
||||
|
||||
t = info[i];
|
||||
info[i] = info[j];
|
||||
info[j] = t;
|
||||
}
|
||||
hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
|
||||
|
||||
if (have_positions) {
|
||||
for (i = start, j = end - 1; i < j; i++, j--) {
|
||||
hb_glyph_position_t t;
|
||||
|
||||
t = pos[i];
|
||||
pos[i] = pos[j];
|
||||
pos[j] = t;
|
||||
}
|
||||
hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -524,7 +503,7 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
|
|||
unsigned int cluster = info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
|
||||
/* Extend end */
|
||||
while (end < len && info[end - 1].cluster == info[end].cluster)
|
||||
|
@ -555,7 +534,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
|
|||
unsigned int cluster = out_info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
|
||||
cluster = hb_min (cluster, out_info[i].cluster);
|
||||
|
||||
/* Extend start */
|
||||
while (start && out_info[start - 1].cluster == out_info[start].cluster)
|
||||
|
@ -612,7 +591,7 @@ done:
|
|||
void
|
||||
hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
|
||||
{
|
||||
unsigned int cluster = (unsigned int) -1;
|
||||
unsigned int cluster = UINT_MAX;
|
||||
cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
|
||||
_unsafe_to_break_set_mask (info, start, end, cluster);
|
||||
}
|
||||
|
@ -628,7 +607,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en
|
|||
assert (start <= out_len);
|
||||
assert (idx <= end);
|
||||
|
||||
unsigned int cluster = (unsigned int) -1;
|
||||
unsigned int cluster = UINT_MAX;
|
||||
cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
|
||||
cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
|
||||
_unsafe_to_break_set_mask (out_info, start, out_len, cluster);
|
||||
|
@ -648,8 +627,8 @@ hb_buffer_t::guess_segment_properties ()
|
|||
if (likely (script != HB_SCRIPT_COMMON &&
|
||||
script != HB_SCRIPT_INHERITED &&
|
||||
script != HB_SCRIPT_UNKNOWN)) {
|
||||
props.script = script;
|
||||
break;
|
||||
props.script = script;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -736,7 +715,7 @@ hb_buffer_create ()
|
|||
hb_buffer_t *
|
||||
hb_buffer_get_empty ()
|
||||
{
|
||||
return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
|
||||
return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -776,8 +755,10 @@ hb_buffer_destroy (hb_buffer_t *buffer)
|
|||
|
||||
free (buffer->info);
|
||||
free (buffer->pos);
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
if (buffer->message_destroy)
|
||||
buffer->message_destroy (buffer->message_data);
|
||||
#endif
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
@ -956,7 +937,7 @@ hb_buffer_get_direction (hb_buffer_t *buffer)
|
|||
*
|
||||
* You can pass one of the predefined #hb_script_t values, or use
|
||||
* hb_script_from_string() or hb_script_from_iso15924_tag() to get the
|
||||
* corresponding script from an ISO 15924 script tag.
|
||||
* corresponding script from an ISO 15924 script tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
@ -999,7 +980,7 @@ hb_buffer_get_script (hb_buffer_t *buffer)
|
|||
* are orthogonal to the scripts, and though they are related, they are
|
||||
* different concepts and should not be confused with each other.
|
||||
*
|
||||
* Use hb_language_from_string() to convert from BCP 47 language tags to
|
||||
* Use hb_language_from_string() to convert from BCP 47 language tags to
|
||||
* #hb_language_t.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
|
@ -1388,7 +1369,7 @@ hb_buffer_get_length (hb_buffer_t *buffer)
|
|||
**/
|
||||
hb_glyph_info_t *
|
||||
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
|
||||
unsigned int *length)
|
||||
unsigned int *length)
|
||||
{
|
||||
if (length)
|
||||
*length = buffer->len;
|
||||
|
@ -1412,7 +1393,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
|
|||
**/
|
||||
hb_glyph_position_t *
|
||||
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
|
||||
unsigned int *length)
|
||||
unsigned int *length)
|
||||
{
|
||||
if (!buffer->have_positions)
|
||||
buffer->clear_positions ();
|
||||
|
@ -1736,7 +1717,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
|
|||
* @buffer: an #hb_buffer_t.
|
||||
* @source: source #hb_buffer_t.
|
||||
* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.
|
||||
* @end: end index into source buffer to copy. Use (unsigned int) -1 to copy to end of buffer.
|
||||
* @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.
|
||||
*
|
||||
* Append (part of) contents of another buffer to this buffer.
|
||||
*
|
||||
|
@ -1858,18 +1839,8 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
|
|||
|
||||
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
|
||||
unsigned int count = buffer->len;
|
||||
if (unlikely (!count)) return;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
unsigned int start = 0;
|
||||
unsigned int end;
|
||||
for (end = start + 1; end < count; end++)
|
||||
if (info[start].cluster != info[end].cluster) {
|
||||
normalize_glyphs_cluster (buffer, start, end, backward);
|
||||
start = end;
|
||||
}
|
||||
normalize_glyphs_cluster (buffer, start, end, backward);
|
||||
foreach_cluster (buffer, start, end)
|
||||
normalize_glyphs_cluster (buffer, start, end, backward);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1936,9 +1907,9 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (contains && info[i].codepoint == dottedcircle_glyph)
|
||||
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
|
||||
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
|
||||
if (contains && info[i].codepoint == 0)
|
||||
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
|
||||
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
|
||||
}
|
||||
result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
|
||||
return hb_buffer_diff_flags_t (result);
|
||||
|
@ -1973,12 +1944,12 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
|
||||
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
|
||||
{
|
||||
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
|
||||
break;
|
||||
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
|
||||
break;
|
||||
}
|
||||
buf_pos++;
|
||||
ref_pos++;
|
||||
|
@ -1993,6 +1964,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
* Debugging.
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
/**
|
||||
* hb_buffer_set_message_func:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
|
@ -2022,11 +1994,11 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
|
|||
buffer->message_destroy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[100];
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
return (bool) this->message_func (this, font, buf, this->message_data);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -365,7 +365,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer);
|
|||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_buffer_pre_allocate (hb_buffer_t *buffer,
|
||||
unsigned int size);
|
||||
unsigned int size);
|
||||
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
|
@ -441,11 +441,11 @@ hb_buffer_get_length (hb_buffer_t *buffer);
|
|||
|
||||
HB_EXTERN hb_glyph_info_t *
|
||||
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
|
||||
unsigned int *length);
|
||||
unsigned int *length);
|
||||
|
||||
HB_EXTERN hb_glyph_position_t *
|
||||
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
|
||||
unsigned int *length);
|
||||
unsigned int *length);
|
||||
|
||||
|
||||
HB_EXTERN void
|
||||
|
|
|
@ -124,9 +124,11 @@ struct hb_buffer_t
|
|||
unsigned int context_len[2];
|
||||
|
||||
/* Debugging API */
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
hb_buffer_message_func_t message_func;
|
||||
void *message_data;
|
||||
hb_destroy_func_t message_destroy;
|
||||
#endif
|
||||
|
||||
/* Internal debugging. */
|
||||
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
|
||||
|
@ -226,10 +228,10 @@ struct hb_buffer_t
|
|||
/* Makes a copy of the glyph at idx to output and replace glyph_index */
|
||||
hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
|
||||
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);
|
||||
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;
|
||||
|
@ -347,9 +349,19 @@ struct hb_buffer_t
|
|||
|
||||
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
|
||||
|
||||
bool messaging () { return unlikely (message_func); }
|
||||
bool messaging ()
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return false;
|
||||
#else
|
||||
return unlikely (message_func);
|
||||
#endif
|
||||
}
|
||||
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return true;
|
||||
#else
|
||||
if (!messaging ())
|
||||
return true;
|
||||
va_list ap;
|
||||
|
@ -357,6 +369,7 @@ struct hb_buffer_t
|
|||
bool ret = message_impl (font, fmt, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
|
||||
|
||||
|
@ -373,13 +386,13 @@ struct hb_buffer_t
|
|||
inf.cluster = cluster;
|
||||
}
|
||||
|
||||
int
|
||||
unsigned int
|
||||
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
|
||||
unsigned int start, unsigned int end,
|
||||
unsigned int cluster) const
|
||||
{
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, infos[i].cluster);
|
||||
cluster = hb_min (cluster, infos[i].cluster);
|
||||
return cluster;
|
||||
}
|
||||
void
|
||||
|
@ -395,8 +408,7 @@ struct hb_buffer_t
|
|||
}
|
||||
}
|
||||
|
||||
void unsafe_to_break_all ()
|
||||
{ unsafe_to_break_impl (0, len); }
|
||||
void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
|
||||
void safe_to_break_all ()
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
|
|
|
@ -220,32 +220,22 @@ struct number_t
|
|||
void init () { set_real (0.0); }
|
||||
void fini () {}
|
||||
|
||||
void set_int (int v) { value = (double) v; }
|
||||
int to_int () const { return (int) value; }
|
||||
void set_int (int v) { value = v; }
|
||||
int to_int () const { return value; }
|
||||
|
||||
void set_fixed (int32_t v) { value = v / 65536.0; }
|
||||
int32_t to_fixed () const { return (int32_t) (value * 65536.0); }
|
||||
int32_t to_fixed () const { return value * 65536.0; }
|
||||
|
||||
void set_real (double v) { value = v; }
|
||||
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); }
|
||||
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)
|
||||
{
|
||||
|
@ -255,37 +245,34 @@ struct number_t
|
|||
}
|
||||
|
||||
protected:
|
||||
double value;
|
||||
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)
|
||||
template <typename T, typename V>
|
||||
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (unlikely ((value < minVal || value > maxVal)))
|
||||
return_trace (false);
|
||||
|
||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
||||
if (unlikely (p == nullptr)) return_trace (false);
|
||||
if (unlikely (!p)) 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);
|
||||
T *ip = c->allocate_size<T> (T::static_size);
|
||||
if (unlikely (!ip)) return_trace (false);
|
||||
return_trace (c->check_assign (*ip, value));
|
||||
}
|
||||
|
||||
static bool serialize_int4 (hb_serialize_context_t *c, int value)
|
||||
{ return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); }
|
||||
template <typename V>
|
||||
static bool serialize_int4 (hb_serialize_context_t *c, V value)
|
||||
{ return serialize_int<HBINT32> (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); }
|
||||
template <typename V>
|
||||
static bool serialize_int2 (hb_serialize_context_t *c, V value)
|
||||
{ return serialize_int<HBINT16> (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,
|
||||
|
@ -308,7 +295,7 @@ struct byte_str_t : hb_ubytes_t
|
|||
: 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_)); }
|
||||
|
@ -320,8 +307,7 @@ struct byte_str_t : hb_ubytes_t
|
|||
/* A byte string associated with the current offset and an error condition */
|
||||
struct byte_str_ref_t
|
||||
{
|
||||
byte_str_ref_t ()
|
||||
{ init (); }
|
||||
byte_str_ref_t () { init (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
|
@ -343,13 +329,12 @@ struct byte_str_ref_t
|
|||
}
|
||||
|
||||
const unsigned char& operator [] (int i) {
|
||||
if (unlikely ((unsigned int)(offset + i) >= str.length))
|
||||
if (unlikely ((unsigned int) (offset + i) >= str.length))
|
||||
{
|
||||
set_error ();
|
||||
return Null(unsigned char);
|
||||
return Null (unsigned char);
|
||||
}
|
||||
else
|
||||
return str[offset + i];
|
||||
return str[offset + i];
|
||||
}
|
||||
|
||||
/* Conversion to byte_str_t */
|
||||
|
@ -359,9 +344,7 @@ struct byte_str_ref_t
|
|||
{ return str.sub_str (offset_, len_); }
|
||||
|
||||
bool avail (unsigned int count=1) const
|
||||
{
|
||||
return (!in_error () && str.check_limit (offset, count));
|
||||
}
|
||||
{ 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)))
|
||||
|
@ -389,7 +372,7 @@ typedef hb_vector_t<byte_str_t> byte_str_array_t;
|
|||
|
||||
/* stack */
|
||||
template <typename ELEM, int LIMIT>
|
||||
struct stack_t
|
||||
struct cff_stack_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
|
@ -400,11 +383,7 @@ struct stack_t
|
|||
for (unsigned int i = 0; i < elements.length; i++)
|
||||
elements[i].init ();
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
elements.fini_deep ();
|
||||
}
|
||||
void fini () { elements.fini_deep (); }
|
||||
|
||||
ELEM& operator [] (unsigned int i)
|
||||
{
|
||||
|
@ -419,7 +398,6 @@ struct stack_t
|
|||
else
|
||||
set_error ();
|
||||
}
|
||||
|
||||
ELEM &push ()
|
||||
{
|
||||
if (likely (count < elements.length))
|
||||
|
@ -427,7 +405,7 @@ struct stack_t
|
|||
else
|
||||
{
|
||||
set_error ();
|
||||
return Crap(ELEM);
|
||||
return Crap (ELEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,10 +416,9 @@ struct stack_t
|
|||
else
|
||||
{
|
||||
set_error ();
|
||||
return Crap(ELEM);
|
||||
return Crap (ELEM);
|
||||
}
|
||||
}
|
||||
|
||||
void pop (unsigned int n)
|
||||
{
|
||||
if (likely (count >= n))
|
||||
|
@ -452,13 +429,12 @@ struct stack_t
|
|||
|
||||
const ELEM& peek ()
|
||||
{
|
||||
if (likely (count > 0))
|
||||
return elements[count-1];
|
||||
else
|
||||
if (unlikely (count < 0))
|
||||
{
|
||||
set_error ();
|
||||
return Null(ELEM);
|
||||
return Null (ELEM);
|
||||
}
|
||||
return elements[count - 1];
|
||||
}
|
||||
|
||||
void unpop ()
|
||||
|
@ -475,7 +451,7 @@ struct stack_t
|
|||
void set_error () { error = true; }
|
||||
|
||||
unsigned int get_count () const { return count; }
|
||||
bool is_empty () const { return count == 0; }
|
||||
bool is_empty () const { return !count; }
|
||||
|
||||
static constexpr unsigned kSizeLimit = LIMIT;
|
||||
|
||||
|
@ -487,7 +463,7 @@ struct stack_t
|
|||
|
||||
/* argument stack */
|
||||
template <typename ARG=number_t>
|
||||
struct arg_stack_t : stack_t<ARG, 513>
|
||||
struct arg_stack_t : cff_stack_t<ARG, 513>
|
||||
{
|
||||
void push_int (int v)
|
||||
{
|
||||
|
@ -519,7 +495,7 @@ struct arg_stack_t : stack_t<ARG, 513>
|
|||
i = 0;
|
||||
S::set_error ();
|
||||
}
|
||||
return (unsigned)i;
|
||||
return (unsigned) i;
|
||||
}
|
||||
|
||||
void push_longint_from_substr (byte_str_ref_t& str_ref)
|
||||
|
@ -538,12 +514,10 @@ struct arg_stack_t : stack_t<ARG, 513>
|
|||
}
|
||||
|
||||
hb_array_t<const ARG> get_subarray (unsigned int start) const
|
||||
{
|
||||
return S::elements.sub_array (start);
|
||||
}
|
||||
{ return S::elements.sub_array (start); }
|
||||
|
||||
private:
|
||||
typedef stack_t<ARG, 513> S;
|
||||
typedef cff_stack_t<ARG, 513> S;
|
||||
};
|
||||
|
||||
/* an operator prefixed by its operands in a byte string */
|
||||
|
@ -565,7 +539,7 @@ struct op_serializer_t
|
|||
TRACE_SERIALIZE (this);
|
||||
|
||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
|
||||
if (unlikely (d == nullptr)) return_trace (false);
|
||||
if (unlikely (!d)) return_trace (false);
|
||||
memcpy (d, &opstr.str[0], opstr.str.length);
|
||||
return_trace (true);
|
||||
}
|
||||
|
@ -605,7 +579,7 @@ struct parsed_values_t
|
|||
}
|
||||
|
||||
unsigned get_count () const { return values.length; }
|
||||
const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
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;
|
||||
|
@ -644,30 +618,19 @@ struct interp_env_t
|
|||
return op;
|
||||
}
|
||||
|
||||
const ARG& eval_arg (unsigned int i)
|
||||
{
|
||||
return argStack[i];
|
||||
}
|
||||
const ARG& eval_arg (unsigned int i) { return argStack[i]; }
|
||||
|
||||
ARG& pop_arg ()
|
||||
{
|
||||
return argStack.pop ();
|
||||
}
|
||||
ARG& pop_arg () { return argStack.pop (); }
|
||||
void pop_n_args (unsigned int n) { argStack.pop (n); }
|
||||
|
||||
void pop_n_args (unsigned int n)
|
||||
{
|
||||
argStack.pop (n);
|
||||
}
|
||||
void clear_args () { pop_n_args (argStack.get_count ()); }
|
||||
|
||||
void clear_args ()
|
||||
{
|
||||
pop_n_args (argStack.get_count ());
|
||||
}
|
||||
|
||||
byte_str_ref_t str_ref;
|
||||
arg_stack_t<ARG> argStack;
|
||||
byte_str_ref_t
|
||||
str_ref;
|
||||
arg_stack_t<ARG>
|
||||
argStack;
|
||||
protected:
|
||||
bool error;
|
||||
bool error;
|
||||
};
|
||||
|
||||
typedef interp_env_t<> num_interp_env_t;
|
||||
|
@ -691,7 +654,7 @@ struct opset_t
|
|||
|
||||
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.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
|
||||
env.str_ref.inc ();
|
||||
break;
|
||||
|
||||
|
@ -711,8 +674,8 @@ struct opset_t
|
|||
};
|
||||
|
||||
template <typename ENV>
|
||||
struct interpreter_t {
|
||||
|
||||
struct interpreter_t
|
||||
{
|
||||
~interpreter_t() { fini (); }
|
||||
|
||||
void fini () { env.fini (); }
|
||||
|
|
|
@ -57,14 +57,14 @@ struct call_context_t
|
|||
|
||||
/* call stack */
|
||||
const unsigned int kMaxCallLimit = 10;
|
||||
struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {};
|
||||
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
|
||||
|
||||
template <typename SUBRS>
|
||||
struct biased_subrs_t
|
||||
{
|
||||
void init (const SUBRS &subrs_)
|
||||
void init (const SUBRS *subrs_)
|
||||
{
|
||||
subrs = &subrs_;
|
||||
subrs = subrs_;
|
||||
unsigned int nSubrs = get_count ();
|
||||
if (nSubrs < 1240)
|
||||
bias = 107;
|
||||
|
@ -76,13 +76,13 @@ struct biased_subrs_t
|
|||
|
||||
void fini () {}
|
||||
|
||||
unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
|
||||
unsigned int get_bias () const { return bias; }
|
||||
unsigned int get_count () const { return subrs ? subrs->count : 0; }
|
||||
unsigned int get_bias () const { return bias; }
|
||||
|
||||
byte_str_t operator [] (unsigned int index) const
|
||||
{
|
||||
if (unlikely ((subrs == nullptr) || index >= subrs->count))
|
||||
return Null(byte_str_t);
|
||||
if (unlikely (!subrs || index >= subrs->count))
|
||||
return Null (byte_str_t);
|
||||
else
|
||||
return (*subrs)[index];
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ struct point_t
|
|||
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_)
|
||||
void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
|
||||
{
|
||||
interp_env_t<ARG>::init (str);
|
||||
|
||||
|
@ -147,8 +147,9 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
|||
return callStack.in_error () || SUPER::in_error ();
|
||||
}
|
||||
|
||||
bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
{
|
||||
subr_num = 0;
|
||||
int n = SUPER::argStack.pop_int ();
|
||||
n += biasedSubrs.get_bias ();
|
||||
if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
|
||||
|
@ -158,11 +159,11 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
|||
return true;
|
||||
}
|
||||
|
||||
void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
{
|
||||
unsigned int subr_num;
|
||||
unsigned int subr_num = 0;
|
||||
|
||||
if (unlikely (!popSubrNum (biasedSubrs, subr_num)
|
||||
if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
|
||||
|| callStack.get_count () >= kMaxCallLimit))
|
||||
{
|
||||
SUPER::set_error ();
|
||||
|
@ -175,7 +176,7 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
|||
SUPER::str_ref = context.str_ref;
|
||||
}
|
||||
|
||||
void returnFromSubr ()
|
||||
void return_from_subr ()
|
||||
{
|
||||
if (unlikely (SUPER::str_ref.in_error ()))
|
||||
SUPER::set_error ();
|
||||
|
@ -246,7 +247,7 @@ struct path_procs_null_t
|
|||
static void flex1 (ENV &env, PARAM& param) {}
|
||||
};
|
||||
|
||||
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, 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)
|
||||
|
@ -254,7 +255,7 @@ struct cs_opset_t : opset_t<ARG>
|
|||
switch (op) {
|
||||
|
||||
case OpCode_return:
|
||||
env.returnFromSubr ();
|
||||
env.return_from_subr ();
|
||||
break;
|
||||
case OpCode_endchar:
|
||||
OPSET::check_width (op, env, param);
|
||||
|
@ -267,11 +268,11 @@ struct cs_opset_t : opset_t<ARG>
|
|||
break;
|
||||
|
||||
case OpCode_callsubr:
|
||||
env.callSubr (env.localSubrs, CSType_LocalSubr);
|
||||
env.call_subr (env.localSubrs, CSType_LocalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
env.callSubr (env.globalSubrs, CSType_GlobalSubr);
|
||||
env.call_subr (env.globalSubrs, CSType_GlobalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_hstem:
|
||||
|
@ -550,8 +551,13 @@ struct path_procs_t
|
|||
|
||||
static void rcurveline (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int arg_count = env.argStack.get_count ();
|
||||
if (unlikely (arg_count < 8))
|
||||
return;
|
||||
|
||||
unsigned int i = 0;
|
||||
for (; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
unsigned int curve_limit = arg_count - 2;
|
||||
for (; i + 6 <= curve_limit; i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
|
@ -561,34 +567,34 @@ struct path_procs_t
|
|||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
for (; i + 2 <= env.argStack.get_count (); i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
|
||||
static void rlinecurve (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int arg_count = env.argStack.get_count ();
|
||||
if (unlikely (arg_count < 8))
|
||||
return;
|
||||
|
||||
unsigned int i = 0;
|
||||
unsigned int line_limit = (env.argStack.get_count () % 6);
|
||||
unsigned int line_limit = arg_count - 6;
|
||||
for (; i + 2 <= line_limit; i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
for (; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
|
||||
static void vvcurveto (ENV &env, PARAM& param)
|
||||
|
|
|
@ -27,8 +27,6 @@
|
|||
#define HB_CFF_INTERP_DICT_COMMON_HH
|
||||
|
||||
#include "hb-cff-interp-common.hh"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
namespace CFF {
|
||||
|
||||
|
@ -58,19 +56,6 @@ struct top_dict_values_t : dict_values_t<OPSTR>
|
|||
}
|
||||
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;
|
||||
};
|
||||
|
@ -94,130 +79,52 @@ struct dict_opset_t : opset_t<number_t>
|
|||
}
|
||||
}
|
||||
|
||||
/* Turns CFF's BCD format into strtod understandable string */
|
||||
static double parse_bcd (byte_str_ref_t& str_ref)
|
||||
{
|
||||
bool neg = false;
|
||||
double int_part = 0;
|
||||
uint64_t frac_part = 0;
|
||||
uint32_t frac_count = 0;
|
||||
bool exp_neg = false;
|
||||
uint32_t exp_part = 0;
|
||||
bool exp_overflow = false;
|
||||
enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
|
||||
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 */
|
||||
if (unlikely (str_ref.in_error ())) return .0;
|
||||
|
||||
double value = 0.0;
|
||||
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
|
||||
|
||||
char buf[32];
|
||||
unsigned char byte = 0;
|
||||
for (uint32_t i = 0;; i++)
|
||||
for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
|
||||
{
|
||||
char d;
|
||||
if ((i & 1) == 0)
|
||||
unsigned nibble;
|
||||
if (!(i & 1))
|
||||
{
|
||||
if (!str_ref.avail ())
|
||||
{
|
||||
str_ref.set_error ();
|
||||
return 0.0;
|
||||
}
|
||||
if (unlikely (!str_ref.avail ())) break;
|
||||
|
||||
byte = str_ref[0];
|
||||
str_ref.inc ();
|
||||
d = byte >> 4;
|
||||
nibble = byte >> 4;
|
||||
}
|
||||
else
|
||||
d = byte & 0x0F;
|
||||
nibble = byte & 0x0F;
|
||||
|
||||
switch (d)
|
||||
if (unlikely (nibble == RESERVED)) break;
|
||||
else if (nibble == END)
|
||||
{
|
||||
case RESERVED:
|
||||
str_ref.set_error ();
|
||||
return value;
|
||||
|
||||
case END:
|
||||
value = (double)(neg? -int_part: int_part);
|
||||
if (frac_count > 0)
|
||||
{
|
||||
double frac = (frac_part / pow (10.0, (double)frac_count));
|
||||
if (neg) frac = -frac;
|
||||
value += frac;
|
||||
}
|
||||
if (unlikely (exp_overflow))
|
||||
{
|
||||
if (value == 0.0)
|
||||
return value;
|
||||
if (exp_neg)
|
||||
return neg? -DBL_MIN: DBL_MIN;
|
||||
else
|
||||
return neg? -DBL_MAX: DBL_MAX;
|
||||
}
|
||||
if (exp_part != 0)
|
||||
{
|
||||
if (exp_neg)
|
||||
value /= pow (10.0, (double)exp_part);
|
||||
else
|
||||
value *= pow (10.0, (double)exp_part);
|
||||
}
|
||||
return value;
|
||||
|
||||
case NEG:
|
||||
if (i != 0)
|
||||
{
|
||||
str_ref.set_error ();
|
||||
return 0.0;
|
||||
}
|
||||
neg = true;
|
||||
const char *p = buf;
|
||||
double pv;
|
||||
if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */)))
|
||||
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 pv;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[count] = "0123456789.EE?-?"[nibble];
|
||||
if (nibble == EXP_NEG)
|
||||
{
|
||||
++count;
|
||||
if (unlikely (count == ARRAY_LENGTH (buf))) break;
|
||||
buf[count] = '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
str_ref.set_error ();
|
||||
return .0;
|
||||
}
|
||||
|
||||
static bool is_hint_op (op_code_t op)
|
||||
|
|
|
@ -40,7 +40,7 @@ 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);
|
||||
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
|
||||
processed_width = false;
|
||||
has_width = false;
|
||||
arg_start = 0;
|
||||
|
@ -81,7 +81,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
|
|||
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> >
|
||||
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 */
|
||||
|
|
|
@ -80,9 +80,9 @@ 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)
|
||||
const int *coords_=nullptr, unsigned int num_coords_=0)
|
||||
{
|
||||
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
|
||||
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
|
||||
|
||||
coords = coords_;
|
||||
num_coords = num_coords_;
|
||||
|
@ -90,7 +90,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
seen_blend = false;
|
||||
seen_vsindex_ = false;
|
||||
scalars.init ();
|
||||
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
|
||||
do_blend = num_coords && coords && varStore->size;
|
||||
set_ivs (acc.privateDicts[fd].ivs);
|
||||
}
|
||||
|
||||
|
@ -134,8 +134,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
if (do_blend)
|
||||
{
|
||||
scalars.resize (region_count);
|
||||
varStore->varStore.get_scalars (get_ivs (),
|
||||
(int *)coords, num_coords,
|
||||
varStore->varStore.get_scalars (get_ivs (), coords, num_coords,
|
||||
&scalars[0], region_count);
|
||||
}
|
||||
seen_blend = true;
|
||||
|
@ -193,7 +192,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
|
||||
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> >
|
||||
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)
|
||||
|
|
275
src/hb-common.cc
275
src/hb-common.cc
|
@ -27,14 +27,13 @@
|
|||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_SETLOCALE
|
||||
#define setlocale(Category, Locale) "C"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION:hb-common
|
||||
|
@ -64,13 +63,12 @@ _hb_options_init ()
|
|||
{
|
||||
const char *p = strchr (c, ':');
|
||||
if (!p)
|
||||
p = c + strlen (c);
|
||||
p = c + strlen (c);
|
||||
|
||||
#define OPTION(name, symbol) \
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
|
||||
|
||||
OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
|
||||
OPTION ("aat", aat);
|
||||
|
||||
#undef OPTION
|
||||
|
||||
|
@ -334,14 +332,14 @@ retry:
|
|||
/**
|
||||
* hb_language_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t): a string representing
|
||||
* a BCP 47 language tag
|
||||
* a BCP 47 language tag
|
||||
* @len: length of the @str, or -1 if it is %NULL-terminated.
|
||||
*
|
||||
* Converts @str representing a BCP 47 language tag to the corresponding
|
||||
* Converts @str representing a BCP 47 language tag to the corresponding
|
||||
* #hb_language_t.
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
* The #hb_language_t corresponding to the BCP 47 language tag.
|
||||
* The #hb_language_t corresponding to the BCP 47 language tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
@ -356,7 +354,7 @@ hb_language_from_string (const char *str, int len)
|
|||
{
|
||||
/* NUL-terminate it. */
|
||||
char strbuf[64];
|
||||
len = MIN (len, (int) sizeof (strbuf) - 1);
|
||||
len = hb_min (len, (int) sizeof (strbuf) - 1);
|
||||
memcpy (strbuf, str, len);
|
||||
strbuf[len] = '\0';
|
||||
item = lang_find_or_insert (strbuf);
|
||||
|
@ -382,7 +380,8 @@ hb_language_from_string (const char *str, int len)
|
|||
const char *
|
||||
hb_language_to_string (hb_language_t language)
|
||||
{
|
||||
/* This is actually nullptr-safe! */
|
||||
if (unlikely (!language)) return nullptr;
|
||||
|
||||
return language->s;
|
||||
}
|
||||
|
||||
|
@ -422,12 +421,12 @@ hb_language_get_default ()
|
|||
|
||||
/**
|
||||
* hb_script_from_iso15924_tag:
|
||||
* @tag: an #hb_tag_t representing an ISO 15924 tag.
|
||||
* @tag: an #hb_tag_t representing an ISO 15924 tag.
|
||||
*
|
||||
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
|
||||
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
|
||||
*
|
||||
* Return value:
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
@ -468,15 +467,15 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
|
|||
/**
|
||||
* hb_script_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t): a string representing an
|
||||
* ISO 15924 tag.
|
||||
* ISO 15924 tag.
|
||||
* @len: length of the @str, or -1 if it is %NULL-terminated.
|
||||
*
|
||||
* Converts a string @str representing an ISO 15924 script tag to a
|
||||
* Converts a string @str representing an ISO 15924 script tag to a
|
||||
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
|
||||
* hb_script_from_iso15924_tag().
|
||||
*
|
||||
* Return value:
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
@ -488,12 +487,12 @@ hb_script_from_string (const char *str, int len)
|
|||
|
||||
/**
|
||||
* hb_script_to_iso15924_tag:
|
||||
* @script: an #hb_script_ to convert.
|
||||
* @script: an #hb_script_t to convert.
|
||||
*
|
||||
* See hb_script_from_iso15924_tag().
|
||||
*
|
||||
* Return value:
|
||||
* An #hb_tag_t representing an ISO 15924 script tag.
|
||||
* An #hb_tag_t representing an ISO 15924 script tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
@ -590,38 +589,6 @@ hb_script_get_horizontal_direction (hb_script_t script)
|
|||
}
|
||||
|
||||
|
||||
/* hb_user_data_array_t */
|
||||
|
||||
bool
|
||||
hb_user_data_array_t::set (hb_user_data_key_t *key,
|
||||
void * data,
|
||||
hb_destroy_func_t destroy,
|
||||
hb_bool_t replace)
|
||||
{
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (replace) {
|
||||
if (!data && !destroy) {
|
||||
items.remove (key, lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hb_user_data_item_t item = {key, data, destroy};
|
||||
bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
hb_user_data_array_t::get (hb_user_data_key_t *key)
|
||||
{
|
||||
hb_user_data_item_t item = {nullptr, nullptr, nullptr};
|
||||
|
||||
return items.find (key, &item, lock) ? item.data : nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* hb_version */
|
||||
|
||||
|
||||
|
@ -719,131 +686,24 @@ parse_char (const char **pp, const char *end, char c)
|
|||
static bool
|
||||
parse_uint (const char **pp, const char *end, unsigned int *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
unsigned int v;
|
||||
|
||||
/* Intentionally use strtol instead of strtoul, such that
|
||||
* -1 turns into "big number"... */
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
|
||||
* such that -1 turns into "big number"... */
|
||||
int v;
|
||||
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
unsigned int v;
|
||||
|
||||
/* Intentionally use strtol instead of strtoul, such that
|
||||
* -1 turns into "big number"... */
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
|
||||
* such that -1 turns into "big number"... */
|
||||
int v;
|
||||
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
|
||||
#define USE_XLOCALE 1
|
||||
#define HB_LOCALE_T locale_t
|
||||
#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
|
||||
#define HB_FREE_LOCALE(loc) freelocale (loc)
|
||||
#elif defined(_MSC_VER)
|
||||
#define USE_XLOCALE 1
|
||||
#define HB_LOCALE_T _locale_t
|
||||
#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
|
||||
#define HB_FREE_LOCALE(loc) _free_locale (loc)
|
||||
#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
|
||||
#endif
|
||||
|
||||
#ifdef USE_XLOCALE
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static void free_static_C_locale ();
|
||||
#endif
|
||||
|
||||
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T),
|
||||
hb_C_locale_lazy_loader_t>
|
||||
{
|
||||
static HB_LOCALE_T create ()
|
||||
{
|
||||
HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
atexit (free_static_C_locale);
|
||||
#endif
|
||||
|
||||
return C_locale;
|
||||
}
|
||||
static void destroy (HB_LOCALE_T p)
|
||||
{
|
||||
HB_FREE_LOCALE (p);
|
||||
}
|
||||
static HB_LOCALE_T get_null ()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} static_C_locale;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_C_locale ()
|
||||
{
|
||||
static_C_locale.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static HB_LOCALE_T
|
||||
get_C_locale ()
|
||||
{
|
||||
return static_C_locale.get_unconst ();
|
||||
}
|
||||
#endif /* USE_XLOCALE */
|
||||
|
||||
static bool
|
||||
parse_float (const char **pp, const char *end, float *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
float v;
|
||||
|
||||
errno = 0;
|
||||
#ifdef USE_XLOCALE
|
||||
v = strtod_l (p, &pend, get_C_locale ());
|
||||
#else
|
||||
v = strtod (p, &pend);
|
||||
#endif
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -953,7 +813,7 @@ parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *fea
|
|||
{
|
||||
bool had_equal = parse_char (pp, end, '=');
|
||||
bool had_value = parse_uint32 (pp, end, &feature->value) ||
|
||||
parse_bool (pp, end, &feature->value);
|
||||
parse_bool (pp, end, &feature->value);
|
||||
/* CSS doesn't use equal-sign between tag and value.
|
||||
* If there was an equal-sign, then there *must* be a value.
|
||||
* A value without an equal-sign is ok, but not required. */
|
||||
|
@ -1067,25 +927,25 @@ hb_feature_to_string (hb_feature_t *feature,
|
|||
len += 4;
|
||||
while (len && s[len - 1] == ' ')
|
||||
len--;
|
||||
if (feature->start != 0 || feature->end != (unsigned int) -1)
|
||||
if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
|
||||
{
|
||||
s[len++] = '[';
|
||||
if (feature->start)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
if (feature->end != feature->start + 1) {
|
||||
s[len++] = ':';
|
||||
if (feature->end != (unsigned int) -1)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
|
||||
if (feature->end != HB_FEATURE_GLOBAL_END)
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
|
||||
}
|
||||
s[len++] = ']';
|
||||
}
|
||||
if (feature->value > 1)
|
||||
{
|
||||
s[len++] = '=';
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
}
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
@ -1096,7 +956,11 @@ static bool
|
|||
parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
|
||||
{
|
||||
parse_char (pp, end, '='); /* Optional. */
|
||||
return parse_float (pp, end, &variation->value);
|
||||
double v;
|
||||
if (unlikely (!hb_parse_double (pp, end, &v))) return false;
|
||||
|
||||
variation->value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -1152,14 +1016,71 @@ 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", (double) variation->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
|
||||
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_alpha:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Alpha channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_alpha) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_alpha (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_red:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Red channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_red) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_red (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_green:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Green channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_green) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_green (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_blue:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Blue channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_blue) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_blue (color);
|
||||
}
|
||||
|
||||
|
||||
/* If there is no visibility control, then hb-static.cc will NOT
|
||||
* define anything. Instead, we get it to define one set in here
|
||||
* only, so only libharfbuzz.so defines them, not other libs. */
|
||||
|
|
|
@ -63,6 +63,8 @@ typedef __int32 int32_t;
|
|||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined (__KERNEL__)
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
@ -423,6 +425,21 @@ typedef void (*hb_destroy_func_t) (void *user_data);
|
|||
*/
|
||||
#define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
|
||||
|
||||
/**
|
||||
* hb_feature_t:
|
||||
* @tag: a feature tag
|
||||
* @value: 0 disables the feature, non-zero (usually 1) enables the feature.
|
||||
* For features implemented as lookup type 3 (like 'salt') the @value is a one
|
||||
* based index into the alternates.
|
||||
* @start: the cluster to start applying this feature setting (inclusive).
|
||||
* @end: the cluster to end applying this feature setting (exclusive).
|
||||
*
|
||||
* The #hb_feature_t is the structure that holds information about requested
|
||||
* feature application. The feature will be applied with the given value to all
|
||||
* glyphs which are in clusters between @start (inclusive) and @end (exclusive).
|
||||
* Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
|
||||
* specifies that the feature always applies to the entire buffer.
|
||||
*/
|
||||
typedef struct hb_feature_t {
|
||||
hb_tag_t tag;
|
||||
uint32_t value;
|
||||
|
@ -467,39 +484,21 @@ 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
|
||||
*/
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_alpha (hb_color_t color);
|
||||
#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_EXTERN uint8_t
|
||||
hb_color_get_red (hb_color_t color);
|
||||
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_green (hb_color_t color);
|
||||
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_blue (hb_color_t color);
|
||||
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue