Merge branch 'master' into remove-coretext-96dpi-assumption

This commit is contained in:
Ebrahim Byagowi 2019-08-20 12:59:33 +04:30 committed by GitHub
commit 37de38adea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
555 changed files with 25930 additions and 17603 deletions

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

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

View file

@ -7,7 +7,7 @@ jobs:
xcode: "9.2.0"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel freetype glib cairo
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
- run: make -j4
- run: make check || .ci/fail.sh
@ -17,49 +17,24 @@ jobs:
xcode: "10.1.0"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel freetype glib cairo
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
- run: make -j4
- run: make check || .ci/fail.sh
macos-llvm-gcc-4.2:
macos-10.14.3-aat-fonts:
macos:
xcode: "8.3.3"
xcode: "10.2.0"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel freetype glib cairo
- run: wget https://packages.macports.org/llvm-gcc42/llvm-gcc42-2336.11_3+universal.darwin_15.i386-x86_64.tbz2 && tar zxvf llvm-gcc42-2336.11_3+universal.darwin_15.i386-x86_64.tbz2
- run: CC=$PWD/opt/local/bin/llvm-gcc-4.2 CXX=$PWD/opt/local/bin/llvm-g++-4.2 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
# Ignoring assembler complains, https://stackoverflow.com/a/39867021
- run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget autoconf automake libtool pkg-config ragel freetype glib cairo icu4c 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
macos-notest-apple-gcc-i686-4.2:
macos:
xcode: "8.3.3"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install wget pkg-config libtool ragel
- run: wget https://packages.macports.org/apple-gcc42/apple-gcc42-5666.3_15+universal.darwin_15.i386-x86_64.tbz2 && tar zxvf apple-gcc42-5666.3_15+universal.darwin_15.i386-x86_64.tbz2
- run: CPP=$PWD/opt/local/bin/i686-apple-darwin15-cpp-apple-4.2.1 CC=$PWD/opt/local/bin/i686-apple-darwin15-gcc-apple-4.2.1 CXX=$PWD/opt/local/bin/i686-apple-darwin15-g++-apple-4.2.1 ./autogen.sh
# Ignoring assembler complains, https://stackoverflow.com/a/39867021
- run: make 2>&1 | grep -v -e '^/var/folders/*' -e '^[[:space:]]*\.section' -e '^[[:space:]]*\^[[:space:]]*~*'
macos-notest-ios:
macos:
xcode: "10.0.0"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake
# not needed to be a framework but we like to test that also
# TODO: wrong way of targeting iOS as it doesn't point to iOS headers thus building
# CoreText support is not possible, after the fix feel free HB_IOS from CMake altogether
- run: cmake -DBUILD_FRAMEWORK=ON -H. -Bbuild -GXcode -DHB_HAVE_CORETEXT=OFF -DHB_BUILD_SUBSET=OFF -DHB_BUILD_TESTS=OFF
- run: cd build && xcodebuild -sdk iphoneos12.0 -configuration Release build -arch arm64
distcheck:
docker:
- image: ubuntu:17.10
- image: ubuntu:19.04
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
@ -70,37 +45,50 @@ jobs:
- 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
alpine-O3-NOMMAP:
alpine-O3-Os-NOMMAP:
docker:
- image: alpine
steps:
- checkout
- run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev
- run: apk update && apk add ragel make pkgconfig libtool autoconf automake gettext gcc g++ glib-dev freetype-dev cairo-dev python
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O3" CXXFLAGS="-O3 -DHB_NO_MMAP" ./autogen.sh
- run: make -j32
- run: make check || .ci/fail.sh
- run: make clean
- run: CFLAGS="-Os -DHB_OPTIMIZE_SIZE" CXXFLAGS="-Os -DHB_NO_MMAP -DHB_OPTIMIZE_SIZE" ./autogen.sh
- run: make -j32
- run: make check || .ci/fail.sh
archlinux-py3-all:
docker:
- image: base/devel
- image: archlinux/base
steps:
- checkout
- run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip
- run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip make which base-devel
- run: pip install flake8 fonttools
- run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-Wall -Wextra -Wno-cast-function-type" CXXFLAGS="-Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-class-memaccess -Wpedantic -Wno-format -Wno-cast-function-type" ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: make -j32 CPPFLAGS="-Werror"
- run: make check CPPFLAGS="-Werror" || .ci/fail.sh
clang-O3-O0:
## Doesn't play well with CircleCI apparently
#void-notest:
# docker:
# - image: voidlinux/voidlinux
# steps:
# - checkout
# - run: xbps-install -Suy freetype gettext gcc glib graphite pkg-config ragel libtool autoconf automake make
# - run: ./autogen.sh && make -j32 && make check
clang-O3-O0-and-nobuildsystem:
docker:
- image: multiarch/crossbuild
- image: ubuntu:18.10
steps:
- checkout
- run: apt update || true
- run: apt install -y ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: apt install -y clang wget autoconf automake libtool pkg-config ragel libfreetype6-dev libfontconfig1-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -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
@ -109,6 +97,7 @@ jobs:
- run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-fontconfig --with-glib --with-cairo --with-icu --with-graphite2
- run: make -j32
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
- run: make clean && cd src && clang++ -c hb-*.cc
gcc-valgrind:
docker:
@ -138,7 +127,7 @@ jobs:
- 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" 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" CXXFLAGS="-Weverything -Wno-old-style-cast -Wno-documentation -Wno-documentation-unknown-command -Wno-c++98-compat -Wno-cast-qual -Wno-c++98-compat-pedantic -Wno-sign-conversion -Wno-padded -Wno-shorten-64-to-32 -Wno-reserved-id-macro -Wno-float-conversion -Wno-format-pedantic -Wno-shadow -Wno-conversion -Wno-zero-as-null-pointer-constant -Wno-missing-field-initializers -Wno-used-but-marked-unused -Wno-unused-macros -Wno-comma -Wno-float-equal -Wno-disabled-macro-expansion -Wno-weak-vtables -Wno-unused-parameter -Wno-covered-switch-default -Wno-unreachable-code -Wno-unused-template" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2 --with-fontconfig
- run: make -j32 CPPFLAGS="-Werror"
- run: make check CPPFLAGS="-Werror" || .ci/fail.sh
@ -208,18 +197,27 @@ jobs:
- run: make -j32
- run: 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: 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 mingw32-gcc-c++ mingw64-gcc-c++ mingw32-glib2 mingw32-cairo mingw32-freetype mingw64-glib2 mingw64-cairo mingw64-freetype glibc-devel.i686 || 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: mkdir build && cd build && ../configure && make -j32 && (make check || ../.ci/fail.sh)
- run: pip install pefile
- run: mkdir winbuild32 && cd winbuild32 && ../mingw32.sh && make -j32 && make dist-win && cp harfbuzz-*-win32.zip harfbuzz-win32.zip
- run: mkdir winbuild64 && cd winbuild64 && ../mingw64.sh && make -j32 && make dist-win && cp harfbuzz-*-win64.zip harfbuzz-win64.zip
- store_artifacts:
path: winbuild32/harfbuzz-win32.zip
destination: harfbuzz-win32.zip
- store_artifacts:
path: winbuild64/harfbuzz-win64.zip
destination: harfbuzz-win64.zip
cmake-gcc:
docker:
- image: ubuntu:17.10
- image: ubuntu:19.04
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
@ -229,17 +227,17 @@ jobs:
- 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
#cmake-oracledeveloperstudio:
# docker:
# - image: fedora
# steps:
# - checkout
# - run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python libnsl || true
# - run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
# - run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
# - run: make -Cbuild -j32
# - run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
# - run: make -Cbuild install
crosscompile-notest-djgpp:
docker:
@ -251,22 +249,13 @@ 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: apt update && apt install ragel
- run: git clone https://github.com/vitasdk/vdpm && cd vdpm && ./bootstrap-vitasdk.sh
- run: echo '#!/bin/true' > /usr/bin/ragel && chmod +x /usr/bin/ragel
- run: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
- run: make -j32
@ -275,17 +264,15 @@ jobs:
- image: dockcross/android-arm
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
crosscompile-cmake-notest-browser-asmjs:
crosscompile-cmake-notest-browser-asmjs-hb_tiny:
docker:
- image: dockcross/browser-asmjs
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DCMAKE_CXX_FLAGS="-DHB_TINY" -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
crosscompile-cmake-notest-linux-arm64:
@ -293,8 +280,7 @@ jobs:
- image: dockcross/linux-arm64
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
crosscompile-cmake-notest-linux-mips:
@ -302,8 +288,7 @@ jobs:
- image: dockcross/linux-mips
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: cmake -Bbuild -H. -GNinja -DHB_BUILD_TESTS=OFF
- run: ninja -Cbuild
#crosscompile-cmake-notest-windows-x64:
@ -311,7 +296,6 @@ jobs:
# - image: dockcross/windows-x64
# steps:
# - checkout
# - run: apt update && apt install ragel
# - run: cmake -Bbuild -H. -GNinja
# - run: ninja -Cbuild
@ -322,39 +306,37 @@ workflows:
# macOS
- macos-10.12.6-aat-fonts
- macos-10.13.6-aat-fonts
- macos-llvm-gcc-4.2
- macos-notest-apple-gcc-i686-4.2
- macos-notest-ios
- macos-10.14.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
#- cmake-oracledeveloperstudio
# 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-browser-asmjs-hb_tiny
- crosscompile-cmake-notest-linux-arm64
- crosscompile-cmake-notest-linux-mips
#- crosscompile-cmake-notest-windows-x64

View file

@ -8,11 +8,8 @@ insert_final_newline = true
[*.{c,cc,h,hh}]
tab_width = 8
indent_style = tab
# This should be the following but as VSCode and Atom don't support it, disabled for now
# https://github.com/Microsoft/vscode/issues/44438
# indent_size = 2
# indent_style = space
indent_size = 2
indent_style = tab # should be space
[*.{py,sh}]
indent_style = tab

View file

@ -6,8 +6,6 @@ language: cpp
env:
global:
- CPPFLAGS=""
- CFLAGS="-Werror -Werror=unused -Werror=unused-function"
- CXXFLAGS="-Werror -Werror=unused -Werror=unused-function -Wno-deprecated-register" # glib uses register and clang raises a warning
- CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
- NOCONFIGURE=1
# COVERITY_SCAN_TOKEN
@ -18,9 +16,10 @@ matrix:
- os: linux
compiler: gcc
script:
# Remove these two lines when Travis updated its distro
- wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
# Remove the following three lines when Travis updates its distro
- export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
- export LD_LIBRARY_PATH="$HOME/.local/lib"
- bash .ci/build-freetype.sh
- ./autogen.sh
- ./configure $CONFIGURE_OPTS --enable-gtk-doc --enable-code-coverage
@ -36,35 +35,24 @@ matrix:
- os: linux
compiler: clang
script:
# Remove these two lines when Travis updated its distro
- wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
# Remove the following three lines when Travis updates its distro
- export PKG_CONFIG_PATH="$HOME/.local/lib/pkgconfig"
- export LD_LIBRARY_PATH="$HOME/.local/lib"
- bash .ci/build-freetype.sh
- ./autogen.sh
- ./configure $CONFIGURE_OPTS
- make
- make check || .ci/fail.sh
- os: osx
compiler: clang
install:
- brew update;
# Workaround Travis/brew bug
- brew uninstall libtool && brew install libtool
- brew install ragel freetype glib gobject-introspection cairo graphite2 || true
- brew upgrade icu4c || true
- export PATH="/usr/local/opt/icu4c/sbin:/usr/local/opt/icu4c/bin:$PATH"
- export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig"
script:
- ./autogen.sh
- ./configure $CONFIGURE_OPTS --with-coretext
- make
- make check || .ci/fail.sh
notifications:
irc: "irc.freenode.org#harfbuzz"
email: harfbuzz-bots-chatter@googlegroups.com
cache:
directories:
- /home/travis/.local
addons:
apt:
packages:

View file

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

View file

@ -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)
@ -70,7 +70,6 @@ option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and
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)
@ -79,6 +78,7 @@ if (HB_CHECK)
set (HB_HAVE_GRAPHITE2 ON)
if (WIN32)
set (HB_HAVE_UNISCRIBE ON)
set (HB_HAVE_GDI ON)
set (HB_HAVE_DIRECTWRITE ON)
elseif (APPLE)
set (HB_HAVE_CORETEXT ON)
@ -90,8 +90,6 @@ include_directories(AFTER
${PROJECT_BINARY_DIR}/src
)
add_definitions(-DHAVE_FALLBACK)
# We need PYTHON_EXECUTABLE to be set for running the tests...
include (FindPythonInterp)
@ -110,7 +108,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)
check_include_file(unistd.h HAVE_UNISTD_H)
if (${HAVE_UNISTD_H})
add_definitions(-DHAVE_UNISTD_H)
@ -144,8 +142,8 @@ 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 ()
@ -160,14 +158,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 +184,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 +192,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 +210,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 +227,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 +234,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 +247,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 +266,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 +277,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 +307,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 +429,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 (); }
@ -610,7 +537,6 @@ if (WIN32)
endif ()
if (HB_HAVE_INTROSPECTION)
find_package(PkgConfig)
pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
@ -842,21 +768,9 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
endif ()
endif ()
if (UNIX AND CMAKE_GENERATOR STREQUAL "Ninja")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
endif ()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color")
endif ()
endif ()
if (HB_BUILD_TESTS)
## src/ executables
foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
foreach (prog main test test-gsub-would-substitute test-gpos-size-params test-buffer-serialize test-unicode-ranges) # hb-ot-tag
set (prog_name ${prog})
if (${prog_name} STREQUAL "test")
# test can not be used as a valid executable name on cmake, lets special case it
@ -865,7 +779,7 @@ if (HB_BUILD_TESTS)
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")
# set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
## Tests
if (UNIX OR MINGW)

151
CONFIG.md Normal file
View file

@ -0,0 +1,151 @@
# Configuring HarfBuzz
Most of the time you will not need any custom configuration. The configuration
options provided by `configure` or `cmake` should be enough. In particular,
if you just want HarfBuzz library plus hb-shape / hb-view utilities, make sure
FreeType and Cairo are available and found during configuration.
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.

View file

@ -2,7 +2,8 @@ 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 Google, Inc.
Copyright © 2019 Facebook, Inc.
Copyright © 2012 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)

View file

@ -9,12 +9,19 @@ 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 \
mingw-configure.sh \
mingw-ldd.py \
mingw32.sh \
mingw64.sh \
$(NULL)
MAINTAINERCLEANFILES = \
@ -36,7 +43,7 @@ ChangeLog: $(srcdir)/ChangeLog
$(srcdir)/ChangeLog:
$(AM_V_GEN) if test -d "$(top_srcdir)/.git"; then \
(GIT_DIR=$(top_srcdir)/.git \
$(GIT) log $(CHANGELOG_RANGE) --stat) | fmt --split-only > $@.tmp \
$(GIT) log $(CHANGELOG_RANGE) --stat) > $@.tmp \
&& mv -f $@.tmp "$(srcdir)/ChangeLog" \
|| ($(RM) $@.tmp; \
echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
@ -60,8 +67,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 +75,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 +86,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

85
NEWS
View file

@ -1,3 +1,88 @@
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
====================================
- Unicode 12.
- Misc fixes.
- Subsetter improvements.
- New API:
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE
hb_directwrite_face_create()
Overview of changes leading to 2.3.1
Wednesday, January 30, 2019
====================================
- AAT bug fixes.
- Misc internal housekeeping cleanup.
Overview of changes leading to 2.3.0
Thursday, December 20, 2018
====================================

18
README
View file

@ -1,18 +0,0 @@
[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
This is HarfBuzz, a text shaping library.
For bug reports, mailing list, and other information please visit:
http://harfbuzz.org/
For license information, see the file COPYING.
Documentation: https://harfbuzz.github.io

1
README Symbolic link
View file

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

View file

@ -1 +0,0 @@
README

24
README.md Normal file
View file

@ -0,0 +1,24 @@
[![Travis Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg?branch=master)](https://travis-ci.org/harfbuzz/harfbuzz)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true&branch=master)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
This is HarfBuzz, a text shaping library.
For bug reports, mailing list, and other information please visit:
http://harfbuzz.org/
For license information, see [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

48
README.mingw.md Normal file
View file

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

View file

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

View file

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

View file

@ -33,39 +33,34 @@ HarfBuzz release walk-through checklist:
That's what happened to 2.0.0 going out with 1.8.0 hb-version.h... So, that's
a clue.
7. "make release-files". Enter your GPG password. This creates a sha256 hash
and signs it.
8. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
7. Now that you have release files, commit NEWS, configure.ac, and src/hb-version.h,
as well as any REPLACEME changes you made. The commit message is simply the
release number. Eg. "1.4.7"
8. "make dist" again to get a tarball with your new commit in the ChangeLog. Then
"make release-files". Enter your GPG password. This creates a sha256 hash
and signs it. Check the size of the three resulting files.
9. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your
GPG password again.
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.
@ -75,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
```

75
TESTING.md Normal file
View file

@ -0,0 +1,75 @@
## 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
cd harfbuzz
mkdir buid
cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
```
## Test with the Fuzzer
```shell
# push your changs to a branch on googlefonts/harfbuzz
# In a local copy of oss-fuzz, edit projects/harfbuzz/Dockerfile
# Change the git clone to pull your branch
# Do this periodically
sudo python infra/helper.py build_image harfbuzz
# Do these to update/run
sudo python infra/helper.py build_fuzzers --sanitizer address harfbuzz
sudo python infra/helper.py run_fuzzer harfbuzz hb-subset-fuzzer
```

2
THANKS
View file

@ -1,6 +1,6 @@
Bradley Grainger
Khaled Hosny
Kenichi Ishibashi
Ivan Kuckir <https://photopea.com/>
Ryan Lortie
Jeff Muizelaar
suzuki toshiya

View file

@ -2,16 +2,18 @@ platform: x64
environment:
matrix:
- compiler: msvc
generator: Visual Studio 14
platform: Win32
configuration: Debug
triplet: x86-windows
- compiler: msvc
generator: Visual Studio 14 Win64
platform: x64
configuration: Debug
triplet: x64-windows
#- compiler: msvc
# generator: Visual Studio 14
# platform: Win32
# configuration: Debug
# triplet: x86-windows
#- compiler: msvc
# generator: Visual Studio 14 Win64
# platform: x64
# configuration: Debug
# triplet: x64-windows
- compiler: msvc
generator: Visual Studio 14 ARM
@ -19,10 +21,35 @@ environment:
configuration: Debug
# Build only
#- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
# compiler: msvc2
# generator: Visual Studio 12
# platform: Win32
# configuration: Release
# triplet: x86-windows
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
compiler: msvc2
generator: Visual Studio 15
platform: Win32
configuration: Release
triplet: x86-windows
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
compiler: msvc2
generator: Visual Studio 16
platform: Win32
configuration: Release
triplet: x86-windows
- compiler: msys2
MINGW_PREFIX: /mingw64
MINGW_CHOST: x86_64-w64-mingw32
MSYS2_ARCH: x86_64
- compiler: msys2
MINGW_PREFIX: /mingw32
MINGW_CHOST: i686-w64-mingw32
@ -30,30 +57,26 @@ environment:
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%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm --force -S --needed mingw-w64-$MSYS2_ARCH-{gcc,freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2,ragel}"'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
build_script:
- 'if "%compiler%"=="msvc" md build'
- 'if "%compiler%"=="msvc" cd build'
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%"'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -Bbuild -H. -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake'
- 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin'
- 'if "%compiler%"=="msvc" 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" cd build'
- 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
- 'if "%compiler%"=="msvc2" cmake -G "%generator%" -Bbuild -H.'
- 'if "%compiler%"=="msvc2" cmake --build build --config %configuration%'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "curl https://raw.githubusercontent.com/mirror/mingw-w64/023eb04c396d4e8d8fcf604cfababc53dae13398/mingw-w64-headers/include/dwrite_1.h > %MINGW_PREFIX%/%MINGW_CHOST%/include/dwrite_1.h"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --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; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --with-directwrite --with-gdi --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make -j3 check || .ci/fail.sh"'
cache:
- c:\tools\vcpkg\installed\
- '%CYGWIN_PREFIX%\var\cache\setup'
notifications:
- provider: Email

View file

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[2.3.0],
[2.6.0],
[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
dnl AX_CXX_COMPILE_STDCXX(11, noext, optional)
AX_CXX_COMPILE_STDCXX(11,, optional)
AC_SYS_LARGEFILE
PKG_PROG_PKG_CONFIG([0.20])
AM_MISSING_PROG([RAGEL], [ragel])
@ -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)
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h stdbool.h)
# Compiler flags
@ -102,9 +96,6 @@ if test "x$GCC" = "xyes"; then
# by overriding CXXFLAGS.
CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics"
# Assorted warnings
CXXFLAGS="$CXXFLAGS -Wcast-align"
case "$host" in
*-*-mingw*)
;;
@ -137,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
@ -147,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@:>@])],,
@ -303,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@:>@])],,
@ -395,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@:>@])],,
@ -410,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])
@ -500,7 +488,6 @@ AC_CONFIG_FILES([
Makefile
src/Makefile
src/harfbuzz-config.cmake
src/hb-ucdn/Makefile
util/Makefile
test/Makefile
test/api/Makefile
@ -518,12 +505,17 @@ docs/version.xml
AC_OUTPUT
echo
echo "C++ compiler version:"
$CXX --version
echo
AC_MSG_NOTICE([
Build configuration:
Unicode callbacks (you want at least one):
Builtin (UCDN): ${have_ucdn}
Builtin true
Glib: ${have_glib}
ICU: ${have_icu}
@ -540,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:

View file

@ -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,12 +75,14 @@ content_files= \
usermanual-what-is-harfbuzz.xml \
usermanual-install-harfbuzz.xml \
usermanual-getting-started.xml \
usermanual-glyph-information.xml \
usermanual-shaping-concepts.xml \
usermanual-object-model.xml \
usermanual-buffers-language-script-and-direction.xml \
usermanual-fonts-and-faces.xml \
usermanual-clusters.xml \
usermanual-opentype-features.xml \
usermanual-glyph-information.xml \
usermanual-clusters.xml \
usermanual-utilities.xml \
version.xml
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded

View file

@ -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>
@ -37,11 +33,12 @@
<xi:include href="usermanual-install-harfbuzz.xml"/>
<xi:include href="usermanual-getting-started.xml"/>
<xi:include href="usermanual-shaping-concepts.xml"/>
<xi:include href="usermanual-object-model.xml"/>
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
<xi:include href="usermanual-fonts-and-faces.xml"/>
<xi:include href="usermanual-clusters.xml"/>
<xi:include href="usermanual-opentype-features.xml"/>
<xi:include href="usermanual-glyph-information.xml"/>
<xi:include href="usermanual-clusters.xml"/>
<xi:include href="usermanual-utilities.xml"/>
</part>
<part>
@ -136,6 +133,11 @@
<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>
<index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
@ -149,7 +151,6 @@
<index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-4-0" role="1.4.0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
<index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>

View file

@ -1,6 +1,7 @@
<SUBSECTION Private>
HB_H_IN
HB_OT_H_IN
HB_AAT_H_IN
</SECTION>
<SECTION>
@ -124,11 +125,17 @@ hb_script_get_horizontal_direction
hb_language_from_string
hb_language_to_string
hb_language_get_default
hb_feature_from_string
hb_feature_to_string
hb_variation_from_string
hb_variation_to_string
hb_bool_t
hb_codepoint_t
hb_destroy_func_t
hb_direction_t
hb_language_t
hb_feature_t
hb_variation_t
hb_mask_t
hb_position_t
hb_tag_t
@ -147,6 +154,8 @@ HB_DIRECTION_IS_HORIZONTAL
HB_DIRECTION_IS_VALID
HB_DIRECTION_IS_VERTICAL
HB_LANGUAGE_INVALID
HB_FEATURE_GLOBAL_END
HB_FEATURE_GLOBAL_START
<SUBSECTION Private>
HB_BEGIN_DECLS
HB_END_DECLS
@ -171,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
@ -187,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>
@ -208,6 +213,14 @@ hb_coretext_face_get_cg_font
hb_coretext_font_get_ct_font
</SECTION>
<SECTION>
<FILE>hb-directwrite</FILE>
hb_directwrite_face_create
hb_directwrite_face_get_font_face
<SUBSECTION Private>
hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>
<FILE>hb-face</FILE>
hb_face_count
@ -255,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
@ -284,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
@ -321,12 +339,10 @@ hb_font_set_ppem
hb_font_set_ptem
hb_font_set_scale
hb_font_set_user_data
hb_variation_t
hb_variation_from_string
hb_variation_to_string
hb_font_set_variations
hb_font_set_var_coords_design
hb_font_set_var_coords_normalized
hb_font_set_var_named_instance
hb_font_subtract_glyph_origin_for_direction
hb_font_t
hb_reference_table_func_t
@ -354,6 +370,11 @@ 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
@ -527,6 +548,7 @@ 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_collect_lookups
hb_ot_layout_collect_features
hb_ot_layout_feature_get_characters
@ -534,6 +556,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
@ -587,6 +610,22 @@ hb_ot_math_get_min_connector_overlap
hb_ot_math_get_glyph_assembly
</SECTION>
<SECTION>
<FILE>hb-ot-meta</FILE>
hb_ot_meta_t
hb_ot_meta_get_entry_tags
hb_ot_meta_reference_entry
</SECTION>
<SECTION>
<FILE>hb-ot-metrics</FILE>
hb_ot_metrics_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
@ -649,11 +688,6 @@ hb_set_union
<SECTION>
<FILE>hb-shape</FILE>
HB_FEATURE_GLOBAL_END
HB_FEATURE_GLOBAL_START
hb_feature_t
hb_feature_from_string
hb_feature_to_string
hb_shape
hb_shape_full
hb_shape_list_shapers
@ -715,8 +749,6 @@ hb_unicode_script_func_t
<FILE>hb-uniscribe</FILE>
hb_uniscribe_font_get_hfont
hb_uniscribe_font_get_logfontw
<SUBSECTION Private>
hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>

View file

@ -7,30 +7,38 @@
<chapter id="buffers-language-script-and-direction">
<title>Buffers, language, script and direction</title>
<para>
The input to HarfBuzz is a series of Unicode characters, stored in a
The input to the HarfBuzz shaper is a series of Unicode characters, stored in a
buffer. In this chapter, we'll look at how to set up a buffer with
the text that we want and then customize the properties of the
buffer.
the text that we want and how to customize the properties of the
buffer. We'll also look at a piece of lower-level machinery that
you will need to understand before proceeding: the functions that
HarfBuzz uses to retrieve Unicode information.
</para>
<para>
After shaping is complete, HarfBuzz puts its output back
into the buffer. But getting that output requires setting up a
face and a font first, so we will look at that in the next chapter
instead of here.
</para>
<section id="creating-and-destroying-buffers">
<title>Creating and destroying buffers</title>
<para>
As we saw in our <emphasis>Getting Started</emphasis> example, a
buffer is created and
initialized with <literal>hb_buffer_create()</literal>. This
initialized with <function>hb_buffer_create()</function>. This
produces a new, empty buffer object, instantiated with some
default values and ready to accept your Unicode strings.
</para>
<para>
HarfBuzz manages the memory of objects (such as buffers) that it
creates, so you don't have to. When you have finished working on
a buffer, you can call <literal>hb_buffer_destroy()</literal>:
a buffer, you can call <function>hb_buffer_destroy()</function>:
</para>
<programlisting language="C">
hb_buffer_t *buffer = hb_buffer_create();
...
hb_buffer_destroy(buffer);
</programlisting>
hb_buffer_t *buf = hb_buffer_create();
...
hb_buffer_destroy(buf);
</programlisting>
<para>
This will destroy the object and free its associated memory -
unless some other part of the program holds a reference to this
@ -39,46 +47,364 @@
else destroying it, you should increase its reference count:
</para>
<programlisting language="C">
void somefunc(hb_buffer_t *buffer) {
buffer = hb_buffer_reference(buffer);
...
</programlisting>
void somefunc(hb_buffer_t *buf) {
buf = hb_buffer_reference(buf);
...
</programlisting>
<para>
And then decrease it once you're done with it:
</para>
<programlisting language="C">
hb_buffer_destroy(buffer);
}
</programlisting>
hb_buffer_destroy(buf);
}
</programlisting>
<para>
While we are on the subject of reference-counting buffers, it is
worth noting that an individual buffer can only meaningfully be
used by one thread at a time.
</para>
<para>
To throw away all the data in your buffer and start from scratch,
call <literal>hb_buffer_reset(buffer)</literal>. If you want to
call <function>hb_buffer_reset(buf)</function>. If you want to
throw away the string in the buffer but keep the options, you can
instead call <literal>hb_buffer_clear_contents(buffer)</literal>.
instead call <function>hb_buffer_clear_contents(buf)</function>.
</para>
</section>
<section id="adding-text-to-the-buffer">
<title>Adding text to the buffer</title>
<para>
Now we have a brand new HarfBuzz buffer. Let's start filling it
with text! From HarfBuzz's perspective, a buffer is just a stream
of Unicode codepoints, but your input string is probably in one of
the standard Unicode character encodings (UTF-8, UTF-16, UTF-32)
of Unicode code points, but your input string is probably in one of
the standard Unicode character encodings (UTF-8, UTF-16, or
UTF-32). HarfBuzz provides convenience functions that accept
each of these encodings:
<function>hb_buffer_add_utf8()</function>,
<function>hb_buffer_add_utf16()</function>, and
<function>hb_buffer_add_utf32()</function>. Other than the
character encoding they accept, they function identically.
</para>
<para>
You can add UTF-8 text to a buffer by passing in the text array,
the array's length, an offset into the array for the first
character to add, and the length of the segment to add:
</para>
<programlisting language="C">
hb_buffer_add_utf8 (hb_buffer_t *buf,
const char *text,
int text_length,
unsigned int item_offset,
int item_length)
</programlisting>
<para>
So, in practice, you can say:
</para>
<programlisting language="C">
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
</programlisting>
<para>
This will append your new characters to
<parameter>buf</parameter>, not replace its existing
contents. Also, note that you can use <literal>-1</literal> in
place of the first instance of <function>strlen(text)</function>
if your text array is NULL-terminated. Similarly, you can also use
<literal>-1</literal> as the final argument want to add its full
contents.
</para>
<para>
Whatever start <parameter>item_offset</parameter> and
<parameter>item_length</parameter> you provide, HarfBuzz will also
attempt to grab the five characters <emphasis>before</emphasis>
the offset point and the five characters
<emphasis>after</emphasis> the designated end. These are the
before and after "context" segments, which are used internally
for HarfBuzz to make shaping decisions. They will not be part of
the final output, but they ensure that HarfBuzz's
script-specific shaping operations are correct. If there are
fewer than five characters available for the before or after
contexts, HarfBuzz will just grab what is there.
</para>
<para>
For longer text runs, such as full paragraphs, it might be
tempting to only add smaller sub-segments to a buffer and
shape them in piecemeal fashion. Generally, this is not a good
idea, however, because a lot of shaping decisions are
dependent on this context information. For example, in Arabic
and other connected scripts, HarfBuzz needs to know the code
points before and after each character in order to correctly
determine which glyph to return.
</para>
<para>
The safest approach is to add all of the text available, then
use <parameter>item_offset</parameter> and
<parameter>item_length</parameter> to indicate which characters you
want shaped, so that HarfBuzz has access to any context.
</para>
<para>
You can also add Unicode code points directly with
<function>hb_buffer_add_codepoints()</function>. The arguments
to this function are the same as those for the UTF
encodings. But it is particularly important to note that
HarfBuzz does not do validity checking on the text that is added
to a buffer. Invalid code points will be replaced, but it is up
to you to do any deep-sanity checking necessary.
</para>
</section>
<section id="setting-buffer-properties">
<title>Setting buffer properties</title>
<para>
Buffers containing input characters still need several
properties set before HarfBuzz can shape their text correctly.
</para>
</section>
<section id="what-about-the-other-scripts">
<title>What about the other scripts?</title>
<para>
Initially, all buffers are set to the
<literal>HB_BUFFER_CONTENT_TYPE_INVALID</literal> content
type. After adding text, the buffer should be set to
<literal>HB_BUFFER_CONTENT_TYPE_UNICODE</literal> instead, which
indicates that it contains un-shaped input
characters. After shaping, the buffer will have the
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal> content type.
</para>
<para>
<function>hb_buffer_add_utf8()</function> and the
other UTF functions set the content type of their buffer
automatically. But if you are reusing a buffer you may want to
check its state with
<function>hb_buffer_get_content_type(buffer)</function>. If
necessary you can set the content type with
</para>
<programlisting language="C">
hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
</programlisting>
<para>
to prepare for shaping.
</para>
<para>
Buffers also need to carry information about the script,
language, and text direction of their contents. You can set
these properties individually:
</para>
<programlisting language="C">
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
</programlisting>
<para>
However, since these properties are often the repeated for
multiple text runs, you can also save them in a
<literal>hb_segment_properties_t</literal> for reuse:
</para>
<programlisting language="C">
hb_segment_properties_t *savedprops;
hb_buffer_get_segment_properties (buf, savedprops);
...
hb_buffer_set_segment_properties (buf2, savedprops);
</programlisting>
<para>
HarfBuzz also provides getter functions to retrieve a buffer's
direction, script, and language properties individually.
</para>
<para>
HarfBuzz recognizes four text directions in
<type>hb_direction_t</type>: left-to-right
(<literal>HB_DIRECTION_LTR</literal>), right-to-left (<literal>HB_DIRECTION_RTL</literal>),
top-to-bottom (<literal>HB_DIRECTION_TTB</literal>), and
bottom-to-top (<literal>HB_DIRECTION_BTT</literal>). For the
script property, HarfBuzz uses identifiers based on the
<ulink
url="https://unicode.org/iso15924/">ISO 15924
standard</ulink>. For languages, HarfBuzz uses tags based on the
<ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
</para>
<para>
Helper functions are provided to convert character strings into
the necessary script and language tag types.
</para>
<para>
Two additional buffer properties to be aware of are the
"invisible glyph" and the replacement code point. The
replacement code point is inserted into buffer output in place of
any invalid code points encountered in the input. By default, it
is the Unicode <literal>REPLACEMENT CHARACTER</literal> code
point, <literal>U+FFFD</literal> "&#xFFFD;". You can change this with
</para>
<programlisting language="C">
hb_buffer_set_replacement_codepoint(buf, replacement);
</programlisting>
<para>
passing in the replacement Unicode code point as the
<parameter>replacement</parameter> parameter.
</para>
<para>
The invisible glyph is used to replace all output glyphs that
are invisible. By default, the standard space character
<literal>U+0020</literal> is used; you can replace this (for
example, when using a font that provides script-specific
spaces) with
</para>
<programlisting language="C">
hb_buffer_set_invisible_glyph(buf, replacement_glyph);
</programlisting>
<para>
Do note that in the <parameter>replacement_glyph</parameter>
parameter, you must provide the glyph ID of the replacement you
wish to use, not the Unicode code point.
</para>
<para>
HarfBuzz supports a few additional flags you might want to set
on your buffer under certain circumstances. The
<literal>HB_BUFFER_FLAG_BOT</literal> and
<literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
that the buffer represents the beginning or end (respectively)
of a text element (such as a paragraph or other block). Knowing
this allows HarfBuzz to apply certain contextual font features
when shaping, such as initial or final variants in connected
scripts.
</para>
<para>
<literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
tells HarfBuzz not to hide glyphs with the
<literal>Default_Ignorable</literal> property in Unicode. This
property designates control characters and other non-printing
code points, such as joiners and variation selectors. Normally
HarfBuzz replaces them in the output buffer with zero-width
space glyphs (using the "invisible glyph" property discussed
above); setting this flag causes them to be printed, which can
be helpful for troubleshooting.
</para>
<para>
Conversely, setting the
<literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
tells HarfBuzz to remove <literal>Default_Ignorable</literal>
glyphs from the output buffer entirely. Finally, setting the
<literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
flag tells HarfBuzz not to insert the dotted-circle glyph
(<literal>U+25CC</literal>, "&#x25CC;"), which is normally
inserted into buffer output when broken character sequences are
encountered (such as combining marks that are not attached to a
base character).
</para>
</section>
<section id="customizing-unicode-functions">
<title>Customizing Unicode functions</title>
<para>
HarfBuzz requires some simple functions for accessing
information from the Unicode Character Database (such as the
<literal>General_Category</literal> (gc) and
<literal>Script</literal> (sc) properties) that is useful
for shaping, as well as some useful operations like composing and
decomposing code points.
</para>
<para>
HarfBuzz includes its own internal, lightweight set of Unicode
functions. At build time, it is also possible to compile support
for some other options, such as the Unicode functions provided
by GLib or the International Components for Unicode (ICU)
library. Generally, this option is only of interest for client
programs that have specific integration requirements or that do
a significant amount of customization.
</para>
<para>
If your program has access to other Unicode functions, however,
such as through a system library or application framework, you
might prefer to use those instead of the built-in
options. HarfBuzz supports this by implementing its Unicode
functions as a set of virtual methods that you can replace —
without otherwise affecting HarfBuzz's functionality.
</para>
<para>
The Unicode functions are specified in a structure called
<literal>unicode_funcs</literal> which is attached to each
buffer. But even though <literal>unicode_funcs</literal> is
associated with a <type>hb_buffer_t</type>, the functions
themselves are called by other HarfBuzz APIs that access
buffers, so it would be unwise for you to hook different
functions into different buffers.
</para>
<para>
In addition, you can mark your <literal>unicode_funcs</literal>
as immutable by calling
<function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
This is especially useful if your code is a
library or framework that will have its own client programs. By
marking your Unicode function choices as immutable, you prevent
your own client programs from changing the
<literal>unicode_funcs</literal> configuration and introducing
inconsistencies and errors downstream.
</para>
<para>
You can retrieve the Unicode-functions configuration for
your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
</para>
<programlisting language="C">
hb_unicode_funcs_t *ufunctions;
ufunctions = hb_buffer_get_unicode_funcs(buf);
</programlisting>
<para>
The current version of <literal>unicode_funcs</literal> uses six functions:
</para>
<itemizedlist>
<listitem>
<para>
<function>hb_unicode_combining_class_func_t</function>:
returns the Canonical Combining Class of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_general_category_func_t</function>:
returns the General Category (gc) of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_mirroring_func_t</function>: returns
the Mirroring Glyph code point (for bi-directional
replacement) of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_script_func_t</function>: returns the
Script (sc) property of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_compose_func_t</function>: returns the
canonical composition of a sequence of two code points.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_decompose_func_t</function>: returns
the canonical decomposition of a code point.
</para>
</listitem>
</itemizedlist>
<para>
Note, however, that future HarfBuzz releases may alter this set.
</para>
<para>
Each Unicode function has a corresponding setter, with which you
can assign a callback to your replacement function. For example,
to replace
<function>hb_unicode_general_category_func_t</function>, you can call
</para>
<programlisting language="C">
hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)
</programlisting>
<para>
Virtualizing this set of Unicode functions is primarily intended
to improve portability. There is no need for every client
program to make the effort to replace the default options, so if
you are unsure, do not feel any pressure to customize
<literal>unicode_funcs</literal>.
</para>
</section>
</chapter>

View file

@ -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>
@ -492,7 +494,7 @@
</para>
<para>
But this initial cluster-merging behavior makes it impossible
client programs to implement some features (such as to
for client programs to implement some features (such as to
color diacritic marks differently from their base
characters). That is why, in level 1, HarfBuzz does not perform
the initial merging step.
@ -684,7 +686,7 @@
<para>
There may be other problems encountered with ligatures under
level 2, such as if the direction of the text is forced to
opposite of its natural direction (for example, Arabic text
the opposite of its natural direction (for example, Arabic text
that is forced into left-to-right directionality). But,
generally speaking, these other scenarios are minor corner
cases that are too obscure for most client programs to need to

View file

@ -5,20 +5,449 @@
<!ENTITY version SYSTEM "version.xml">
]>
<chapter id="fonts-and-faces">
<title>Fonts and faces</title>
<section id="using-freetype">
<title>Fonts, faces, and output</title>
<para>
In the previous chapter, we saw how to set up a buffer and fill
it with text as Unicode code points. In order to shape this
buffer text with HarfBuzz, you will need also need a font
object.
</para>
<para>
HarfBuzz provides abstractions to help you cache and reuse the
heavier parts of working with binary fonts, so we will look at
how to do that. We will also look at how to work with the
FreeType font-rendering library and at how you can customize
HarfBuzz to work with other libraries.
</para>
<para>
Finally, we will look at how to work with OpenType variable
fonts, the latest update to the OpenType font format, and at
some other recent additions to OpenType.
</para>
<section id="fonts-and-faces-objects">
<title>Font and face objects</title>
<para>
The outcome of shaping a run of text depends on the contents of
a specific font file (such as the substitutions and positioning
moves in the 'GSUB' and 'GPOS' tables), so HarfBuzz makes
accessing those internals fast.
</para>
<para>
An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
in HarfBuzz. This data type is a wrapper around an
<type>hb_blob_t</type> blob that holds the contents of a binary
font file. Since HarfBuzz supports TrueType Collections and
OpenType Collections (each of which can include multiple
typefaces), a HarfBuzz face also requires an index number
specifying which typeface in the file you want to use. Most of
the font files you will encounter in the wild include just a
single face, however, so most of the time you would pass in
<literal>0</literal> as the index when you create a face:
</para>
<programlisting language="C">
hb_blob_t* blob = hb_blob_create_from_file(file);
...
hb_face_t* face = hb_face_create(blob, 0);
</programlisting>
<para>
On its own, a face object is not quite ready to use for
shaping. The typeface must be set to a specific point size in
order for some details (such as hinting) to work. In addition,
if the font file in question is an OpenType Variable Font, then
you may need to specify one or variation-axis settings (or a
named instance) in order to get the output you need.
</para>
<para>
In HarfBuzz, you do this by creating a <emphasis>font</emphasis>
object from your face.
</para>
<para>
Font objects also have the advantage of being considerably
lighter-weight than face objects (remember that a face contains
the contents of a binary font file mapped into memory). As a
result, you can cache and reuse a font object, but you could
also create a new one for each additional size you needed.
Creating new fonts incurs some additional overhead, of course,
but whether or not it is excessive is your call in the end. In
contrast, face objects are substantially larger, and you really
should cache them and reuse them whenever possible.
</para>
<para>
You can create a font object from a face object:
</para>
<programlisting language="C">
hb_font_t* hb_font = hb_font_create(hb_face);
</programlisting>
<para>
After creating a font, there are a few properties you should
set. Many fonts enable and disable hints based on the size it
is used at, so setting this is important for font
objects. <function>hb_font_set_ppem(font, x_ppem,
y_ppem)</function> sets the pixels-per-EM value of the font. You
can also set the point size of the font with
<function>hb_font_set_ptem(font, ptem)</function>. HarfBuzz uses the
industry standard 72 points per inch.
</para>
<para>
HarfBuzz lets you specify the degree subpixel precision you want
through a scaling factor. You can set horizontal and
vertical scaling factors on the
font by calling <function>hb_font_set_scale(font, x_scale,
y_scale)</function>.
</para>
<para>
There may be times when you are handed a font object and need to
access the face object that it comes from. For that, you can call
</para>
<programlisting language="C">
hb_face = hb_font_get_face(hb_font);
</programlisting>
<para>
You can also create a font object from an existing font object
using the <function>hb_font_create_sub_font()</function>
function. This creates a child font object that is initiated
with the same attributes as its parent; it can be used to
quickly set up a new font for the purpose of overriding a specific
font-functions method.
</para>
<para>
All face objects and font objects are lifecycle-managed by
HarfBuzz. After creating a face, you increase its reference
count with <function>hb_face_reference(face)</function> and
decrease it with
<function>hb_face_destroy(face)</function>. Likewise, you
increase the reference count on a font with
<function>hb_font_reference(font)</function> and decrease it
with <function>hb_font_destroy(font)</function>.
</para>
<para>
You can also attach user data to face objects and font objects.
</para>
</section>
<section id="fonts-and-faces-custom-functions">
<title>Customizing font functions</title>
<para>
During shaping, HarfBuzz frequently needs to query font objects
to get at the contents and parameters of the glyphs in a font
file. It includes a built-in set of functions that is tailored
to working with OpenType fonts. However, as was the case with
Unicode functions in the buffers chapter, HarfBuzz also wants to
make it easy for you to assign a substitute set of font
functions if you are developing a program to work with a library
or platform that provides its own font functions.
</para>
<para>
Therefore, the HarfBuzz API defines a set of virtual
methods for accessing font-object properties, and you can
replace the defaults with your own selections without
interfering with the shaping process. Each font object in
HarfBuzz includes a structure called
<literal>font_funcs</literal> that serves as a vtable for the
font object. The virtual methods in
<literal>font_funcs</literal> are:
</para>
<itemizedlist>
<listitem>
<para>
<function>hb_font_get_font_h_extents_func_t</function>: returns
the extents of the font for horizontal text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_font_v_extents_func_t</function>: returns
the extents of the font for vertical text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_nominal_glyph_func_t</function>: returns
the font's nominal glyph for a given code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_variation_glyph_func_t</function>: returns
the font's glyph for a given code point when it is followed by a
given Variation Selector.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_nominal_glyphs_func_t</function>: returns
the font's nominal glyphs for a series of code points.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_advance_func_t</function>: returns
the advance for a glyph.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_h_advance_func_t</function>: returns
the advance for a glyph for horizontal text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_v_advance_func_t</function>:returns
the advance for a glyph for vertical text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_advances_func_t</function>: returns
the advances for a series of glyphs.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_h_advances_func_t</function>: returns
the advances for a series of glyphs for horizontal text .
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_v_advances_func_t</function>: returns
the advances for a series of glyphs for vertical text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_origin_func_t</function>: returns
the origin coordinates of a glyph.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_h_origin_func_t</function>: returns
the origin coordinates of a glyph for horizontal text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_v_origin_func_t</function>: returns
the origin coordinates of a glyph for vertical text.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_extents_func_t</function>: returns
the extents for a glyph.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_contour_point_func_t</function>:
returns the coordinates of a specific contour point from a glyph.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_name_func_t</function>: returns the
name of a glyph (from its glyph index).
</para>
</listitem>
<listitem>
<para>
<function>hb_font_get_glyph_from_name_func_t</function>: returns
the glyph index that corresponds to a given glyph name.
</para>
</listitem>
</itemizedlist>
<para>
You can fetch the font-functions configuration for a font object
by calling <function>hb_font_get_font_funcs()</function>:
</para>
<programlisting language="C">
hb_font_funcs_t *ffunctions;
ffunctions = hb_font_get_font_funcs (font);
</programlisting>
<para>
The individual methods can each be replaced with their own setter
function, such as
<function>hb_font_funcs_set_nominal_glyph_func(*ffunctions,
func, *user_data, destroy)</function>.
</para>
<para>
Font-functions structures can be reused for multiple font
objects, and can be reference counted with
<function>hb_font_funcs_reference()</function> and
<function>hb_font_funcs_destroy()</function>. Just like other
objects in HarfBuzz, you can set user-data for each
font-functions structure and assign a destroy callback for
it.
</para>
<para>
You can also mark a font-functions structure as immutable,
with <function>hb_font_funcs_make_immutable()</function>. This
is especially useful if your code is a library or framework that
will have its own client programs. By marking your
font-functions structures as immutable, you prevent your client
programs from changing the configuration and introducing
inconsistencies and errors downstream.
</para>
</section>
<section id="fonts-and-faces-native-opentype">
<title>Font objects and HarfBuzz's native OpenType implementation</title>
<para>
By default, whenever HarfBuzz creates a font object, it will
configure the font to use a built-in set of font functions that
supports contemporary OpenType font internals. If you want to
work with OpenType or TrueType fonts, you should be able to use
these functions without difficulty.
</para>
<para>
Many of the methods in the font-functions structure deal with
the fundamental properties of glyphs that are required for
shaping text: extents (the maximums and minimums on each axis),
origins (the <literal>(0,0)</literal> coordinate point which
glyphs are drawn in reference to), and advances (the amount that
the cursor needs to be moved after drawing each glyph, including
any empty space for the glyph's side bearings).
</para>
<para>
As you can see in the list of functions, there are separate "horizontal"
and "vertical" variants depending on whether the text is set in
the horizontal or vertical direction. For some scripts, fonts
that are designed to support text set horizontally or vertically (for
example, in Japanese) may include metrics for both text
directions. When fonts don't include this information, HarfBuzz
does its best to transform what the font provides.
</para>
<para>
In addition to the direction-specific functions, HarfBuzz
provides some higher-level functions for fetching information
like extents and advances for a glyph. If you call
</para>
<programlisting language="C">
hb_font_get_glyph_advance_for_direction(font, direction, extents);
</programlisting>
<para>
then you can provide any <type>hb_direction_t</type> as the
<parameter>direction</parameter> parameter, and HarfBuzz will
use the correct function variant for the text direction. There
are similar higher-level versions of the functions for fetching
extents, origin coordinates, and contour-point
coordinates. There are also addition and subtraction functions
for moving points with respect to the origin.
</para>
<para>
There are also methods for fetching the glyph ID that
corresponds to a Unicode code point (possibly when followed by a
variation-selector code point), fetching the glyph name from the
font, and fetching the glyph ID that corresponds to a glyph name
you already have.
</para>
<para>
HarfBuzz also provides functions for converting between glyph
names and string
variables. <function>hb_font_glyph_to_string(font, glyph, s,
size)</function> retrieves the name for the glyph ID
<parameter>glyph</parameter> from the font object. It generates a
generic name of the form <literal>gidDDD</literal> (where DDD is
the glyph index) if there is no name for the glyph in the
font. The <function>hb_font_glyph_from_string(font, s, len,
glyph)</function> takes an input string <parameter>s</parameter>
and looks for a glyph with that name in the font, returning its
glyph ID in the <parameter>glyph</parameter>
output parameter. It automatically parses
<literal>gidDDD</literal> and <literal>uniUUUU</literal> strings.
</para>
</section>
<!-- Commenting out FreeType integration section-holder for now. May move
to the full-blown Integration Chapter. -->
<!-- <section id="fonts-and-faces-freetype">
<title>Using FreeType</title>
<para>
</para>
</section>
<section id="using-harfbuzzs-native-opentype-implementation">
<title>Using HarfBuzz's native OpenType implementation</title>
<para>
</para>
</section>
<section id="using-your-own-font-functions">
<title>Using your own font functions</title>
</section> -->
<section id="fonts-and-faces-variable">
<title>Working with OpenType Variable Fonts</title>
<para>
If you are working with OpenType Variable Fonts, there are a few
additional functions you should use to specify the
variation-axis settings of your font object. Without doing so,
your variable font's font object can still be used, but only at
the default setting for every axis (which, of course, is
sometimes what you want, but does not cover general usage).
</para>
<para>
HarfBuzz manages variation settings in the
<type>hb_variation_t</type> data type, which holds a <property>tag</property> for the
variation-axis identifier tag and a <property>value</property> for its
setting. You can retrieve the list of variation axes in a font
binary from the face object (not from a font object, notably) by
calling <function>hb_ot_var_get_axis_count(face)</function> to
find the number of axes, then using
<function>hb_ot_var_get_axis_infos()</function> to collect the
axis structures:
</para>
<programlisting language="C">
axes = hb_ot_var_get_axis_count(face);
...
hb_ot_var_get_axis_infos(face, 0, axes, axes_array);
</programlisting>
<para>
For each axis returned in the array, you can can access the
identifier in its <property>tag</property>. HarfBuzz also has
tag definitions predefined for the five standard axes specified
in OpenType (<literal>ital</literal> for italic,
<literal>opsz</literal> for optical size,
<literal>slnt</literal> for slant, <literal>wdth</literal> for
width, and <literal>wght</literal> for weight). Each axis also
has a <property>min_value</property>, a
<property>default_value</property>, and a <property>max_value</property>.
</para>
<para>
To set your font object's variation settings, you call the
<function>hb_font_set_variations()</function> function with an
array of <type>hb_variation_t</type> variation settings. Let's
say our font has weight and width axes. We need to specify each
of the axes by tag and assign a value on the axis:
</para>
<programlisting language="C">
unsigned int variation_count = 2;
hb_variation_t variation_data[variation_count];
variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WIDTH;
variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
variation_data[0].value = 80;
variation_data[1].value = 750;
...
hb_font_set_variations(font, variation_data, variation_count);
</programlisting>
<para>
That should give us a slightly condensed font ("normal" on the
<literal>wdth</literal> axis is 100) at a noticeably bolder
weight ("regular" is 400 on the <literal>wght</literal> axis).
</para>
<para>
In practice, though, you should always check that the value you
want to set on the axis is within the
[<property>min_value</property>,<property>max_value</property>]
range actually implemented in the font's variation axis. After
all, a font might only provide lighter-than-regular weights, and
setting a heavier value on the <literal>wght</literal> axis will
not change that.
</para>
<para>
Once your variation settings are specified on your font object,
however, shaping with a variable font is just like shaping a
static font.
</para>
</section>
</chapter>
</chapter>

View file

@ -223,7 +223,7 @@
<orderedlist numeration="arabic">
<listitem override="2">
<para>
Guess the script, language and direction of the buffer.
Set the script, language and direction of the buffer.
</para>
</listitem>
</orderedlist>
@ -275,14 +275,14 @@
</orderedlist>
<programlisting language="C">
for (i = 0; i &lt; glyph_count; ++i) {
glyphid = glyph_info[i].codepoint;
x_offset = glyph_pos[i].x_offset / 64.0;
y_offset = glyph_pos[i].y_offset / 64.0;
x_advance = glyph_pos[i].x_advance / 64.0;
y_advance = glyph_pos[i].y_advance / 64.0;
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
cursor_x += x_advance;
cursor_y += y_advance;
glyphid = glyph_info[i].codepoint;
x_offset = glyph_pos[i].x_offset / 64.0;
y_offset = glyph_pos[i].y_offset / 64.0;
x_advance = glyph_pos[i].x_advance / 64.0;
y_advance = glyph_pos[i].y_advance / 64.0;
draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset);
cursor_x += x_advance;
cursor_y += y_advance;
}
</programlisting>
<orderedlist numeration="arabic">

View file

@ -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,13 +398,25 @@
<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.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>--enable-gtk-doc</command></term>
<listitem>
<para>
Use <ulink url="https://www.gtk.org/gtk-doc/">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
</para>
<para>
This option enables the building of the documentation.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>

View file

@ -0,0 +1,258 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY version SYSTEM "version.xml">
]>
<chapter id="object-model">
<title>The HarfBuzz object model</title>
<section id="object-model-intro">
<title>An overview of data types in HarfBuzz</title>
<para>
HarfBuzz features two kinds of data types: non-opaque,
pass-by-value types and opaque, heap-allocated types. This kind
of separation is common in C libraries that have to provide
API/ABI compatibility (almost) indefinitely.
</para>
<para>
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
types include integer types, enums, and small structs. Exposing
a struct in the public API makes it impossible to expand the
struct in the future. As such, exposing structs is reserved for
cases where its extremely inefficient to do otherwise.
</para>
<para>
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
category and are non-opaque.
</para>
<para>
For all non-opaque structs where future extensibility may be
necessary, reserved members are included to hold space for
possible future members. As such, its important to provide
<function>equal()</function>, and <function>hash()</function>
methods for such structs, allowing users of the API do
effectively deal with the type without having to
adapt their code to future changes.
</para>
<para>
Important value types provided by HarfBuzz include the structs
for working with Unicode code points, glyphs, and tags for font
tables and features, as well as the enums for many Unicode and
OpenType properties.
</para>
</section>
<section id="object-model-object-types">
<title>Objects in HarfBuzz</title>
<para>
<emphasis>Object types:</emphasis> Opaque struct types are used
for what HarfBuzz loosely calls "objects." This doesnt have
much to do with the terminology from object-oriented programming
(OOP), although some of the concepts are similar.
</para>
<para>
In HarfBuzz, all object types provide certain
lifecycle-management APIs. Objects are reference-counted, and
constructed with various <function>create()</function> methods, referenced via
<function>reference()</function> and dereferenced using
<function>destroy()</function>.
</para>
<para>
For example,
the <literal>hb_buffer_t</literal> object has
<function>hb_buffer_create()</function> as its constructor,
<function>hb_buffer_reference()</function> to reference, and
<function>hb_buffer_destroy()</function> to dereference.
</para>
<para>
After construction, each object's properties are accessible only
through the setter and getter functions described in the API
Reference manual.
</para>
<para>
Key object types provided by HarfBuzz include:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
data. Blobs are typically used to hold the contents of a
binary font file.
</para>
</listitem>
<listitem>
<para>
<emphasis>faces</emphasis>, which represent typefaces from a
font file, but without specific parameters (such as size) set.
</para>
</listitem>
<listitem>
<para>
<emphasis>fonts</emphasis>, which represent instances of a
face with all of their parameters specified.
</para>
</listitem>
<listitem>
<para>
<emphasis>buffers</emphasis>, which hold Unicode code points
for characters (before shaping) and the shaped glyph output
(after shaping).
</para>
</listitem>
<listitem>
<para>
<emphasis>shape plans</emphasis>, which store the settings
that HarfBuzz will use when shaping a particular text
segment. Shape plans are not generally used by client
programs directly, but as we will see in a later chapter,
they are still valuable to understand.
</para>
</listitem>
</itemizedlist>
</section>
<section id="object-model-lifecycle">
<title>Object lifecycle management</title>
<para>
Each object type in HarfBuzz provides a
<function>create()</function> method. Some object types provide
additional variants of <function>create()</function> to handle
special cases or to speed up common tasks; those variants are
documented in the API reference. For example,
<function>hb_blob_create_from_file()</function> constructs a new
blob directly from the contents of a file.
</para>
<para>
All objects are created with an initial reference count of
<literal>1</literal>. Client programs can increase the reference
count on an object by calling its
<function>reference()</function> method. Whenever a client
program is finished with an object, it should call its
corresponding <function>destroy()</function> method. The destroy
method will decrease the reference count on the object and,
whenever the reference count reaches zero, it will also destroy
the object and free all of the associated memory.
</para>
<para>
All of HarfBuzz's object-lifecycle-management APIs are
thread-safe (unless you compiled HarfBuzz from source with the
<literal>HB_NO_MT</literal> configuration flag), even when the
object as a whole is not thread-safe.
It is also permissible to <function>reference()</function> or to
<function>destroy()</function> the <literal>NULL</literal>
value.
</para>
<para>
Some objects are thread-safe after they have been constructed
and set up. The general pattern is to
<function>create()</function> the object, make a few
<function>set_*()</function> calls to set up the
object, and then use it without further modification.
</para>
<para>
To ensure that such an object is not modified, client programs
can explicitly mark an object as immutable. HarfBuzz provides
<function>make_immutable()</function> methods to mark an object
as immutable and <function>is_immutable()</function> methods to
test whether or not an object is immutable. Attempts to use
setter functions on immutable objects will fail silently; see the API
Reference manual for specifics.
</para>
<para>
Note also that there are no "make mutable" methods. If client
programs need to alter an object previously marked as immutable,
they will need to make a duplicate of the original.
</para>
<para>
Finally, object constructors (and, indeed, as much of the
shaping API as possible) will never return
<literal>NULL</literal>. Instead, if there is an allocation
error, each constructor will return an “empty” object
singleton.
</para>
<para>
These empty-object singletons are inert and safe (although
typically useless) to pass around. This design choice avoids
having to check for <literal>NULL</literal> pointers all
throughout the code.
</para>
<para>
In addition, this “empty” object singleton can also be accessed
using the <function>get_empty()</function> method of the object
type in question.
</para>
</section>
<section id="object-model-user-data">
<title>User data</title>
<para>
To better integrate with client programs, HarfBuzz's objects
offer a "user data" mechanism that can be used to attach
arbitrary data to the object. User-data attachment can be
useful for tying the lifecycles of various pieces of data
together, or for creating language bindings.
</para>
<para>
Each object type has a <function>set_user_data()</function>
method and a <function>get_user_data()</function> method. The
<function>set_user_data()</function> methods take a client-provided
<literal>key</literal> and a pointer,
<literal>user_data</literal>, pointing to the data itself. Once
the key-data pair has been attached to the object, the
<function>get_user_data()</function> method can be called with
the key, returning the <function>user_data</function> pointer.
</para>
<para>
The <function>set_user_data()</function> methods also support an
optional <function>destroy</function> callback. Client programs
can set the <function>destroy</function> callback and receive
notification from HarfBuzz whenever the object is destructed.
</para>
<para>
Finally, each <function>set_user_data()</function> method allows
the client program to set a <literal>replace</literal> Boolean
indicating whether or not the function call should replace any
existing <literal>user_data</literal>
associated with the specified key.
</para>
</section>
<section id="object-model-blobs">
<title>Blobs</title>
<para>
While most of HarfBuzz's object types are specific to the
shaping process, <emphasis>blobs</emphasis> are somewhat
different.
</para>
<para>
Blobs are an abstraction desgined to negotiate lifecycle and
permissions for raw pieces of data. For example, when you load
the raw font data into memory and want to pass it to HarfBuzz,
you do so in a <literal>hb_blob_t</literal> wrapper.
</para>
<para>
This allows you to take advantage of HarffBuzz's
reference-counting and <function>destroy</function>
callbacks. If you allocated the memory for the data using
<function>malloc()</function>, you would create the blob using
</para>
<programlisting language="C">
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, NULL, free)
</programlisting>
<para>
That way, HarfBuzz will call <function>free()</function> on the
allocated memory whenever the blob drops its last reference and
is deconstructed. Consequently, the user code can stop worrying
about freeing memory and let the reference-counting machinery
take care of that.
</para>
</section>
</chapter>

View file

@ -6,14 +6,299 @@
]>
<chapter id="shaping-and-shape-plans">
<title>Shaping and shape plans</title>
<section id="opentype-features">
<para>
Once you have your face and font objects configured as desired and
your input buffer is filled with the characters you need to shape,
all you need to do is call <function>hb_shape()</function>.
</para>
<para>
HarfBuzz will return the shaped version of the text in the same
buffer that you provided, but it will be in output mode. At that
point, you can iterate through the glyphs in the buffer, drawing
each one at the specified position or handing them off to the
appropriate graphics library.
</para>
<para>
For the most part, HarfBuzz's shaping step is straightforward from
the outside. But that doesn't mean there will never be cases where
you want to look under the hood and see what is happening on the
inside. HarfBuzz provides facilities for doing that, too.
</para>
<section id="shaping-buffer-output">
<title>Shaping and buffer output</title>
<para>
The <function>hb_shape()</function> function call takes four arguments: the font
object to use, the buffer of characters to shape, an array of
user-specified features to apply, and the length of that feature
array. The feature array can be NULL, so for the sake of
simplicity we will start with that case.
</para>
<para>
Internally, HarfBuzz looks at the tables of the font file to
determine where glyph classes, substitutions, and positioning
are defined, using that information to decide which
<emphasis>shaper</emphasis> to use (<literal>ot</literal> for
OpenType fonts, <literal>aat</literal> for Apple Advanced
Typography fonts, and so on). It also looks at the direction,
script, and language properties of the segment to figure out
which script-specific shaping model is needed (at least, in
shapers that support multiple options).
</para>
<para>
If a font has a GDEF table, then that is used for
glyph classes; if not, HarfBuzz will fall back to Unicode
categorization by code point. If a font has an AAT "morx" table,
then it is used for substitutions; if not, but there is a GSUB
table, then the GSUB table is used. If the font has an AAT
"kerx" table, then it is used for positioning; if not, but
there is a GPOS table, then the GPOS table is used. If neither
table is found, but there is a "kern" table, then HarfBuzz will
use the "kern" table. If there is no "kerx", no GPOS, and no
"kern", HarfBuzz will fall back to positioning marks itself.
</para>
<para>
With a well-behaved OpenType font, you expect GDEF, GSUB, and
GPOS tables to all be applied. HarfBuzz implements the
script-specific shaping models in internal functions, rather
than in the public API.
</para>
<para>
The algorithms
used for complex scripts can be quite involved; HarfBuzz tries
to be compatible with the OpenType Layout specification
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
output of Microsoft's Uniscribe engine. See the <ulink
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
Typography pages</ulink> for more detail.
</para>
<para>
In general, though, all that you need to know is that
<function>hb_shape()</function> returns the results of shaping
in the same buffer that you provided. The buffer's content type
will now be set to
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
that it contains shaped output, rather than input text. You can
now extract the glyph information and positioning arrays:
</para>
<programlisting language="C">
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
<para>
The glyph information array holds a <type>hb_glyph_info_t</type>
for each output glyph, which has two fields:
<parameter>codepoint</parameter> and
<parameter>cluster</parameter>. Whereas, in the input buffer,
the <parameter>codepoint</parameter> field contained the Unicode
code point, it now contains the glyph ID of the corresponding
glyph in the font. The <parameter>cluster</parameter> field is
an integer that you can use to help identify when shaping has
reordered, split, or combined code points; we will say more
about that in the next chapter.
</para>
<para>
The glyph positions array holds a corresponding
<type>hb_glyph_position_t</type> for each output glyph,
containing four fields: <parameter>x_advance</parameter>,
<parameter>y_advance</parameter>,
<parameter>x_offset</parameter>, and
<parameter>y_offset</parameter>. The advances tell you how far
you need to move the drawing point after drawing this glyph,
depending on whether you are setting horizontal text (in which
case you will have x advances) or vertical text (for which you
will have y advances). The x and y offsets tell you where to
move to start drawing the glyph; usually you will have both and
x and a y offset, regardless of the text direction.
</para>
<para>
Most of the time, you will rely on a font-rendering library or
other graphics library to do the actual drawing of glyphs, so
you will need to iterate through the glyphs in the buffer and
pass the corresponding values off.
</para>
</section>
<section id="shaping-opentype-features">
<title>OpenType features</title>
<para>
OpenType features enable fonts to include smart behavior,
implemented as "lookup" rules stored in the GSUB and GPOS
tables. The OpenType specification defines a long list of
standard features that fonts can use for these behaviors; each
feature has a four-character reserved name and a well-defined
semantic meaning.
</para>
<para>
Some OpenType features are defined for the purpose of supporting
complex-script shaping, and are automatically activated, but
only when a buffer's script property is set to a script that the
feature supports.
</para>
<para>
Other features are more generic and can apply to several (or
any) script, and shaping engines are expected to implement
them. By default, HarfBuzz activates several of these features
on every text run. They include <literal>ccmp</literal>,
<literal>locl</literal>, <literal>mark</literal>,
<literal>mkmk</literal>, and <literal>rlig</literal>.
</para>
<para>
In addition, if the text direction is horizontal, HarfBuzz
also applies the <literal>calt</literal>,
<literal>clig</literal>, <literal>curs</literal>,
<literal>kern</literal>, <literal>liga</literal>,
<literal>rclt</literal>, and <literal>frac</literal> features.
</para>
<para>
If the text direction is vertical, HarfBuzz applies
the <literal>vert</literal> feature by default.
</para>
<para>
Still other features are designed to be purely optional and left
up to the application or the end user to enable or disable as desired.
</para>
<para>
You can adjust the set of features that HarfBuzz applies to a
buffer by supplying an array of <type>hb_feature_t</type>
features as the third argument to
<function>hb_shape()</function>. For a simple case, let's just
enable the <literal>dlig</literal> feature, which turns on any
"discretionary" ligatures in the font:
</para>
<programlisting language="C">
hb_feature_t userfeatures[1];
userfeatures[0].tag = HB_TAG('d','l','i','g');
userfeatures[0].value = 1;
userfeatures[0].start = HB_FEATURE_GLOBAL_START;
userfeatures[0].end = HB_FEATURE_GLOBAL_END;
</programlisting>
<para>
<literal>HB_FEATURE_GLOBAL_END</literal> and
<literal>HB_FEATURE_GLOBAL_END</literal> are macros we can use
to indicate that the features will be applied to the entire
buffer. We could also have used a literal <literal>0</literal>
for the start and a <literal>-1</literal> to indicate the end of
the buffer (or have selected other start and end positions, if needed).
</para>
<para>
When we pass the <varname>userfeatures</varname> array to
<function>hb_shape()</function>, any discretionary ligature
substitutions from our font that match the text in our buffer
will get performed:
</para>
<programlisting language="C">
hb_shape(font, buf, userfeatures, num_features);
</programlisting>
<para>
Just like we enabled the <literal>dlig</literal> feature by
setting its <parameter>value</parameter> to
<literal>1</literal>, you would disable a feature by setting its
<parameter>value</parameter> to <literal>0</literal>. Some
features can take other <parameter>value</parameter> settings;
be sure you read the full specification of each feature tag to
understand what it does and how to control it.
</para>
</section>
<section id="plans-and-caching">
<section id="shaping-shaper-selection">
<title>Shaper selection</title>
<para>
The basic version of <function>hb_shape()</function> determines
its shaping strategy based on examining the capabilities of the
font file. OpenType font tables cause HarfBuzz to try the
<literal>ot</literal> shaper, while AAT font tables cause HarfBuzz to try the
<literal>aat</literal> shaper.
</para>
<para>
In the real world, however, a font might include some unusual
mix of tables, or one of the tables might simply be broken for
the script you need to shape. So, sometimes, you might not
want to rely on HarfBuzz's process for deciding what to do, and
just tell <function>hb_shape()</function> what you want it to try.
</para>
<para>
<function>hb_shape_full()</function> is an alternate shaping
function that lets you supply a list of shapers for HarfBuzz to
try, in order, when shaping your buffer. For example, if you
have determined that HarfBuzz's attempts to work around broken
tables gives you better results than the AAT shaper itself does,
you might move the AAT shaper to the end of your list of
preferences and call <function>hb_shape_full()</function>
</para>
<programlisting language="C">
char *shaperprefs[3] = {"ot", "default", "aat"};
...
hb_shape_full(font, buf, userfeatures, num_features, shaperprefs);
</programlisting>
<para>
to get results you are happier with.
</para>
<para>
You may also want to call
<function>hb_shape_list_shapers()</function> to get a list of
the shapers that were built at compile time in your copy of HarfBuzz.
</para>
</section>
<section id="shaping-plans-and-caching">
<title>Plans and caching</title>
<para>
Internally, HarfBuzz uses a structure called a shape plan to
track its decisions about how to shape the contents of a
buffer. The <function>hb_shape()</function> function builds up the shape plan by
examining segment properties and by inspecting the contents of
the font.
</para>
<para>
This process can involve some decision-making and
trade-offs — for example, HarfBuzz inspects the GSUB and GPOS
lookups for the script and language tags set on the segment
properties, but it falls back on the lookups under the
<literal>DFLT</literal> tag (and sometimes other common tags)
if there are actually no lookups for the tag requested.
</para>
<para>
HarfBuzz also includes some work-arounds for
handling well-known older font conventions that do not follow
OpenType or Unicode specifications, for buggy system fonts, and for
peculiarities of Microsoft Uniscribe. All of that means that a
shape plan, while not something that you should edit directly in
client code, still might be an object that you want to
inspect. Furthermore, if resources are tight, you might want to
cache the shape plan that HarfBuzz builds for your buffer and
font, so that you do not have to rebuild it for every shaping call.
</para>
<para>
You can create a cacheable shape plan with
<function>hb_shape_plan_create_cached(face, props,
user_features, num_user_features, shaper_list)</function>, where
<parameter>face</parameter> is a face object (not a font object,
notably), <parameter>props</parameter> is an
<type>hb_segment_properties_t</type>,
<parameter>user_features</parameter> is an array of
<type>hb_feature_t</type>s (with length
<parameter>num_user_features</parameter>), and
<parameter>shaper_list</parameter> is a list of shapers to try.
</para>
<para>
Shape plans are objects in HarfBuzz, so there are
reference-counting functions and user-data attachment functions
you can
use. <function>hb_shape_plan_reference(shape_plan)</function>
increases the reference count on a shape plan, while
<function>hb_shape_plan_destroy(shape_plan)</function> decreases
the reference count, destroying the shape plan when the last
reference is dropped.
</para>
<para>
You can attach user data to a shaper (with a key) using the
<function>hb_shape_plan_set_user_data(shape_plan,key,data,destroy,replace)</function>
function, optionally supplying a <function>destroy</function>
callback to use. You can then fetch the user data attached to a
shape plan with
<function>hb_shape_plan_get_user_data(shape_plan, key)</function>.
</para>
</section>
</chapter>

View file

@ -0,0 +1,244 @@
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
<!ENTITY version SYSTEM "version.xml">
]>
<chapter id="utilities">
<title>Utilities</title>
<para>
HarfBuzz includes several auxiliary components in addition to the
main APIs. These include a set of command-line tools, a set of
lower-level APIs for common data types that may be of interest to
client programs, and an embedded library for working with
Unicode Character Database (UCD) data.
</para>
<section id="utilities-command-line-tools">
<title>Command-line tools</title>
<para>
HarfBuzz include three command-line tools:
<program>hb-shape</program>, <program>hb-view</program>, and
<program>hb-subset</program>. They can be used to examine
HarfBuzz's functionality, debug font binaries, or explore the
various shaping models and features from a terminal.
</para>
<section id="utilities-command-line-hbshape">
<title>hb-shape</title>
<para>
<emphasis><program>hb-shape</program></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
<emphasis>not</emphasis> render the results of the shaping call
into rendered text (you can use <program>hb-view</program>, below, for
that). Instead, it prints out the final glyph indices and
positions, taking all shaping operations into account, as if the
input string were a HarfBuzz input buffer.
</para>
<para>
You can specify the font to be used for shaping and, with
command-line options, you can add various aspects of the
internal state to the output that is sent to the terminal. The
general format is
</para>
<programlisting>
<command>hb-shape</command> <optional>[OPTIONS]</optional>
<parameter>path/to/font/file.ttf</parameter>
<parameter>yourinputtext</parameter>
</programlisting>
<para>
The default output format is plain text (although JSON output
can be selected instead by specifying the option
<optional>--output-format=json</optional>). The default output
syntax reports each glyph name (or glyph index if there is no
name) followed by its cluster value, its horizontal and vertical
position displacement, and its horizontal and vertical advances.
</para>
<para>
Output options exist to skip any of these elements in the
output, and to include additional data, such as Unicode
code-point values, glyph extents, glyph flags, or interim
shaping results.
</para>
<para>
Output can also be redirected to a file, or input read from a
file. Additional options enable you to enable or disable
specific font features, to set variation-font axis values, to
alter the language, script, direction, and clustering settings
used, to enable sanity checks, or to change which shaping engine is used.
</para>
<para>
For a complete explanation of the options available, run
</para>
<programlisting>
<command>hb-shape</command> <parameter>--help</parameter>
</programlisting>
</section>
<section id="utilities-command-line-hbview">
<title>hb-view</title>
<para>
<emphasis><program>hb-view</program></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
as its arguments:
</para>
<programlisting>
<command>hb-view</command> <optional>[OPTIONS]</optional>
<parameter>path/to/font/file.ttf</parameter>
<parameter>yourinputtext</parameter>
</programlisting>
<para>
By default, <program>hb-view</program> renders the shaped
text in ASCII block-character images as terminal output. By
appending the
<command>--output-file=<optional>filename</optional></command>
switch, you can write the output to a PNG, SVG, or PDF file
(among other formats).
</para>
<para>
As with <program>hb-shape</program>, a lengthy set of options
is available, with which you can enable or disable
specific font features, set variation-font axis values,
alter the language, script, direction, and clustering settings
used, enable sanity checks, or change which shaping engine is
used.
</para>
<para>
You can also set the foreground and background colors used for
the output, independently control the width of all four
margins, alter the line spacing, and annotate the output image
with
</para>
<para>
In general, <program>hb-view</program> 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
why something does not appear as expected.
</para>
</section>
<section id="utilities-command-line-hbsubset">
<title>hb-subset</title>
<para>
<emphasis><program>hb-subset</program></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
generate a font that covers the input text exactly like the
input font does, but includes no other characters or features.
</para>
<programlisting>
<command>hb-subset</command> <optional>[OPTIONS]</optional>
<parameter>path/to/font/file.ttf</parameter>
<parameter>yourinputtext</parameter>
</programlisting>
<para>
For example, to create a subset of Noto Serif that just includes the
numerals and the lowercase Latin alphabet, you could run
</para>
<programlisting>
<command>hb-subset</command> <optional>[OPTIONS]</optional>
<parameter>NotoSerif-Regular.ttf</parameter>
<parameter>0123456789abcdefghijklmnopqrstuvwxyz</parameter>
</programlisting>
<para>
There are options available to remove hinting from the
subsetted font and to specify a list of variation-axis settings.
</para>
</section>
</section>
<section id="utilities-common-types-apis">
<title>Common data types and APIs</title>
<para>
HarfBuzz includes several APIs for working with general-purpose
data that you may find convenient to leverage in your own
software. They include set operations and integer-to-integer
mapping operations.
</para>
<para>
HarfBuzz uses set operations for internal bookkeeping, such as
when it collects all of the glyph IDs covered by a particular
font feature. You can also use the set API to build sets, add
and remove elements, test whether or not sets contain particular
elements, or compute the unions, intersections, or differences
between sets.
</para>
<para>
All set elements are integers (specifically,
<type>hb_codepoint_t</type> 32-bit unsigned ints), and there are
functions for fetching the minimum and maximum element from a
set. The set API also includes some functions that might not
be part of a generic set facility, such as the ability to add a
contiguous range of integer elements to a set in bulk, and the
ability to fetch the next-smallest or next-largest element.
</para>
<para>
The HarfBuzz set API includes some conveniences as well. All
sets are lifecycle-managed, just like other HarfBuzz
objects. You increase the reference count on a set with
<function>hb_set_reference()</function> and decrease it with
<function>hb_set_destroy()</function>. You can also attach
user data to a set, just like you can to blobs, buffers, faces,
fonts, and other objects, and set destroy callbacks.
</para>
<para>
HarfBuzz also provides an API for keeping track of
integer-to-integer mappings. As with the set API, each integer is
stored as an unsigned 32-bit <type>hb_codepoint_t</type>
element. Maps, like other objects, are reference counted with
reference and destroy functions, and you can attach user data to
them. The mapping operations include adding and deleting
integer-to-integer key:value pairs to the map, testing for the
presence of a key, fetching the population of the map, and so on.
</para>
<para>
There are several other internal HarfBuzz facilities that are
exposed publicly and which you may want to take advantage of
while processing text. HarfBuzz uses a common
<type>hb_tag_t</type> for a variety of OpenType tag identifiers (for
scripts, languages, font features, table names, variation-axis
names, and more), and provides functions for converting strings
to tags and vice-versa.
</para>
<para>
Finally, HarfBuzz also includes data type for Booleans, bit
masks, and other simple types.
</para>
</section>
<section id="utilities-ucdn">
<title>UCDN</title>
<para>
HarfBuzz includes a copy of the <ulink
url="https://github.com/grigorig/ucdn">UCDN</ulink> (Unicode
Database and Normalization) library, which provides functions
for accessing basic Unicode character properties, performing
canonical composition, and performing both canonical and
compatibility decomposition.
</para>
<para>
Currently, UCDN supports direct queries for several more character
properties than HarfBuzz's built-in set of Unicode functions
does, such as the BiDirectional Class, East Asian Width, Paired
Bracket and Resolved Linebreak properties. If you need to access
more properties than HarfBuzz's internal implementation
provides, using the built-in UCDN functions may be a useful solution.
</para>
<para>
The built-in UCDN functions are compiled by default when
building HarfBuzz from source, but this can be disabled with a
compile-time switch.
</para>
</section>
</chapter>

View file

@ -151,9 +151,9 @@
</para>
<para>
For example, in Tamil, when the letter &quot;TTA&quot; (ட)
letter is followed by &quot;U&quot; (உ), the pair
letter is followed by the vowel sign &quot;U&quot; (ு), the pair
must be replaced by the single glyph &quot;டு&quot;. The
sequence of Unicode characters &quot;&quot; needs to be
sequence of Unicode characters &quot;,ு&quot; needs to be
substituted with a single &quot;டு&quot; glyph from the
font.
</para>

28
mingw-configure.sh Executable file
View file

@ -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 \
"$@"

58
mingw-ldd.py Executable file
View file

@ -0,0 +1,58 @@
#!/usr/bin/env python
# Copied from https://github.com/xantares/mingw-ldd/blob/master/mingw-ldd.py
# Modified to point to right prefix location on Fedora.
# WTFPL - Do What the Fuck You Want to Public License
from __future__ import print_function
import pefile
import os
import sys
def get_dependency(filename):
deps = []
pe = pefile.PE(filename)
for imp in pe.DIRECTORY_ENTRY_IMPORT:
deps.append(imp.dll.decode())
return deps
def dep_tree(root, prefix=None):
if not prefix:
arch = get_arch(root)
#print('Arch =', arch)
prefix = '/usr/'+arch+'-w64-mingw32/sys-root/mingw/bin'
#print('Using default prefix', prefix)
dep_dlls = dict()
def dep_tree_impl(root, prefix):
for dll in get_dependency(root):
if dll in dep_dlls:
continue
full_path = os.path.join(prefix, dll)
if os.path.exists(full_path):
dep_dlls[dll] = full_path
dep_tree_impl(full_path, prefix=prefix)
else:
dep_dlls[dll] = 'not found'
dep_tree_impl(root, prefix)
return (dep_dlls)
def get_arch(filename):
type2arch= {pefile.OPTIONAL_HEADER_MAGIC_PE: 'i686',
pefile.OPTIONAL_HEADER_MAGIC_PE_PLUS: 'x86_64'}
pe = pefile.PE(filename)
try:
return type2arch[pe.PE_TYPE]
except KeyError:
sys.stderr.write('Error: unknown architecture')
sys.exit(1)
if __name__ == '__main__':
filename = sys.argv[1]
for dll, full_path in dep_tree(filename).items():
print(' ' * 7, dll, '=>', full_path)

View file

@ -1,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 "$@"

View file

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

View file

@ -12,9 +12,15 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS =
check_PROGRAMS =
EXTRA_DIST += harfbuzz.cc
# 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 +34,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)
@ -80,6 +82,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 +96,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
@ -258,36 +256,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)
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 HBIndicVowelConstraints.txt Scripts.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc \
|| ($(RM) $(srcdir)/hb-ot-shape-complex-vowel-constraints.cc; false)
emoji-table: gen-emoji-table.py emoji-data.txt
$(AM_V_GEN) $(builddir)/$^ > $(srcdir)/hb-unicode-emoji-table.hh \
|| ($(RM) $(srcdir)/hb-unicode-emoji-table.hh; false)
built-sources: $(BUILT_SOURCES)
@ -306,13 +312,30 @@ $(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-gpos-size-params \
test-gsub-would-substitute \
$(NULL)
bin_PROGRAMS =
@ -328,17 +351,21 @@ 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_gpos_size_params_SOURCES = test-gpos-size-params.cc
test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
if HAVE_FREETYPE
if HAVE_CAIRO_FT
@ -384,16 +411,24 @@ 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-iter test-ot-tag test-unicode-ranges
COMPILED_TESTS = test-algs test-iter test-meta test-ot-tag test-unicode-ranges test-bimap
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
check_PROGRAMS += $(COMPILED_TESTS)
TESTS += $(COMPILED_TESTS)
test_algs_SOURCES = test-algs.cc hb-static.cc
test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_algs_LDADD = $(COMPILED_TESTS_LDADD)
test_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_ot_tag_SOURCES = hb-ot-tag.cc
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
@ -402,6 +437,10 @@ 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)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
@ -430,6 +469,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 = \

View file

@ -10,12 +10,14 @@ 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 \
hb-aat-ltag-table.hh \
hb-aat-map.cc \
hb-aat-map.hh \
hb-algs.hh \
hb-array.hh \
hb-atomic.hh \
hb-blob.cc \
@ -30,10 +32,12 @@ HB_BASE_sources = \
hb-cff1-interp-cs.hh \
hb-cff2-interp-cs.hh \
hb-common.cc \
hb-config.hh \
hb-debug.hh \
hb-dsalgs.hh \
hb-dispatch.hh \
hb-face.cc \
hb-face.hh \
hb-fallback-shape.cc \
hb-font.cc \
hb-font.hh \
hb-iter.hh \
@ -41,6 +45,8 @@ 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-object.hh \
@ -60,6 +66,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 \
@ -82,7 +89,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 \
@ -127,6 +138,9 @@ HB_BASE_sources = \
hb-ot-var-mvar-table.hh \
hb-ot-var.cc \
hb-ot-vorg-table.hh \
hb-pool.hh \
hb-sanitize.hh \
hb-serialize.hh \
hb-set-digest.hh \
hb-set.cc \
hb-set.hh \
@ -139,6 +153,8 @@ 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 \
@ -180,6 +196,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 \
@ -192,10 +210,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
@ -215,12 +229,12 @@ 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
@ -236,9 +250,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 \

View file

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

View file

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

View file

@ -4,6 +4,7 @@ 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)
@ -52,14 +53,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 */")

View file

@ -79,10 +79,6 @@ data = combined
del combined
num = len (data)
for u in [0x17CD, 0x17CE, 0x17CF, 0x17D0, 0x17D3]:
if data[u][0] == 'Other':
data[u][0] = "Vowel_Dependent"
# Move the outliers NO-BREAK SPACE and DOTTED CIRCLE out
singles = {}
for u in ALLOWED_SINGLES:
@ -102,6 +98,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 ()
@ -131,6 +131,8 @@ for i in range (2):
what = ["INDIC_SYLLABIC_CATEGORY", "INDIC_MATRA_CATEGORY"]
what_short = ["ISC", "IMC"]
print ('#pragma GCC diagnostic push')
print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
for i in range (2):
print ()
vv = sorted (values[i].keys ())
@ -148,6 +150,7 @@ for i in range (2):
(what_short[i], s, what[i], v.upper (),
' '* ((48-1 - len (what[i]) - 1 - len (v)) // 8),
values[i][v], v))
print ('#pragma GCC diagnostic pop')
print ()
print ("#define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M)")
print ()
@ -252,6 +255,8 @@ for i in range (2):
print ("#undef %s_%s" %
(what_short[i], short[i][v]))
print ()
print ()
print ('#endif')
print ("/* == End of generated table == */")
# Maintain at least 30% occupancy in the table */

4
src/gen-os2-unicode-ranges.py Normal file → Executable file
View file

@ -1,8 +1,10 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# 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).
# (https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
from __future__ import print_function, division, absolute_import

View file

@ -895,20 +895,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 +921,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 +1047,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 +1099,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)

164
src/gen-ucd-table.py Executable file
View file

@ -0,0 +1,164 @@
#!/usr/bin/env python
from __future__ import print_function, division, absolute_import
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]", 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.')

View file

@ -47,9 +47,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]
data[0][0x20F0] = 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
@ -172,7 +185,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):
@ -184,15 +197,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):
@ -201,7 +214,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
@ -217,6 +232,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)
@ -226,20 +242,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])))
@ -265,6 +283,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,
@ -306,7 +325,11 @@ use_positions = {
'H': None,
'HVM': None,
'B': None,
'FM': None,
'FM': {
'Abv': [Top],
'Blw': [Bottom],
'Pst': [Not_Applicable],
},
'SUB': None,
}
@ -317,12 +340,11 @@ def map_to_use(data):
# Resolve Indic_Syllabic_Category
# TODO: These don't have UISC assigned in Unicode 8.0, but have UIPC
if U == 0x17DD: UISC = Vowel_Dependent
# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
# Tibetan:
# TODO: These don't have UISC assigned in Unicode 11.0, but have UIPC
# TODO: These don't have UISC assigned in Unicode 12.0, but have UIPC
if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
if 0x0F86 <= U <= 0x0F87: UISC = Tone_Mark
# Overrides to allow NFC order matching syllable
@ -346,48 +368,28 @@ 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; UIPC = Bottom
# TODO: https://github.com/harfbuzz/harfbuzz/pull/609
if U == 0x20F0: UISC = Cantillation_Mark; UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/626
if U == 0xA8B4: UISC = Consonant_Medial
# TODO: https://github.com/harfbuzz/harfbuzz/issues/1105
if U == 0x11134: UISC = Gemination_Mark
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1399
if U == 0x111C9: UISC = Consonant_Final
values = [k for k,v in items if v(U,UISC,UGC)]
assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
USE = values[0]
# Resolve Indic_Positional_Category
# TODO: Not in Unicode 8.0 yet, but in spec.
if U == 0x1B6C: UIPC = Bottom
# TODO: These should die, but have UIPC in Unicode 8.0
# TODO: These should die, but have UIPC in Unicode 12.0
if U in [0x953, 0x954]: UIPC = Not_Applicable
# TODO: In USE's override list but not in Unicode 11.0
# TODO: In USE's override list but not in Unicode 12.0
if U == 0x103C: UIPC = Left
# TODO: These are not in USE's override list that we have, nor are they in Unicode 11.0
# TODO: These are not in USE's override list that we have, nor are they in Unicode 12.0
if 0xA926 <= U <= 0xA92A: UIPC = Top
if U == 0x111CA: UIPC = Bottom
if U == 0x11300: UIPC = Top
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
if U == 0x11302: UIPC = Top
if U == 0x1133C: UIPC = Bottom
if U == 0x1171E: UIPC = Left # Correct?!
if 0x1CF2 <= U <= 0x1CF3: UIPC = Right
# and https://github.com/harfbuzz/harfbuzz/issues/1631
if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
if U == 0x1171E: UIPC = Left
if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
# https://github.com/roozbehp/unicode-data/issues/8
if U == 0x0A51: UIPC = Bottom
assert (UIPC in [Not_Applicable, Visual_Order_Left] or
USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
@ -417,6 +419,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 ()
@ -455,6 +461,8 @@ num = 0
offset = 0
starts = []
ends = []
print ('#pragma GCC diagnostic push')
print ('#pragma GCC diagnostic ignored "-Wunused-macros"')
for k,v in sorted(use_mapping.items()):
if k in use_positions and use_positions[k]: continue
print ("#define %s USE_%s /* %s */" % (k, k, v.__name__[3:]))
@ -463,6 +471,7 @@ for k,v in sorted(use_positions.items()):
for suf in v.keys():
tag = k + suf
print ("#define %s USE_%s" % (tag, tag))
print ('#pragma GCC diagnostic pop')
print ("")
print ("static const USE_TABLE_ELEMENT_TYPE use_table[] = {")
for u in uu:
@ -528,6 +537,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 */

View file

@ -157,6 +157,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 +185,12 @@ 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 ('#if defined(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 ()
print (' /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
print (' * vowel-sequences that look like another vowel. Data for each script')
print (' * collected from the USE script development spec.')
@ -212,8 +223,11 @@ print (' if (processed)')
print (' {')
print (' if (buffer->idx < count)')
print (' buffer->next_glyph ();')
print (' buffer->swap_buffers ();')
print (' }')
print ('}')
print ()
print ()
print ('#endif')
print ('/* == End of generated functions == */')

53
src/harfbuzz.cc Normal file
View file

@ -0,0 +1,53 @@
#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-face.cc"
#include "hb-fallback-shape.cc"
#include "hb-font.cc"
#include "hb-map.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-warning.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"

View file

@ -74,7 +74,7 @@ struct FontDescriptor
struct fdsc
{
enum { tableTag = HB_AAT_TAG_fdsc };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
enum {
Weight = HB_TAG ('w','g','h','t'),

View file

@ -58,20 +58,16 @@ typedef LArrayOf<Anchor> GlyphAnchors;
struct ankr
{
enum { tableTag = HB_AAT_TAG_ankr };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
const Anchor &get_anchor (hb_codepoint_t glyph_id,
unsigned int i,
unsigned int num_glyphs,
const char *end) const
unsigned int num_glyphs) const
{
const Offset<HBUINT16, false> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
if (!offset)
return Null(Anchor);
const GlyphAnchors &anchors = StructAtOffset<GlyphAnchors> (&(this+anchorData), *offset);
if (unlikely (end - (const char *) &anchors < anchors.len.static_size ||
end - (const char *) &anchors < anchors.get_size ()))
return Null(Anchor);
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
return anchors[i];
}
@ -80,16 +76,16 @@ struct ankr
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
version == 0 &&
lookupTable.sanitize (c, this) &&
anchorData.sanitize (c, this) /* Just one byte. */));
c->check_range (this, anchorData) &&
lookupTable.sanitize (c, this, &(this+anchorData))));
}
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
LOffsetTo<Lookup<Offset<HBUINT16, false> >, false>
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
lookupTable; /* Offset to the table's lookup table */
LOffsetTo<HBUINT8, false>
LNNOffsetTo<HBUINT8>
anchorData; /* Offset to the glyph data table */
public:

View file

@ -116,7 +116,7 @@ struct BaselineTableFormat3Part
struct bsln
{
enum { tableTag = HB_AAT_TAG_bsln };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
bool sanitize (hb_sanitize_context_t *c) const
{

View file

@ -77,7 +77,7 @@ struct LookupFormat0
template <typename T>
struct LookupSegmentSingle
{
enum { TerminationWordCount = 2 };
static constexpr unsigned TerminationWordCount = 2u;
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1 ; }
@ -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). */
@ -136,7 +136,7 @@ struct LookupFormat2
template <typename T>
struct LookupSegmentArray
{
enum { TerminationWordCount = 2 };
static constexpr unsigned TerminationWordCount = 2u;
const T* get_value (hb_codepoint_t glyph_id, const void *base) const
{
@ -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 */
OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
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). */
@ -207,7 +207,7 @@ struct LookupFormat4
template <typename T>
struct LookupSingle
{
enum { TerminationWordCount = 1 };
static constexpr unsigned TerminationWordCount = 1u;
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
@ -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);
@ -394,7 +394,7 @@ struct Lookup
case 4: return_trace (u.format4.sanitize (c, base));
case 6: return_trace (u.format6.sanitize (c, base));
case 8: return_trace (u.format8.sanitize (c, base));
case 10: return_trace (false); /* No need to support format10 apparently */
case 10: return_trace (false); /* We don't support format10 here currently. */
default:return_trace (true);
}
}
@ -418,15 +418,11 @@ struct Lookup
} /* Close namespace. */
/* Ugly hand-coded null objects for template Lookup<> :(. */
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
template <>
/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > ()
{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); }
template <>
/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > ()
{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); }
template <>
/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > ()
{ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); }
template <typename T>
struct Null<AAT::Lookup<T>> {
static AAT::Lookup<T> const & get_null ()
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
};
namespace AAT {
enum { DELETED_GLYPH = 0xFFFF };
@ -511,9 +507,10 @@ struct StateTable
const Entry<Extra> *get_entries () const
{ return (this+entryTable).arrayZ; }
const Entry<Extra> *get_entryZ (int state, unsigned int klass) const
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses)) return nullptr;
if (unlikely (klass >= nClasses))
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
@ -521,7 +518,7 @@ struct StateTable
unsigned int entry = states[state * nClasses + klass];
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
return &entries[entry];
return entries[entry];
}
bool sanitize (hb_sanitize_context_t *c,
@ -529,6 +526,7 @@ struct StateTable
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) &&
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
classTable.sanitize (c, this)))) return_trace (false);
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
@ -571,14 +569,14 @@ struct StateTable
-min_state,
row_stride)))
return_trace (false);
if ((c->max_ops -= state_neg - min_state) < 0)
if ((c->max_ops -= state_neg - min_state) <= 0)
return_trace (false);
{ /* Sweep new states. */
const HBUSHORT *stop = &states[min_state * num_classes];
if (unlikely (stop > states))
return_trace (false);
for (const HBUSHORT *p = states; stop < p; p--)
num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
num_entries = hb_max (num_entries, *(p - 1) + 1);
state_neg = min_state;
}
}
@ -590,7 +588,7 @@ struct StateTable
max_state + 1,
row_stride)))
return_trace (false);
if ((c->max_ops -= max_state - state_pos + 1) < 0)
if ((c->max_ops -= max_state - state_pos + 1) <= 0)
return_trace (false);
{ /* Sweep new states. */
if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
@ -599,22 +597,22 @@ 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;
}
}
if (unlikely (!c->check_array (entries, num_entries)))
return_trace (false);
if ((c->max_ops -= num_entries - entry) < 0)
if ((c->max_ops -= num_entries - entry) <= 0)
return_trace (false);
{ /* Sweep new entries. */
const Entry<Extra> *stop = &entries[num_entries];
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
{
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;
}
@ -629,11 +627,11 @@ struct StateTable
protected:
HBUINT nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
OffsetTo<ClassType, HBUINT, false>
NNOffsetTo<ClassType, HBUINT>
classTable; /* Offset to the class table. */
OffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
stateArrayTable;/* Offset to the state array. */
OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
entryTable; /* Offset to the entry array. */
public:
@ -669,7 +667,7 @@ struct ClassTable
struct ObsoleteTypes
{
enum { extended = false };
static constexpr bool extended = false;
typedef HBUINT16 HBUINT;
typedef HBUINT8 HBUSHORT;
typedef ClassTable<HBUINT8> ClassTypeNarrow;
@ -699,7 +697,7 @@ struct ObsoleteTypes
};
struct ExtendedTypes
{
enum { extended = true };
static constexpr bool extended = true;
typedef HBUINT32 HBUINT;
typedef HBUINT16 HBUSHORT;
typedef Lookup<HBUINT16> ClassTypeNarrow;
@ -745,16 +743,13 @@ struct StateTableDriver
buffer->clear_output ();
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
bool last_was_dont_advance = false;
for (buffer->idx = 0; buffer->successful;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry))
break;
const Entry<EntryData> &entry = machine.get_entry (state, klass);
/* Unsafe-to-break before this if not in state 0, as things might
* go differently if we start from state 0 here.
@ -765,31 +760,28 @@ struct StateTableDriver
/* If there's no action and we're just epsilon-transitioning to state 0,
* safe to break. */
if (c->is_actionable (this, entry) ||
!(entry->newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
entry->flags == context_t::DontAdvance))
!(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
entry.flags == context_t::DontAdvance))
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
}
/* Unsafe-to-break if end-of-text would kick in here. */
if (buffer->idx + 2 <= buffer->len)
{
const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
if (c->is_actionable (this, end_entry))
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
}
if (unlikely (!c->transition (this, entry)))
break;
c->transition (this, entry);
last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
state = machine.new_state (entry->newState);
state = machine.new_state (entry.newState);
DEBUG_MSG (APPLY, nullptr, "s%d", state);
if (buffer->idx == buffer->len)
break;
if (!last_was_dont_advance)
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
buffer->next_glyph ();
}
@ -825,7 +817,6 @@ struct hb_aat_apply_context_t :
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
const char *ankr_end;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
@ -838,7 +829,7 @@ struct hb_aat_apply_context_t :
HB_INTERNAL ~hb_aat_apply_context_t ();
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_, const char *ankr_end_);
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
};

View file

@ -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;
}
@ -154,7 +154,7 @@ struct FeatureName
struct feat
{
enum { tableTag = HB_AAT_TAG_feat };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
bool has_data () const { return version.to_int (); }
@ -162,21 +162,18 @@ 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;
}
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 (); }

View file

@ -309,7 +309,7 @@ struct WidthDeltaPair
public:
DEFINE_SIZE_STATIC (24);
};
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
struct JustificationCategory
@ -371,7 +371,7 @@ struct JustificationHeader
* of postcompensation subtable (set to zero if none).
*
* The postcompensation subtable, if present in the font. */
Lookup<OffsetTo<WidthDeltaCluster> >
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. */
@ -382,7 +382,7 @@ struct JustificationHeader
struct just
{
enum { tableTag = HB_AAT_TAG_just };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
bool sanitize (hb_sanitize_context_t *c) const
{

View file

@ -170,11 +170,11 @@ struct Format1Entry<true>
DEFINE_SIZE_STATIC (2);
};
static bool performAction (const Entry<EntryData> *entry)
{ return entry->data.kernActionIndex != 0xFFFF; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.data.kernActionIndex != 0xFFFF; }
static unsigned int kernActionIndex (const Entry<EntryData> *entry)
{ return entry->data.kernActionIndex; }
static unsigned int kernActionIndex (const Entry<EntryData> &entry)
{ return entry.data.kernActionIndex; }
};
template <>
struct Format1Entry<false>
@ -192,11 +192,11 @@ struct Format1Entry<false>
typedef void EntryData;
static bool performAction (const Entry<EntryData> *entry)
{ return entry->flags & Offset; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
static unsigned int kernActionIndex (const Entry<EntryData> *entry)
{ return entry->flags & Offset; }
static unsigned int kernActionIndex (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
};
template <typename KernSubTableHeader>
@ -210,7 +210,7 @@ struct KerxSubTableFormat1
struct driver_context_t
{
enum { in_place = true };
static constexpr bool in_place = true;
enum
{
DontAdvance = Format1EntryT::DontAdvance,
@ -228,15 +228,15 @@ struct KerxSubTableFormat1
crossStream (table->header.coverage & table->header.CrossStream) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
const Entry<EntryData> &entry)
{
return Format1EntryT::performAction (entry);
}
bool transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry->flags;
unsigned int flags = entry.flags;
if (flags & Format1EntryT::Reset)
depth = 0;
@ -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);
@ -259,7 +259,7 @@ struct KerxSubTableFormat1
if (!c->sanitizer.check_array (actions, depth, tuple_count))
{
depth = 0;
return false;
return;
}
hb_mask_t kern_mask = c->plan->kern_mask;
@ -334,8 +334,6 @@ struct KerxSubTableFormat1
}
}
}
return true;
}
private:
@ -374,7 +372,7 @@ struct KerxSubTableFormat1
protected:
KernSubTableHeader header;
StateTable<Types, EntryData> machine;
OffsetTo<UnsizedArrayOf<FWORD>, HBUINT, false>kernAction;
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT> kernAction;
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 5 * sizeof (HBUINT));
};
@ -443,13 +441,13 @@ struct KerxSubTableFormat2
protected:
KernSubTableHeader header;
HBUINT rowWidth; /* The width, in bytes, of a row in the table. */
OffsetTo<typename Types::ClassTypeWide, HBUINT, false>
NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
leftClassTable; /* Offset from beginning of this subtable to
* left-hand class table. */
OffsetTo<typename Types::ClassTypeWide, HBUINT, false>
NNOffsetTo<typename Types::ClassTypeWide, HBUINT>
rightClassTable;/* Offset from beginning of this subtable to
* right-hand class table. */
OffsetTo<UnsizedArrayOf<FWORD>, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<FWORD>, HBUINT>
array; /* Offset from beginning of this subtable to
* the start of the kerning array. */
public:
@ -471,7 +469,7 @@ struct KerxSubTableFormat4
struct driver_context_t
{
enum { in_place = true };
static constexpr bool in_place = true;
enum Flags
{
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
@ -498,16 +496,16 @@ struct KerxSubTableFormat4
mark (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
const Entry<EntryData> &entry)
{
return entry->data.ankrActionIndex != 0xFFFF;
return entry.data.ankrActionIndex != 0xFFFF;
}
bool transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
if (mark_set && entry->data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
{
hb_glyph_position_t &o = buffer->cur_pos();
switch (action_type)
@ -515,9 +513,8 @@ struct KerxSubTableFormat4
case 0: /* Control Point Actions.*/
{
/* indexed into glyph outline. */
const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
if (!c->sanitizer.check_array (data, 2))
return false;
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
if (!c->sanitizer.check_array (data, 2)) return;
HB_UNUSED unsigned int markControlPoint = *data++;
HB_UNUSED unsigned int currControlPoint = *data++;
hb_position_t markX = 0;
@ -532,7 +529,7 @@ struct KerxSubTableFormat4
currControlPoint,
HB_DIRECTION_LTR /*XXX*/,
&currX, &currY))
return true; /* True, such that the machine continues. */
return;
o.x_offset = markX - currX;
o.y_offset = markY - currY;
@ -542,19 +539,16 @@ struct KerxSubTableFormat4
case 1: /* Anchor Point Actions. */
{
/* Indexed into 'ankr' table. */
const HBUINT16 *data = &ankrData[entry->data.ankrActionIndex];
if (!c->sanitizer.check_array (data, 2))
return false;
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
if (!c->sanitizer.check_array (data, 2)) return;
unsigned int markAnchorPoint = *data++;
unsigned int currAnchorPoint = *data++;
const Anchor markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
markAnchorPoint,
c->sanitizer.get_num_glyphs (),
c->ankr_end);
const Anchor currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
currAnchorPoint,
c->sanitizer.get_num_glyphs (),
c->ankr_end);
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
markAnchorPoint,
c->sanitizer.get_num_glyphs ());
const Anchor &currAnchor = c->ankr_table->get_anchor (c->buffer->cur ().codepoint,
currAnchorPoint,
c->sanitizer.get_num_glyphs ());
o.x_offset = c->font->em_scale_x (markAnchor.xCoordinate) - c->font->em_scale_x (currAnchor.xCoordinate);
o.y_offset = c->font->em_scale_y (markAnchor.yCoordinate) - c->font->em_scale_y (currAnchor.yCoordinate);
@ -563,9 +557,8 @@ struct KerxSubTableFormat4
case 2: /* Control Point Coordinate Actions. */
{
const FWORD *data = (const FWORD *) &ankrData[entry->data.ankrActionIndex];
if (!c->sanitizer.check_array (data, 4))
return false;
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
if (!c->sanitizer.check_array (data, 4)) return;
int markX = *data++;
int markY = *data++;
int currX = *data++;
@ -581,13 +574,11 @@ struct KerxSubTableFormat4
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
}
if (entry->flags & Mark)
if (entry.flags & Mark)
{
mark_set = true;
mark = buffer->idx;
}
return true;
}
private:
@ -721,18 +712,18 @@ struct KerxSubTableFormat6
{
struct Long
{
LOffsetTo<Lookup<HBUINT32>, false> rowIndexTable;
LOffsetTo<Lookup<HBUINT32>, false> columnIndexTable;
LOffsetTo<UnsizedArrayOf<FWORD32>, false> array;
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
} l;
struct Short
{
LOffsetTo<Lookup<HBUINT16>, false> rowIndexTable;
LOffsetTo<Lookup<HBUINT16>, false> columnIndexTable;
LOffsetTo<UnsizedArrayOf<FWORD>, false> array;
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
} s;
} u;
LOffsetTo<UnsizedArrayOf<FWORD>, false> vector;
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
};
@ -780,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 ());
}
}
@ -981,8 +972,8 @@ struct kerx : KerxTable<kerx>
{
friend struct KerxTable<kerx>;
enum { tableTag = HB_AAT_TAG_kerx };
enum { minVersion = 2u };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_kerx;
static constexpr unsigned minVersion = 2u;
typedef KerxSubTableHeader SubTableHeader;
typedef SubTableHeader::Types Types;

View file

@ -38,9 +38,83 @@ 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
{
enum { tableTag = HB_AAT_TAG_lcar };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
@ -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);
};

View file

@ -54,7 +54,7 @@ struct RearrangementSubtable
struct driver_context_t
{
enum { in_place = true };
static constexpr bool in_place = true;
enum Flags
{
MarkFirst = 0x8000, /* If set, make the current glyph the first
@ -74,21 +74,21 @@ struct RearrangementSubtable
start (0), end (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
const Entry<EntryData> &entry)
{
return (entry->flags & Verb) && start < end;
return (entry.flags & Verb) && start < end;
}
bool transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry->flags;
unsigned int flags = entry.flags;
if (flags & MarkFirst)
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;
@ -152,8 +152,6 @@ struct RearrangementSubtable
}
}
}
return true;
}
public:
@ -204,7 +202,7 @@ struct ContextualSubtable
struct driver_context_t
{
enum { in_place = true };
static constexpr bool in_place = true;
enum Flags
{
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
@ -223,39 +221,39 @@ struct ContextualSubtable
subs (table+table->substitutionTables) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
if (buffer->idx == buffer->len && !mark_set)
return false;
return entry->data.markIndex != 0xFFFF || entry->data.currentIndex != 0xFFFF;
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
}
bool transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
/* 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 true;
return;
const GlyphID *replacement;
replacement = nullptr;
if (Types::extended)
{
if (entry->data.markIndex != 0xFFFF)
if (entry.data.markIndex != 0xFFFF)
{
const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
const Lookup<GlyphID> &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;
unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
@ -263,24 +261,24 @@ struct ContextualSubtable
}
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)
if (entry.data.currentIndex != 0xFFFF)
{
const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
const Lookup<GlyphID> &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;
unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
@ -292,13 +290,11 @@ struct ContextualSubtable
ret = true;
}
if (entry->flags & SetMark)
if (entry.flags & SetMark)
{
mark_set = true;
mark = buffer->idx;
}
return true;
}
public:
@ -341,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));
@ -352,7 +348,7 @@ struct ContextualSubtable
protected:
StateTable<Types, EntryData>
machine;
OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT, false>
NNOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
@ -385,11 +381,11 @@ struct LigatureEntry<true>
DEFINE_SIZE_STATIC (2);
};
static bool performAction (const Entry<EntryData> *entry)
{ return entry->flags & PerformAction; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & PerformAction; }
static unsigned int ligActionIndex (const Entry<EntryData> *entry)
{ return entry->data.ligActionIndex; }
static unsigned int ligActionIndex (const Entry<EntryData> &entry)
{ return entry.data.ligActionIndex; }
};
template <>
struct LigatureEntry<false>
@ -407,11 +403,11 @@ struct LigatureEntry<false>
typedef void EntryData;
static bool performAction (const Entry<EntryData> *entry)
{ return entry->flags & Offset; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
static unsigned int ligActionIndex (const Entry<EntryData> *entry)
{ return entry->flags & Offset; }
static unsigned int ligActionIndex (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
};
@ -425,7 +421,7 @@ struct LigatureSubtable
struct driver_context_t
{
enum { in_place = false };
static constexpr bool in_place = false;
enum
{
DontAdvance = LigatureEntryT::DontAdvance,
@ -453,26 +449,23 @@ struct LigatureSubtable
match_length (0) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
const Entry<EntryData> &entry)
{
return LigatureEntryT::performAction (entry);
}
bool transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
if (entry->flags & LigatureEntryT::SetComponent)
if (entry.flags & LigatureEntryT::SetComponent)
{
if (unlikely (match_length >= ARRAY_LENGTH (match_positions)))
return false;
/* Never mark same index twice, in case DontAdvance was used... */
if (match_length && match_positions[match_length - 1] == buffer->out_len)
if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len)
match_length--;
match_positions[match_length++] = buffer->out_len;
match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len;
DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len);
}
@ -482,10 +475,10 @@ struct LigatureSubtable
unsigned int end = buffer->out_len;
if (unlikely (!match_length))
return true;
return;
if (buffer->idx >= buffer->len)
return false; // TODO Work on previous instead?
return; /* TODO Work on previous instead? */
unsigned int cursor = match_length;
@ -506,9 +499,9 @@ struct LigatureSubtable
}
DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1);
buffer->move_to (match_positions[--cursor]);
buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]);
if (unlikely (!actionData->sanitize (&c->sanitizer))) return false;
if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
action = *actionData;
uint32_t uoffset = action & LigActionOffset;
@ -518,7 +511,7 @@ struct LigatureSubtable
unsigned int component_idx = buffer->cur().codepoint + offset;
component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
const HBUINT16 &componentData = component[component_idx];
if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
ligature_idx += componentData;
DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
@ -528,23 +521,23 @@ struct LigatureSubtable
{
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
const GlyphID &ligatureData = ligature[ligature_idx];
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
buffer->replace_glyph (lig);
unsigned int lig_end = match_positions[match_length - 1] + 1;
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
/* Now go and delete all subsequent components. */
while (match_length - 1 > cursor)
while (match_length - 1u > cursor)
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
buffer->move_to (match_positions[--match_length]);
buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]);
buffer->replace_glyph (DELETED_GLYPH);
}
buffer->move_to (lig_end);
buffer->merge_out_clusters (match_positions[cursor], buffer->out_len);
buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len);
}
actionData++;
@ -552,8 +545,6 @@ struct LigatureSubtable
while (!(action & LigActionLast));
buffer->move_to (end);
}
return true;
}
public:
@ -591,11 +582,11 @@ struct LigatureSubtable
protected:
StateTable<Types, EntryData>
machine;
OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT>
ligAction; /* Offset to the ligature action table. */
OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
component; /* Offset to the component table. */
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
ligature; /* Offset to the actual ligature lists. */
public:
DEFINE_SIZE_STATIC (28);
@ -661,7 +652,7 @@ struct InsertionSubtable
struct driver_context_t
{
enum { in_place = false };
static constexpr bool in_place = false;
enum Flags
{
SetMark = 0x8000, /* If set, mark the current glyph. */
@ -714,28 +705,29 @@ struct InsertionSubtable
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
mark_set (false),
mark (0),
insertionAction (table+table->insertionAction) {}
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> *entry)
const Entry<EntryData> &entry)
{
return (entry->flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry->data.currentInsertIndex != 0xFFFF ||entry->data.markedInsertIndex != 0xFFFF);
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
}
bool transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> *entry)
void transition (StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry->flags;
unsigned int flags = entry.flags;
if (entry->data.markedInsertIndex != 0xFFFF && mark_set)
unsigned mark_loc = buffer->out_len;
if (entry.data.markedInsertIndex != 0xFFFF)
{
unsigned int count = (flags & MarkedInsertCount);
unsigned int start = entry->data.markedInsertIndex;
unsigned int start = entry.data.markedInsertIndex;
const GlyphID *glyphs = &insertionAction[start];
if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
bool before = flags & MarkedInsertBefore;
@ -752,15 +744,18 @@ 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 (entry->data.currentInsertIndex != 0xFFFF)
if (flags & SetMark)
mark = mark_loc;
if (entry.data.currentInsertIndex != 0xFFFF)
{
unsigned int count = (flags & CurrentInsertCount) >> 5;
unsigned int start = entry->data.currentInsertIndex;
unsigned int start = entry.data.currentInsertIndex;
const GlyphID *glyphs = &insertionAction[start];
if (unlikely (!c->sanitizer.check_array (glyphs, count))) return false;
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
bool before = flags & CurrentInsertBefore;
@ -791,21 +786,12 @@ struct InsertionSubtable
*/
buffer->move_to ((flags & DontAdvance) ? end : end + count);
}
if (flags & SetMark)
{
mark_set = true;
mark = buffer->out_len;
}
return true;
}
public:
bool ret;
private:
hb_aat_apply_context_t *c;
bool mark_set;
unsigned int mark;
const UnsizedArrayOf<GlyphID> &insertionAction;
};
@ -833,7 +819,7 @@ struct InsertionSubtable
protected:
StateTable<Types, EntryData>
machine;
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT, false>
NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
insertionAction; /* Byte offset from stateHeader to the start of
* the insertion glyph table. */
public:
@ -897,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 ());
}
}
@ -983,7 +969,7 @@ 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++)
{
@ -1045,7 +1031,7 @@ struct Chain
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);
}
}
@ -1063,13 +1049,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);
@ -1097,7 +1083,7 @@ struct Chain
template <typename Types>
struct mortmorx
{
enum { tableTag = HB_AAT_TAG_morx };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
bool has_data () const { return version != 0; }
@ -1109,7 +1095,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);
}
}
@ -1123,7 +1109,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);
}
}
@ -1139,7 +1125,7 @@ struct mortmorx
{
if (!chain->sanitize (c, version))
return_trace (false);
chain = &StructAfter<Chain<Types> > (*chain);
chain = &StructAfter<Chain<Types>> (*chain);
}
return_trace (true);
@ -1159,11 +1145,11 @@ struct mortmorx
struct morx : mortmorx<ExtendedTypes>
{
enum { tableTag = HB_AAT_TAG_morx };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
};
struct mort : mortmorx<ObsoleteTypes>
{
enum { tableTag = HB_AAT_TAG_mort };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
};

View file

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

View file

@ -66,7 +66,7 @@ struct TrackTableEntry
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
OffsetTo<UnsizedArrayOf<FWORD>, HBUINT16, false>
NNOffsetTo<UnsizedArrayOf<FWORD>>
valuesZ; /* Offset from start of tracking table to
* per-size tracking values for this track. */
@ -153,7 +153,7 @@ struct TrackData
struct trak
{
enum { tableTag = HB_AAT_TAG_trak };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
bool has_data () const { return version.to_int (); }

View file

@ -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,49 +172,16 @@ 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 (const hb_aat_feature_mapping_t *) hb_bsearch (&tag,
feature_mappings,
ARRAY_LENGTH (feature_mappings),
sizeof (feature_mappings[0]),
hb_aat_feature_mapping_t::cmp);
}
#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)),
ankr_end (nullptr),
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_,
const char *ankr_end_)
{
ankr_table = ankr_table_;
ankr_end = ankr_end_;
}
#ifndef HB_NO_AAT
/*
* mort/morx/kerx/trak
@ -286,11 +290,8 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
hb_blob_t *ankr_blob = font->face->table.ankr.get_blob ();;
const AAT::ankr& ankr = *font->face->table.ankr;
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
c.set_ankr_table (&ankr, ankr_blob->data + ankr_blob->length);
c.set_ankr_table (font->face->table.ankr.get ());
kerx.apply (&c);
}
@ -319,14 +320,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
@ -390,3 +383,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

View file

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

View file

@ -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,7 +39,7 @@ struct hb_aat_feature_mapping_t
hb_aat_layout_feature_selector_t selectorToEnable;
hb_aat_layout_feature_selector_t selectorToDisable;
static int cmp (const void *key_, const void *entry_)
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_;
@ -77,9 +77,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 */

View file

@ -50,7 +50,7 @@ struct FTStringRange
}
protected:
OffsetTo<UnsizedArrayOf<HBUINT8>, HBUINT16, false>
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
tag; /* Offset from the start of the table to
* the beginning of the string */
HBUINT16 length; /* String length (in bytes) */
@ -60,7 +60,7 @@ struct FTStringRange
struct ltag
{
enum { tableTag = HB_AAT_TAG_ltag };
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
hb_language_t get_language (unsigned int i) const
{

View file

@ -26,6 +26,10 @@
* Google Author(s): Behdad Esfahbod
*/
#include "hb.hh"
#ifndef HB_NO_AAT_SHAPE
#include "hb-aat-map.hh"
#include "hb-aat-layout.hh"
@ -66,3 +70,6 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
hb_aat_layout_compile_map (this, &m);
}
#endif

View file

@ -66,7 +66,7 @@ struct hb_aat_map_builder_t
hb_aat_layout_feature_selector_t setting;
unsigned seq; /* For stable sorting only. */
static int cmp (const void *pa, const void *pb)
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;
@ -84,7 +84,7 @@ struct hb_aat_map_builder_t
hb_face_t *face;
public:
hb_vector_t<feature_info_t> features;
hb_sorted_vector_t<feature_info_t> features;
};

1042
src/hb-algs.hh Normal file

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,7 @@
#define HB_ARRAY_HH
#include "hb.hh"
#include "hb-dsalgs.hh"
#include "hb-algs.hh"
#include "hb-iter.hh"
#include "hb-null.hh"
@ -37,22 +37,31 @@ template <typename Type>
struct hb_sorted_array_t;
template <typename Type>
struct hb_array_t :
hb_iter_t<hb_array_t<Type>, Type>,
hb_iter_mixin_t<hb_array_t<Type>, Type>
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
{
/*
* Constructors.
*/
hb_array_t () : arrayZ (nullptr), length (0) {}
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (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) {}
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>, 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; }
/*
* Iterator implementation.
*/
typedef Type __item_type__;
typedef Type& __item_t__;
static constexpr bool is_random_access_iterator = true;
Type& __item_at__ (unsigned i) const
{
if (unlikely (i >= length)) return CrapOrNull (Type);
@ -63,16 +72,25 @@ struct hb_array_t :
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; }
bool __random_access__ () const { return true; }
/* 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.
*/
@ -80,6 +98,9 @@ struct hb_array_t :
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
template <typename T> operator T * () const { return arrayZ; }
HB_INTERNAL bool operator == (const hb_array_t &o) const;
HB_INTERNAL uint32_t hash () const;
/*
* Compare, Sort, and Search.
*/
@ -91,7 +112,7 @@ struct hb_array_t :
return (int) a.length - (int) length;
return hb_memcmp (a.arrayZ, arrayZ, get_size ());
}
static int cmp (const void *pa, const void *pb)
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;
@ -120,21 +141,21 @@ struct hb_array_t :
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->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->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->item_size, Type::cmp);
}
/*
@ -154,7 +175,7 @@ struct hb_array_t :
else
count -= start_offset;
if (seg_count)
count = *seg_count = MIN (count, *seg_count);
count = *seg_count = hb_min (count, *seg_count);
return hb_array_t<Type> (arrayZ + start_offset, count);
}
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
@ -164,6 +185,17 @@ struct hb_array_t :
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); }
@ -175,6 +207,7 @@ struct hb_array_t :
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)
@ -183,7 +216,6 @@ template <typename T, unsigned int length_> inline hb_array_t<T>
hb_array (T (&array_)[length_])
{ return hb_array_t<T> (array_); }
enum hb_bfind_not_found_t
{
HB_BFIND_NOT_FOUND_DONT_STORE,
@ -193,14 +225,32 @@ enum hb_bfind_not_found_t
template <typename Type>
struct hb_sorted_array_t :
hb_sorted_iter_t<hb_sorted_array_t<Type>, Type>,
hb_array_t<Type>,
hb_iter_mixin_t<hb_sorted_array_t<Type>, Type>
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
hb_array_t<Type>
{
typedef hb_iter_t<hb_sorted_array_t<Type>, Type&> iter_base_t;
HB_ITER_USING (iter_base_t);
static constexpr bool is_random_access_iterator = true;
static constexpr bool is_sorted_iterator = true;
hb_sorted_array_t () : hb_array_t<Type> () {}
hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
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_) {}
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>, 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<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)); }
@ -269,9 +319,30 @@ template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
hb_sorted_array (T (&array_)[length_])
{ return hb_sorted_array_t<T> (array_); }
template <typename T>
bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
{
return length == o.length &&
+ hb_zip (*this, o)
| hb_map ([] (hb_pair_t<T&, T&> &&_) { return _.first == _.second; })
| hb_all
;
}
template <typename T>
uint32_t hb_array_t<T>::hash () const
{
return
+ hb_iter (*this)
| hb_map (hb_hash)
| hb_reduce ([] (uint32_t a, uint32_t b) { return a * 31 + b; }, 0)
;
}
typedef hb_array_t<const char> hb_bytes_t;
typedef hb_array_t<const unsigned char> hb_ubytes_t;
/* TODO Specialize opeator==/hash() for hb_bytes_t and hb_ubytes_t. */
//template <>
//uint32_t hb_array_t<const char>::hash () const { return 0; }
#endif /* HB_ARRAY_HH */

View file

@ -33,6 +33,7 @@
#define HB_ATOMIC_HH
#include "hb.hh"
#include "hb-meta.hh"
/*
@ -85,11 +86,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
static inline bool
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
@ -106,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);
@ -184,7 +185,7 @@ static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
#endif
#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
#include <builtins.h>
@ -215,7 +216,7 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
#define _hb_memory_barrier()
#define _hb_memory_barrier() do {} while (0)
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
@ -226,7 +227,7 @@ static_assert ((sizeof (long) == sizeof (void *)), "");
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
#define _hb_memory_barrier()
#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)
@ -282,7 +283,7 @@ struct hb_atomic_int_t
template <typename P>
struct hb_atomic_ptr_t
{
typedef typename 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_); }

143
src/hb-bimap.hh Normal file
View file

@ -0,0 +1,143 @@
/*
* 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
{
/* 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 = get_population ();
set (lhs, rhs);
}
return rhs;
}
/* 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);
}
};
#endif /* HB_BIMAP_HH */

View file

@ -30,8 +30,11 @@
* 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
*/
#ifndef _POSIX_C_SOURCE
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
#define _POSIX_C_SOURCE 200809L
#pragma GCC diagnostic pop
#endif
#include "hb.hh"
@ -152,7 +155,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);
@ -484,6 +487,7 @@ hb_blob_t::try_make_writable ()
* Mmap
*/
#ifndef HB_NO_OPEN
#ifdef HAVE_MMAP
# include <sys/types.h>
# include <sys/stat.h>
@ -673,3 +677,4 @@ fread_fail_without_close:
free (data);
return hb_blob_get_empty ();
}
#endif /* !HB_NO_OPEN */

View file

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

View file

@ -81,7 +81,7 @@ struct hb_blob_t
template <typename P>
struct hb_blob_ptr_t
{
typedef typename 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_; }

View file

@ -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];
@ -138,34 +142,34 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
*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;
@ -380,7 +384,7 @@ static hb_bool_t
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));
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
strncpy (buf, pp, len);
buf[len] = '\0';
@ -401,7 +405,7 @@ static hb_bool_t
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));
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
strncpy (buf, pp, len);
buf[len] = '\0';
@ -484,3 +488,6 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
}
}
#endif

View file

@ -524,7 +524,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 +555,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)
@ -1993,6 +1993,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 +2023,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

View file

@ -284,6 +284,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* space glyph and zeroing the advance width.)
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
* precedence over this flag. Since: 1.8.0
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
* flag indicating that a dotted circle should
* not be inserted in the rendering of incorrect
* character sequences (such at <0905 093E>). Since: 2.4
*
* Since: 0.9.20
*/
@ -292,7 +296,8 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
} hb_buffer_flags_t;
HB_EXTERN void

View file

@ -119,12 +119,14 @@ struct hb_buffer_t
/* Text before / after the main buffer contents.
* Always in Unicode, and ordered outward.
* Index 0 is for "pre-context", 1 for "post-context". */
enum { CONTEXT_LENGTH = 5 };
static constexpr unsigned CONTEXT_LENGTH = 5u;
hb_codepoint_t context[2][CONTEXT_LENGTH];
unsigned int context_len[2];
/* Debugging API */
#ifndef HB_NO_BUFFER_MESSAGE
hb_buffer_message_func_t message_func;
#endif
void *message_data;
hb_destroy_func_t message_destroy;
@ -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);
@ -379,7 +392,7 @@ struct hb_buffer_t
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

View file

@ -226,7 +226,7 @@ struct number_t
void set_fixed (int32_t v) { value = v / 65536.0; }
int32_t to_fixed () const { return (int32_t) (value * 65536.0); }
void set_real (double v) { value = v; }
void set_real (double v) { value = v; }
double to_real () const { return value; }
int ceil () const { return (int) ::ceil (value); }
@ -235,17 +235,10 @@ struct number_t
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,7 +248,7 @@ struct number_t
}
protected:
double value;
double value;
};
/* byte string */
@ -272,11 +265,11 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
if (unlikely (p == nullptr)) return_trace (false);
p->set (intOp);
*p = intOp;
INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
if (unlikely (ip == nullptr)) return_trace (false);
ip->set ((unsigned int)value);
*ip = (unsigned int) value;
return_trace (true);
}
@ -308,7 +301,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 +313,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 +335,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 +350,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 +378,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 +389,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 +404,6 @@ struct stack_t
else
set_error ();
}
ELEM &push ()
{
if (likely (count < elements.length))
@ -441,7 +425,6 @@ struct stack_t
return Crap(ELEM);
}
}
void pop (unsigned int n)
{
if (likely (count >= n))
@ -452,13 +435,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 elements[count - 1];
}
void unpop ()
@ -475,9 +457,9 @@ 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 const unsigned int kSizeLimit = LIMIT;
static constexpr unsigned kSizeLimit = LIMIT;
protected:
bool error;
@ -487,7 +469,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 +501,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 +520,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 */
@ -605,7 +585,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 +624,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 +660,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 +680,8 @@ struct opset_t
};
template <typename ENV>
struct interpreter_t {
struct interpreter_t
{
~interpreter_t() { fini (); }
void fini () { env.fini (); }

View file

@ -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,8 +76,8 @@ 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 == nullptr) ? 0 : subrs->count; }
unsigned int get_bias () const { return bias; }
byte_str_t operator [] (unsigned int index) const
{
@ -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);
@ -127,6 +127,7 @@ struct cs_interp_env_t : interp_env_t<ARG>
seen_hintmask = false;
hstem_count = 0;
vstem_count = 0;
hintmask_size = 0;
pt.init ();
callStack.init ();
globalSubrs.init (globalSubrs_);
@ -146,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 ())))
@ -157,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 ();
@ -174,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 ();
@ -245,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)
@ -253,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);
@ -266,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:

View file

@ -134,10 +134,10 @@ struct dict_opset_t : opset_t<number_t>
return value;
case END:
value = (double)(neg? -int_part: int_part);
value = (double) (neg ? -int_part : int_part);
if (frac_count > 0)
{
double frac = (frac_part / pow (10.0, (double)frac_count));
double frac = (frac_part / pow (10.0, (double) frac_count));
if (neg) frac = -frac;
value += frac;
}
@ -146,16 +146,16 @@ struct dict_opset_t : opset_t<number_t>
if (value == 0.0)
return value;
if (exp_neg)
return neg? -DBL_MIN: DBL_MIN;
return neg ? -DBL_MIN : DBL_MIN;
else
return neg? -DBL_MAX: DBL_MAX;
return neg ? -DBL_MAX : DBL_MAX;
}
if (exp_part != 0)
{
if (exp_neg)
value /= pow (10.0, (double)exp_part);
value /= pow (10.0, (double) exp_part);
else
value *= pow (10.0, (double)exp_part);
value *= pow (10.0, (double) exp_part);
}
return value;

View file

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

View file

@ -82,7 +82,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
void init (const byte_str_t &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int num_coords_=0)
{
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
coords = coords_;
num_coords = num_coords_;
@ -193,7 +193,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)

View file

@ -35,6 +35,9 @@
#include <xlocale.h>
#endif
#ifdef HB_NO_SETLOCALE
#define setlocale(Category, Locale) "C"
#endif
/**
* SECTION:hb-common
@ -67,7 +70,7 @@ _hb_options_init ()
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);
@ -356,7 +359,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);
@ -488,7 +491,7 @@ 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().
*
@ -720,7 +723,7 @@ 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));
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
@ -731,7 +734,7 @@ parse_uint (const char **pp, const char *end, unsigned int *pv)
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
v = strtol (p, &pend, 10);
if (errno || p == pend)
return false;
@ -744,7 +747,7 @@ 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));
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
@ -755,7 +758,7 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
v = strtol (p, &pend, 10);
if (errno || p == pend)
return false;
@ -783,7 +786,7 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv)
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),
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 ()
@ -825,7 +828,7 @@ 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));
unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
@ -857,9 +860,14 @@ parse_bool (const char **pp, const char *end, uint32_t *pv)
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
if (*pp - p == 2
&& TOLOWER (p[0]) == 'o'
&& TOLOWER (p[1]) == 'n')
*pv = 1;
else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
else if (*pp - p == 3
&& TOLOWER (p[0]) == 'o'
&& TOLOWER (p[1]) == 'f'
&& TOLOWER (p[2]) == 'f')
*pv = 0;
else
return false;
@ -974,7 +982,41 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
*
* Parses a string into a #hb_feature_t.
*
* TODO: document the syntax here.
* The format for specifying feature strings follows. All valid CSS
* font-feature-settings values other than 'normal' and the global values are
* also accepted, though not documented below. CSS string escapes are not
* supported.
*
* The range indices refer to the positions between Unicode characters. The
* position before the first character is always 0.
*
* The format is Python-esque. Here is how it all works:
*
* <informaltable pgwide='1' align='left' frame='none'>
* <tgroup cols='5'>
* <thead>
* <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
* </thead>
* <tbody>
* <row><entry>Setting value:</entry></row>
* <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry></entry> <entry>Turn feature off</entry></row>
* <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry></entry> <entry>Turn feature off</entry></row>
* <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry></entry> <entry>Choose 2nd alternate</entry></row>
* <row><entry>Setting index:</entry></row>
* <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry></entry> <entry>Turn feature on</entry></row>
* <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry></entry> <entry>Turn feature on, partial</entry></row>
* <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row>
* <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row>
* <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
* <row><entry>Mixing it all:</entry></row>
* <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row>
* </tbody>
* </tgroup>
* </informaltable>
*
* Return value:
* %true if @str is successfully parsed, %false otherwise.
@ -1032,21 +1074,21 @@ hb_feature_to_string (hb_feature_t *feature,
{
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));
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';
}
@ -1113,14 +1155,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. */

View file

@ -67,7 +67,7 @@ typedef unsigned __int64 uint64_t;
# include <stdint.h>
#endif
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define HB_DEPRECATED __attribute__((__deprecated__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
#define HB_DEPRECATED __declspec(deprecated)
@ -75,7 +75,7 @@ typedef unsigned __int64 uint64_t;
#define HB_DEPRECATED
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
@ -108,7 +108,7 @@ typedef union _hb_var_int_t {
typedef uint32_t hb_tag_t;
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
#define HB_UNTAG(tag) (((tag)>>24)&0xFF), (((tag)>>16)&0xFF), (((tag)>>8)&0xFF), ((tag)&0xFF)
#define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
#define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
@ -357,6 +357,14 @@ typedef enum
/*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'),
/*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'),
/*
* Since 2.4.0
*/
/*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'),
/*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'),
/*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'),
/*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'),
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
@ -459,39 +467,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

161
src/hb-config.hh Normal file
View file

@ -0,0 +1,161 @@
/*
* Copyright © 2019 Facebook, 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.
*
* Facebook Author(s): Behdad Esfahbod
*/
#ifndef HB_CONFIG_HH
#define HB_CONFIG_HH
#if 0 /* Make test happy. */
#include "hb.hh"
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HB_TINY
#define HB_LEAN
#define HB_MINI
#define HB_NO_MT
#define HB_NO_UCD_UNASSIGNED
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef __OPTIMIZE_SIZE__
#define __OPTIMIZE_SIZE__
#endif
#endif
#ifdef HB_LEAN
#define HB_DISABLE_DEPRECATED
#define HB_NDEBUG
#define HB_NO_ATEXIT
#define HB_NO_BUFFER_MESSAGE
#define HB_NO_BUFFER_SERIALIZE
#define HB_NO_BITMAP
#define HB_NO_CFF
#define HB_NO_COLOR
#define HB_NO_FACE_COLLECT_UNICODES
#define HB_NO_GETENV
#define HB_NO_HINTING
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
#define HB_NO_LAYOUT_FEATURE_PARAMS
#define HB_NO_LAYOUT_COLLECT_GLYPHS
#define HB_NO_LAYOUT_UNUSED
#define HB_NO_MATH
#define HB_NO_META
#define HB_NO_METRICS
#define HB_NO_MMAP
#define HB_NO_NAME
#define HB_NO_OPEN
#define HB_NO_SETLOCALE
#define HB_NO_OT_FONT_GLYPH_NAMES
#define HB_NO_OT_SHAPE_FRACTIONS
#define HB_NO_STAT
#define HB_NO_SUBSET_LAYOUT
#define HB_NO_VAR
#endif
#ifdef HB_MINI
#define HB_NO_AAT
#define HB_NO_LEGACY
#endif
/* Closure of options. */
#ifdef HB_DISABLE_DEPRECATED
#define HB_IF_NOT_DEPRECATED(x)
#else
#define HB_IF_NOT_DEPRECATED(x) x
#endif
#ifdef HB_NO_AAT
#define HB_NO_OT_NAME_LANGUAGE_AAT
#define HB_NO_AAT_SHAPE
#endif
#ifdef HB_NO_BITMAP
#define HB_NO_OT_FONT_BITMAP
#endif
#ifdef HB_NO_CFF
#define HB_NO_OT_FONT_CFF
#define HB_NO_SUBSET_CFF
#endif
#ifdef HB_NO_GETENV
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
#endif
#ifdef HB_NO_LEGACY
#define HB_NO_CMAP_LEGACY_SUBTABLES
#define HB_NO_FALLBACK_SHAPE
#define HB_NO_OT_KERN
#define HB_NO_OT_LAYOUT_BLACKLIST
#define HB_NO_OT_SHAPE_FALLBACK
#endif
#ifdef HB_NO_NAME
#define HB_NO_OT_NAME_LANGUAGE
#endif
#ifdef HB_NO_OT
#define HB_NO_OT_FONT
#define HB_NO_OT_LAYOUT
#define HB_NO_OT_TAG
#define HB_NO_OT_SHAPE
#endif
#ifdef HB_NO_OT_SHAPE
#define HB_NO_AAT_SHAPE
#endif
#ifdef HB_NO_OT_SHAPE_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
#endif
#ifdef NDEBUG
#ifndef HB_NDEBUG
#define HB_NDEBUG
#endif
#endif
#ifdef __OPTIMIZE_SIZE__
#ifndef HB_OPTIMIZE_SIZE
#define HB_OPTIMIZE_SIZE
#endif
#endif
#ifdef HAVE_CONFIG_OVERRIDE_H
#include "config-override.h"
#endif
#endif /* HB_CONFIG_HH */

View file

@ -27,6 +27,9 @@
*/
#include "hb.hh"
#ifdef HAVE_CORETEXT
#include "hb-shaper-impl.hh"
#include "hb-coretext.h"
@ -54,7 +57,7 @@ release_table_data (void *user_data)
}
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
@ -153,7 +156,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
# define kCTFontUIFontSystem kCTFontSystemFontType
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
#endif
@ -196,7 +199,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
}
CFURLRef original_url = nullptr;
#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ATSFontRef atsFont;
FSRef fsref;
OSStatus status;
@ -226,7 +229,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = nullptr;
#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
status = ATSFontGetFileReference (atsFont, &fsref);
if (status == noErr)
@ -278,7 +281,7 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
{
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
}
/*
@ -393,7 +396,7 @@ struct active_feature_t {
feature_record_t rec;
unsigned int order;
static int cmp (const void *pa, const void *pb) {
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
const active_feature_t *a = (const active_feature_t *) pa;
const active_feature_t *b = (const active_feature_t *) pb;
return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
@ -411,7 +414,7 @@ struct feature_event_t {
bool start;
active_feature_t feature;
static int cmp (const void *pa, const void *pb) {
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
const feature_event_t *a = (const feature_event_t *) pa;
const feature_event_t *b = (const feature_event_t *) pb;
return a->index < b->index ? -1 : a->index > b->index ? 1 :
@ -581,7 +584,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
} else {
active_feature_t *feature = active_features.find (&event->feature);
if (feature)
active_features.remove (feature - active_features.arrayZ ());
active_features.remove (feature - active_features.arrayZ);
}
}
}
@ -591,7 +594,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
Type *name = (Type *) scratch; \
{ \
do { \
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
if (unlikely (_consumed > scratch_size)) \
{ \
@ -600,7 +603,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
} \
scratch += _consumed; \
scratch_size -= _consumed; \
}
} while (0)
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
unsigned int chars_len = 0;
@ -632,7 +635,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
ret = false; \
goto fail; \
} HB_STMT_END;
} HB_STMT_END
bool ret = true;
CFStringRef string_ref = nullptr;
@ -694,7 +697,7 @@ resize_and_retry:
/* What's the iOS equivalent of this check?
* The symbols was introduced in iOS 7.0.
* At any rate, our fallback is safe and works fine. */
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090
# define kCTLanguageAttributeName CFSTR ("NSLanguage")
#endif
CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
@ -754,7 +757,7 @@ resize_and_retry:
feature.start < chars_len && feature.start < feature.end)
{
CFRange feature_range = CFRangeMake (feature.start,
MIN (feature.end, chars_len) - feature.start);
hb_min (feature.end, chars_len) - feature.start);
if (feature.value)
CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
else
@ -766,7 +769,7 @@ resize_and_retry:
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
#endif
CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
@ -960,7 +963,7 @@ resize_and_retry:
#define SCRATCH_RESTORE() \
scratch_size = scratch_size_saved; \
scratch = scratch_saved;
scratch = scratch_saved
{ /* Setup glyphs */
SCRATCH_SAVE();
@ -1052,7 +1055,7 @@ resize_and_retry:
if (false)
{
/* Make sure all runs had the expected direction. */
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
}
@ -1099,7 +1102,7 @@ resize_and_retry:
unsigned int cluster = info[count - 1].cluster;
for (unsigned int i = count - 1; i > 0; i--)
{
cluster = MIN (cluster, info[i - 1].cluster);
cluster = hb_min (cluster, info[i - 1].cluster);
info[i - 1].cluster = cluster;
}
}
@ -1108,7 +1111,7 @@ resize_and_retry:
unsigned int cluster = info[0].cluster;
for (unsigned int i = 1; i < count; i++)
{
cluster = MIN (cluster, info[i].cluster);
cluster = hb_min (cluster, info[i].cluster);
info[i].cluster = cluster;
}
}
@ -1133,57 +1136,4 @@ fail:
}
/*
* AAT shaper
*/
/*
* shaper face data
*/
struct hb_coretext_aat_face_data_t {};
hb_coretext_aat_face_data_t *
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
{
return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ?
(hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
}
void
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
{
}
/*
* shaper font data
*/
struct hb_coretext_aat_font_data_t {};
hb_coretext_aat_font_data_t *
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
{
return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
}
void
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
{
}
/*
* shaper
*/
hb_bool_t
_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
}
#endif

View file

@ -29,7 +29,7 @@
#include "hb.hh"
#include "hb-atomic.hh"
#include "hb-dsalgs.hh"
#include "hb-algs.hh"
#ifndef HB_DEBUG
@ -63,6 +63,9 @@ extern HB_INTERNAL hb_atomic_int_t _hb_options;
static inline hb_options_t
hb_options ()
{
#ifdef HB_NO_GETENV
return hb_options_t ();
#endif
/* Make a local copy, so we can access bitfield threadsafely. */
hb_options_union_t u;
u.i = _hb_options.get_relaxed ();
@ -158,7 +161,7 @@ _hb_debug_msg_va (const char *what,
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
fprintf (stderr, "%2u %s" VRBAR "%s",
level,
bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
} else
fprintf (stderr, " " VRBAR LBAR);
@ -246,8 +249,8 @@ struct hb_printer_t<bool> {
};
template <>
struct hb_printer_t<hb_void_t> {
const char *print (hb_void_t) { return ""; }
struct hb_printer_t<hb_empty_t> {
const char *print (hb_empty_t) { return ""; }
};
@ -263,7 +266,7 @@ static inline void _hb_warn_no_return (bool returned)
}
}
template <>
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
{}
template <int max_level, typename ret_t>
@ -327,18 +330,20 @@ struct hb_auto_trace_t<0, ret_t>
const char *message,
...) HB_PRINTF_FUNC(6, 7) {}
ret_t ret (ret_t v,
const char *func HB_UNUSED = nullptr,
unsigned int line HB_UNUSED = 0) { return v; }
template <typename T>
T ret (T&& v,
const char *func HB_UNUSED = nullptr,
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
};
/* For disabled tracing; optimize out everything.
* https://github.com/harfbuzz/harfbuzz/pull/605 */
template <typename ret_t>
struct hb_no_trace_t {
ret_t ret (ret_t v,
const char *func HB_UNUSED = "",
unsigned int line HB_UNUSED = 0) { return v; }
template <typename T>
T ret (T&& v,
const char *func HB_UNUSED = nullptr,
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
};
#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
@ -401,30 +406,6 @@ struct hb_no_trace_t {
#define TRACE_APPLY(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif
#if HB_DEBUG_CLOSURE
#define TRACE_CLOSURE(this) \
hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
" ")
#else
#define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
#endif
#ifndef HB_DEBUG_COLLECT_GLYPHS
#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
#endif
#if HB_DEBUG_COLLECT_GLYPHS
#define TRACE_COLLECT_GLYPHS(this) \
hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
" ")
#else
#define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
#endif
#ifndef HB_DEBUG_SANITIZE
#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
#endif
@ -461,27 +442,12 @@ struct hb_no_trace_t {
#define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_WOULD_APPLY
#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
#endif
#if HB_DEBUG_WOULD_APPLY
#define TRACE_WOULD_APPLY(this) \
hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
"%d glyphs", c->len);
#else
#define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_DISPATCH
#define HB_DEBUG_DISPATCH ( \
HB_DEBUG_APPLY + \
HB_DEBUG_CLOSURE + \
HB_DEBUG_COLLECT_GLYPHS + \
HB_DEBUG_SANITIZE + \
HB_DEBUG_SERIALIZE + \
HB_DEBUG_SUBSET + \
HB_DEBUG_WOULD_APPLY + \
HB_DEBUG_SUBSET + \
0)
#endif
#if HB_DEBUG_DISPATCH

View file

@ -63,7 +63,7 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t *glyph,
void *user_data);
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
@ -165,29 +165,8 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *decomposed);
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_v_kerning_func:
* @ffuncs: font functions.
@ -206,19 +185,9 @@ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_position_t
hb_font_get_glyph_v_kerning (hb_font_t *font,
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
#endif
HB_END_DECLS

View file

@ -1,5 +1,5 @@
/*
* Copyright © 2015-2018 Ebrahim Byagowi
* Copyright © 2015-2019 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
@ -23,13 +23,23 @@
*/
#include "hb.hh"
#ifdef HAVE_DIRECTWRITE
#include "hb-shaper-impl.hh"
#include <DWrite_1.h>
#include <dwrite_1.h>
#include "hb-directwrite.h"
/* Declare object creator for dynamic support of DWRITE */
typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
/*
* hb-directwrite uses new/delete syntatically but as we let users
* to override malloc/free, we will redefine new/delete so users
@ -71,6 +81,8 @@ public:
*fontFileStream = mFontFileStream;
return S_OK;
}
virtual ~DWriteFontFileLoader() {}
};
class DWriteFontFileStream : public IDWriteFontFileStream
@ -122,6 +134,8 @@ public:
virtual HRESULT STDMETHODCALLTYPE
GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
virtual ~DWriteFontFileStream() {}
};
@ -131,10 +145,11 @@ public:
struct hb_directwrite_face_data_t
{
HMODULE dwrite_dll;
IDWriteFactory *dwriteFactory;
IDWriteFontFile *fontFile;
IDWriteFontFileStream *fontFileStream;
IDWriteFontFileLoader *fontFileLoader;
DWriteFontFileStream *fontFileStream;
DWriteFontFileLoader *fontFileLoader;
IDWriteFontFace *fontFace;
hb_blob_t *faceBlob;
};
@ -146,12 +161,43 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
if (unlikely (!data))
return nullptr;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return nullptr; \
} HB_STMT_END
data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
if (unlikely (!data->dwrite_dll))
FAIL ("Cannot find DWrite.DLL");
t_DWriteCreateFactory p_DWriteCreateFactory;
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
if (unlikely (!p_DWriteCreateFactory))
FAIL ("Cannot find DWriteCreateFactory().");
HRESULT hr;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
if (unlikely (hr != S_OK))
FAIL ("Failed to run DWriteCreateFactory().");
hb_blob_t *blob = hb_face_reference_blob (face);
DWriteFontFileStream *fontFileStream;
fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
@ -165,12 +211,6 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
fontFileLoader, &fontFile);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return nullptr; \
} HB_STMT_END;
if (FAILED (hr))
FAIL ("Failed to load font file from data!");
@ -217,6 +257,8 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
delete data->fontFileStream;
if (data->faceBlob)
hb_blob_destroy (data->faceBlob);
if (data->dwrite_dll)
FreeLibrary (data->dwrite_dll);
if (data)
delete data;
}
@ -281,7 +323,7 @@ public:
public:
TextAnalysis (const wchar_t* text, uint32_t textLength,
const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
: mText (text), mTextLength (textLength), mLocaleName (localeName),
: mTextLength (textLength), mText (text), mLocaleName (localeName),
mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
~TextAnalysis ()
{
@ -497,11 +539,6 @@ protected:
Run mRunHead;
};
static inline uint16_t hb_uint16_swap (const uint16_t v)
{ return (v >> 8) | (v << 8); }
static inline uint32_t hb_uint32_swap (const uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
/*
* shaper
*/
@ -516,7 +553,6 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
{
hb_face_t *face = font->face;
const hb_directwrite_face_data_t *face_data = face->data.directwrite;
const hb_directwrite_font_data_t *font_data = font->data.directwrite;
IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
IDWriteFontFace *fontFace = face_data->fontFace;
@ -527,12 +563,12 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
#define ALLOCATE_ARRAY(Type, name, len) \
Type *name = (Type *) scratch; \
{ \
do { \
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
assert (_consumed <= scratch_size); \
scratch += _consumed; \
scratch_size -= _consumed; \
}
} while (0)
#define utf16_index() var1.u32
@ -655,10 +691,10 @@ retry_getglyphs:
* alignment needed after the WORD array. sizeof (WORD) == 2. */
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
/ (sizeof (WORD) +
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof (int) +
sizeof (DWRITE_GLYPH_OFFSET) +
sizeof (uint32_t));
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
sizeof (int) +
sizeof (DWRITE_GLYPH_OFFSET) +
sizeof (uint32_t));
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
#undef ALLOCATE_ARRAY
@ -770,15 +806,15 @@ retry_getglyphs:
/* Calculate visual-clusters. That's what we ship. */
for (unsigned int i = 0; i < glyphCount; i++)
vis_clusters[i] = -1;
vis_clusters[i] = (uint32_t) -1;
for (unsigned int i = 0; i < buffer->len; i++)
{
uint32_t *p =
&vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
*p = MIN (*p, buffer->info[i].cluster);
*p = hb_min (*p, buffer->info[i].cluster);
}
for (unsigned int i = 1; i < glyphCount; i++)
if (vis_clusters[i] == -1)
if (vis_clusters[i] == (uint32_t) -1)
vis_clusters[i] = vis_clusters[i - 1];
#undef utf16_index
@ -843,10 +879,23 @@ _hb_directwrite_shape (hb_shape_plan_t *shape_plan,
features, num_features, 0);
}
/*
* Public [experimental] API
*/
/**
* hb_directwrite_shape_experimental_width:
* Experimental API to test DirectWrite's justification algorithm.
*
* It inserts Kashida at wrong order so don't use the API ever.
*
* It doesn't work with cygwin/msys due to header bugs so one
* should use MSVC toolchain in order to use it for now.
*
* @font:
* @buffer:
* @features:
* @num_features:
* @width:
*
* Since: 1.4.2
**/
hb_bool_t
hb_directwrite_shape_experimental_width (hb_font_t *font,
hb_buffer_t *buffer,
@ -865,3 +914,83 @@ hb_directwrite_shape_experimental_width (hb_font_t *font,
return res;
}
struct _hb_directwrite_font_table_context {
IDWriteFontFace *face;
void *table_context;
};
static void
_hb_directwrite_table_data_release (void *data)
{
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
context->face->ReleaseFontTable (context->table_context);
delete context;
}
static hb_blob_t *
_hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
const void *data;
uint32_t length;
void *table_context;
BOOL exists;
if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
&length, &table_context, &exists)))
return nullptr;
if (!data || !exists || !length)
{
dw_face->ReleaseFontTable (table_context);
return nullptr;
}
_hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
context->face = dw_face;
context->table_context = table_context;
return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
context, _hb_directwrite_table_data_release);
}
static void
_hb_directwrite_font_release (void *data)
{
if (data)
((IDWriteFontFace *) data)->Release ();
}
/**
* hb_directwrite_face_create:
* @font_face: a DirectWrite IDWriteFontFace object.
*
* Return value: #hb_face_t object corresponding to the given input
*
* Since: 2.4.0
**/
hb_face_t *
hb_directwrite_face_create (IDWriteFontFace *font_face)
{
if (font_face)
font_face->AddRef ();
return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face,
_hb_directwrite_font_release);
}
/**
* hb_directwrite_face_get_font_face:
* @face: a #hb_face_t object
*
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
*
* Since: 2.5.0
**/
IDWriteFontFace *
hb_directwrite_face_get_font_face (hb_face_t *face)
{
return face->data.directwrite->fontFace;
}
#endif

View file

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

58
src/hb-dispatch.hh Normal file
View file

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

View file

@ -1,638 +0,0 @@
/*
* Copyright © 2017 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_DSALGS_HH
#define HB_DSALGS_HH
#include "hb.hh"
#include "hb-null.hh"
/* Void! For when we need a expression-type of void. */
typedef const struct _hb_void_t *hb_void_t;
#define HB_VOID ((const _hb_void_t *) nullptr)
/*
* Bithacks.
*/
/* Return the number of 1 bits in v. */
template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_popcount (T v)
{
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_popcountl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_popcountll (v);
#endif
if (sizeof (T) <= 4)
{
/* "HACKMEM 169" */
uint32_t y;
y = (v >> 1) &033333333333;
y = v - y - ((y >>1) & 033333333333);
return (((y + (y >> 3)) & 030707070707) % 077);
}
if (sizeof (T) == 8)
{
unsigned int shift = 32;
return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/* Returns the number of bits needed to store number */
template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v);
if (sizeof (T) <= sizeof (unsigned long))
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
_BitScanReverse (&where, v);
return 1 + where;
}
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanReverse64 (&where, v);
return 1 + where;
}
# endif
#endif
if (sizeof (T) <= 4)
{
/* "bithacks" */
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
unsigned int r = 0;
for (int i = 4; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r + 1;
}
if (sizeof (T) <= 8)
{
/* "bithacks" */
const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
unsigned int r = 0;
for (int i = 5; i >= 0; i--)
if (v & b[i])
{
v >>= S[i];
r |= S[i];
}
return r + 1;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
hb_bit_storage<uint64_t> ((uint64_t) v);
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/* Returns the number of zero bits in the least significant side of v */
template <typename T>
static inline HB_CONST_FUNC unsigned int
hb_ctz (T v)
{
if (unlikely (!v)) return 0;
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v);
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_ctzl (v);
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_ctzll (v);
#endif
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
if (sizeof (T) <= sizeof (unsigned int))
{
unsigned long where;
_BitScanForward (&where, v);
return where;
}
# if _WIN64
if (sizeof (T) <= 8)
{
unsigned long where;
_BitScanForward64 (&where, v);
return where;
}
# endif
#endif
if (sizeof (T) <= 4)
{
/* "bithacks" */
unsigned int c = 32;
v &= - (int32_t) v;
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;
return c;
}
if (sizeof (T) <= 8)
{
/* "bithacks" */
unsigned int c = 64;
v &= - (int64_t) (v);
if (v) c--;
if (v & 0x00000000FFFFFFFFULL) c -= 32;
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
if (v & 0x3333333333333333ULL) c -= 2;
if (v & 0x5555555555555555ULL) c -= 1;
return c;
}
if (sizeof (T) == 16)
{
unsigned int shift = 64;
return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
}
assert (0);
return 0; /* Shut up stupid compiler. */
}
/*
* Tiny stuff.
*/
template <typename T>
static inline T* hb_addressof (T& arg)
{
/* https://en.cppreference.com/w/cpp/memory/addressof */
return reinterpret_cast<T*>(
&const_cast<char&>(
reinterpret_cast<const volatile char&>(arg)));
}
/* ASCII tag/character handling */
static inline bool ISALPHA (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
static inline bool ISALNUM (unsigned char c)
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
static inline bool ISSPACE (unsigned char c)
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
static inline unsigned char TOUPPER (unsigned char c)
{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
static inline unsigned char TOLOWER (unsigned char c)
{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
#undef MIN
template <typename Type>
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
#undef MAX
template <typename Type>
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
{ return (a + (b - 1)) / b; }
#undef ARRAY_LENGTH
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
/* A const version, but does not detect erratically being called on pointers. */
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
static inline int
hb_memcmp (const void *a, const void *b, unsigned int len)
{
/* It's illegal to pass NULL to memcmp(), even if len is zero.
* So, wrap it.
* https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
if (!len) return 0;
return memcmp (a, b, len);
}
static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
{
return (size > 0) && (count >= ((unsigned int) -1) / size);
}
static inline unsigned int
hb_ceil_to_4 (unsigned int v)
{
return ((v - 1) | 3) + 1;
}
template <typename T> struct hb_is_signed;
template <> struct hb_is_signed<signed char> { enum { value = true }; };
template <> struct hb_is_signed<signed short> { enum { value = true }; };
template <> struct hb_is_signed<signed int> { enum { value = true }; };
template <> struct hb_is_signed<signed long> { enum { value = true }; };
template <> struct hb_is_signed<unsigned char> { enum { value = false }; };
template <> struct hb_is_signed<unsigned short> { enum { value = false }; };
template <> struct hb_is_signed<unsigned int> { enum { value = false }; };
template <> struct hb_is_signed<unsigned long> { enum { value = false }; };
/* We need to define hb_is_signed for the typedefs we use on pre-Visual
* Studio 2010 for the int8_t type, since __int8/__int64 is not considered
* the same as char/long. The previous lines will suffice for the other
* types, though. Note that somehow, unsigned __int8 is considered same
* as unsigned char.
* https://github.com/harfbuzz/harfbuzz/pull/1499
*/
#if defined(_MSC_VER) && (_MSC_VER < 1600)
template <> struct hb_is_signed<__int8> { enum { value = true }; };
#endif
template <typename T> static inline bool
hb_in_range (T u, T lo, T hi)
{
/* The sizeof() is here to force template instantiation.
* I'm sure there are better ways to do this but can't think of
* one right now. Declaring a variable won't work as HB_UNUSED
* is unusable on some platforms and unused types are less likely
* to generate a warning than unused variables. */
static_assert (!hb_is_signed<T>::value, "");
/* The casts below are important as if T is smaller than int,
* the subtract results will become a signed int! */
return (T)(u - lo) <= (T)(hi - lo);
}
template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
{
return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
}
template <typename T> static inline bool
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
{
return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
}
/*
* Sort and search.
*/
static inline void *
hb_bsearch (const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *_key, const void *_item))
{
int min = 0, max = (int) nmemb - 1;
while (min <= max)
{
int mid = (min + max) / 2;
const void *p = (const void *) (((const char *) base) + (mid * size));
int c = compar (key, p);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
return (void *) p;
}
return nullptr;
}
static inline void *
hb_bsearch_r (const void *key, const void *base,
size_t nmemb, size_t size,
int (*compar)(const void *_key, const void *_item, void *_arg),
void *arg)
{
int min = 0, max = (int) nmemb - 1;
while (min <= max)
{
int mid = ((unsigned int) min + (unsigned int) max) / 2;
const void *p = (const void *) (((const char *) base) + (mid * size));
int c = compar (key, p, arg);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
return (void *) p;
}
return nullptr;
}
/* From https://github.com/noporpoise/sort_r
* With following modifications:
*
* 10 November 2018:
* https://github.com/noporpoise/sort_r/issues/7
*/
/* Isaac Turner 29 April 2014 Public Domain */
/*
hb_sort_r function to be exported.
Parameters:
base is the array to be sorted
nel is the number of elements in the array
width is the size in bytes of each element of the array
compar is the comparison function
arg is a pointer to be passed to the comparison function
void hb_sort_r(void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg);
*/
/* swap a, b iff a>b */
/* __restrict is same as restrict but better support on old machines */
static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
int (*compar)(const void *_a, const void *_b,
void *_arg),
void *arg)
{
char tmp, *end = a+w;
if(compar(a, b, arg) > 0) {
for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
return 1;
}
return 0;
}
/* Note: quicksort is not stable, equivalent values may be swapped */
static inline void sort_r_simple(void *base, size_t nel, size_t w,
int (*compar)(const void *_a, const void *_b,
void *_arg),
void *arg)
{
char *b = (char *)base, *end = b + nel*w;
if(nel < 7) {
/* Insertion sort for arbitrarily small inputs */
char *pi, *pj;
for(pi = b+w; pi < end; pi += w) {
for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
}
}
else
{
/* nel > 6; Quicksort */
/* Use median of first, middle and last items as pivot */
char *x, *y, *xend, ch;
char *pl, *pm, *pr;
char *last = b+w*(nel-1), *tmp;
char *l[3];
l[0] = b;
l[1] = b+w*(nel/2);
l[2] = last;
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
if(compar(l[1],l[2],arg) > 0) {
tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
}
/* swap l[id], l[2] to put pivot as last element */
for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
ch = *x; *x = *y; *y = ch;
}
pl = b;
pr = last;
while(pl < pr) {
pm = pl+((pr-pl+1)>>1);
for(; pl < pm; pl += w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pr -= w; /* pivot now at pl */
break;
}
}
pm = pl+((pr-pl)>>1);
for(; pm < pr; pr -= w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pl += w; /* pivot now at pr */
break;
}
}
}
sort_r_simple(b, (pl-b)/w, w, compar, arg);
sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
}
}
static inline void hb_sort_r(void *base, size_t nel, size_t width,
int (*compar)(const void *_a, const void *_b, void *_arg),
void *arg)
{
sort_r_simple(base, nel, width, compar, arg);
}
template <typename T, typename T2> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
{
for (unsigned int i = 1; i < len; i++)
{
unsigned int j = i;
while (j && compar (&array[j - 1], &array[i]) > 0)
j--;
if (i == j)
continue;
/* Move item i to occupy place for item j, shift what's in between. */
{
T t = array[i];
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
array[j] = t;
}
if (array2)
{
T2 t = array2[i];
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
array2[j] = t;
}
}
}
template <typename T> static inline void
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
{
hb_stable_sort (array, len, compar, (int *) nullptr);
}
static inline hb_bool_t
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
{
/* Pain because we don't know whether s is nul-terminated. */
char buf[64];
len = MIN (ARRAY_LENGTH (buf) - 1, len);
strncpy (buf, s, len);
buf[len] = '\0';
char *end;
errno = 0;
unsigned long v = strtoul (buf, &end, base);
if (errno) return false;
if (*end) return false;
*out = v;
return true;
}
struct HbOpOr
{
enum { passthru_left = true };
enum { passthru_right = true };
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
};
struct HbOpAnd
{
enum { passthru_left = false };
enum { passthru_right = false };
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
};
struct HbOpMinus
{
enum { passthru_left = true };
enum { passthru_right = false };
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
};
struct HbOpXor
{
enum { passthru_left = true };
enum { passthru_right = true };
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
};
/* Compiler-assisted vectorization. */
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
* using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
* Define that to 0 to disable. */
template <typename elt_t, unsigned int byte_size>
struct hb_vector_size_t
{
elt_t& operator [] (unsigned int i) { return u.v[i]; }
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
template <class Op>
hb_vector_size_t process (const hb_vector_size_t &o) const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
return r;
}
hb_vector_size_t operator | (const hb_vector_size_t &o) const
{ return process<HbOpOr> (o); }
hb_vector_size_t operator & (const hb_vector_size_t &o) const
{ return process<HbOpAnd> (o); }
hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
{ return process<HbOpXor> (o); }
hb_vector_size_t operator ~ () const
{
hb_vector_size_t r;
#if HB_VECTOR_SIZE && 0
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
r.u.vec[i] = ~u.vec[i];
else
#endif
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
r.u.v[i] = ~u.v[i];
return r;
}
private:
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
union {
elt_t v[byte_size / sizeof (elt_t)];
#if HB_VECTOR_SIZE
hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
#endif
} u;
};
#endif /* HB_DSALGS_HH */

View file

@ -531,6 +531,7 @@ hb_face_get_table_tags (const hb_face_t *face,
*/
#ifndef HB_NO_FACE_COLLECT_UNICODES
/**
* hb_face_collect_unicodes:
* @face: font face.
@ -544,7 +545,6 @@ hb_face_collect_unicodes (hb_face_t *face,
{
face->table.cmap->collect_unicodes (out);
}
/**
* hb_face_collect_variation_selectors:
* @face: font face.
@ -560,7 +560,6 @@ hb_face_collect_variation_selectors (hb_face_t *face,
{
face->table.cmap->collect_variation_selectors (out);
}
/**
* hb_face_collect_variation_unicodes:
* @face: font face.
@ -577,7 +576,7 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
{
face->table.cmap->collect_variation_unicodes (variation_selector, out);
}
#endif
/*

View file

@ -26,6 +26,7 @@
#include "hb-shaper-impl.hh"
#ifndef HB_NO_FALLBACK_SHAPE
/*
* shaper face data
@ -120,3 +121,5 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
return true;
}
#endif

View file

@ -139,10 +139,10 @@ hb_font_get_nominal_glyphs_default (hb_font_t *font,
for (unsigned int i = 0; i < count; i++)
{
if (!font->get_nominal_glyph (*first_unicode, first_glyph))
return i;
return i;
first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
}
return count;
}
@ -238,8 +238,8 @@ hb_font_get_glyph_h_advances_default (hb_font_t* font,
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->get_glyph_h_advance (*first_glyph);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
return;
}
@ -250,7 +250,7 @@ hb_font_get_glyph_h_advances_default (hb_font_t* font,
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->parent_scale_x_distance (*first_advance);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
@ -270,8 +270,8 @@ hb_font_get_glyph_v_advances_default (hb_font_t* font,
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->get_glyph_v_advance (*first_glyph);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
return;
}
@ -282,7 +282,7 @@ hb_font_get_glyph_v_advances_default (hb_font_t* font,
for (unsigned int i = 0; i < count; i++)
{
*first_advance = font->parent_scale_y_distance (*first_advance);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
@ -355,6 +355,7 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font,
return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
}
#ifndef HB_DISABLE_DEPRECATED
static hb_position_t
hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
@ -373,6 +374,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font,
{
return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
}
#endif
static hb_bool_t
hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
@ -516,9 +518,9 @@ static const hb_font_funcs_t _hb_font_funcs_default = {
/**
* hb_font_funcs_create: (Xconstructor)
*
*
*
* Return value: (transfer full):
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
@ -538,9 +540,9 @@ hb_font_funcs_create ()
/**
* hb_font_funcs_get_empty:
*
*
*
* Return value: (transfer full):
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
@ -554,9 +556,9 @@ hb_font_funcs_get_empty ()
* hb_font_funcs_reference: (skip)
* @ffuncs: font functions.
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -570,7 +572,7 @@ hb_font_funcs_reference (hb_font_funcs_t *ffuncs)
* hb_font_funcs_destroy: (skip)
* @ffuncs: font functions.
*
*
*
*
* Since: 0.9.2
**/
@ -590,14 +592,14 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
/**
* hb_font_funcs_set_user_data: (skip)
* @ffuncs: font functions.
* @key:
* @data:
* @destroy:
* @replace:
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -614,11 +616,11 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
/**
* hb_font_funcs_get_user_data: (skip)
* @ffuncs: font functions.
* @key:
* @key:
*
*
*
* Return value: (transfer none):
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
@ -634,7 +636,7 @@ hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
* hb_font_funcs_make_immutable:
* @ffuncs: font functions.
*
*
*
*
* Since: 0.9.2
**/
@ -651,9 +653,9 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs)
* hb_font_funcs_is_immutable:
* @ffuncs: font functions.
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -749,13 +751,13 @@ hb_font_get_v_extents (hb_font_t *font,
/**
* hb_font_get_glyph:
* @font: a font.
* @unicode:
* @variation_selector:
* @glyph: (out):
* @unicode:
* @variation_selector:
* @glyph: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -772,12 +774,12 @@ hb_font_get_glyph (hb_font_t *font,
/**
* hb_font_get_nominal_glyph:
* @font: a font.
* @unicode:
* @glyph: (out):
* @unicode:
* @glyph: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 1.2.3
**/
@ -792,13 +794,13 @@ hb_font_get_nominal_glyph (hb_font_t *font,
/**
* hb_font_get_variation_glyph:
* @font: a font.
* @unicode:
* @variation_selector:
* @glyph: (out):
* @unicode:
* @variation_selector:
* @glyph: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 1.2.3
**/
@ -813,11 +815,11 @@ hb_font_get_variation_glyph (hb_font_t *font,
/**
* hb_font_get_glyph_h_advance:
* @font: a font.
* @glyph:
* @glyph:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -831,11 +833,11 @@ hb_font_get_glyph_h_advance (hb_font_t *font,
/**
* hb_font_get_glyph_v_advance:
* @font: a font.
* @glyph:
* @glyph:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -850,7 +852,7 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
* hb_font_get_glyph_h_advances:
* @font: a font.
*
*
*
*
* Since: 1.8.6
**/
@ -868,7 +870,7 @@ hb_font_get_glyph_h_advances (hb_font_t* font,
* hb_font_get_glyph_v_advances:
* @font: a font.
*
*
*
*
* Since: 1.8.6
**/
@ -886,13 +888,13 @@ hb_font_get_glyph_v_advances (hb_font_t* font,
/**
* hb_font_get_glyph_h_origin:
* @font: a font.
* @glyph:
* @x: (out):
* @y: (out):
* @glyph:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -907,13 +909,13 @@ hb_font_get_glyph_h_origin (hb_font_t *font,
/**
* hb_font_get_glyph_v_origin:
* @font: a font.
* @glyph:
* @x: (out):
* @y: (out):
* @glyph:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -928,15 +930,14 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
/**
* hb_font_get_glyph_h_kerning:
* @font: a font.
* @left_glyph:
* @right_glyph:
* @left_glyph:
* @right_glyph:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
@ -945,15 +946,16 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
return font->get_glyph_h_kerning (left_glyph, right_glyph);
}
#ifndef HB_DISABLE_DEPRECATED
/**
* hb_font_get_glyph_v_kerning:
* @font: a font.
* @top_glyph:
* @bottom_glyph:
* @top_glyph:
* @bottom_glyph:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
* Deprecated: 2.0.0
@ -964,16 +966,17 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
{
return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
}
#endif
/**
* hb_font_get_glyph_extents:
* @font: a font.
* @glyph:
* @extents: (out):
* @glyph:
* @extents: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -988,14 +991,14 @@ hb_font_get_glyph_extents (hb_font_t *font,
/**
* hb_font_get_glyph_contour_point:
* @font: a font.
* @glyph:
* @point_index:
* @x: (out):
* @y: (out):
* @glyph:
* @point_index:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1010,13 +1013,13 @@ hb_font_get_glyph_contour_point (hb_font_t *font,
/**
* hb_font_get_glyph_name:
* @font: a font.
* @glyph:
* @name: (array length=size):
* @size:
* @glyph:
* @name: (array length=size):
* @size:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1031,13 +1034,13 @@ hb_font_get_glyph_name (hb_font_t *font,
/**
* hb_font_get_glyph_from_name:
* @font: a font.
* @name: (array length=len):
* @len:
* @glyph: (out):
* @name: (array length=len):
* @len:
* @glyph: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1072,12 +1075,12 @@ hb_font_get_extents_for_direction (hb_font_t *font,
/**
* hb_font_get_glyph_advance_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
*
* Since: 0.9.2
**/
@ -1092,9 +1095,9 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
/**
* hb_font_get_glyph_advances_for_direction:
* @font: a font.
* @direction:
* @direction:
*
*
*
*
* Since: 1.8.6
**/
@ -1113,12 +1116,12 @@ hb_font_get_glyph_advances_for_direction (hb_font_t* font,
/**
* hb_font_get_glyph_origin_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
*
* Since: 0.9.2
**/
@ -1134,12 +1137,12 @@ hb_font_get_glyph_origin_for_direction (hb_font_t *font,
/**
* hb_font_add_glyph_origin_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
*
* Since: 0.9.2
**/
@ -1155,12 +1158,12 @@ hb_font_add_glyph_origin_for_direction (hb_font_t *font,
/**
* hb_font_subtract_glyph_origin_for_direction:
* @font: a font.
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
* @glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
*
* Since: 0.9.2
**/
@ -1176,16 +1179,15 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
/**
* hb_font_get_glyph_kerning_for_direction:
* @font: a font.
* @first_glyph:
* @second_glyph:
* @direction:
* @x: (out):
* @y: (out):
* @first_glyph:
* @second_glyph:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
*
* Since: 0.9.2
* Deprecated: 2.0.0
**/
void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
@ -1199,13 +1201,13 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
/**
* hb_font_get_glyph_extents_for_origin:
* @font: a font.
* @glyph:
* @direction:
* @extents: (out):
* @glyph:
* @direction:
* @extents: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1221,15 +1223,15 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font,
/**
* hb_font_get_glyph_contour_point_for_origin:
* @font: a font.
* @glyph:
* @point_index:
* @direction:
* @x: (out):
* @y: (out):
* @glyph:
* @point_index:
* @direction:
* @x: (out):
* @y: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1246,11 +1248,11 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font,
/**
* hb_font_glyph_to_string:
* @font: a font.
* @glyph:
* @s: (array length=size):
* @size:
* @glyph:
* @s: (array length=size):
* @size:
*
*
*
*
* Since: 0.9.2
**/
@ -1266,13 +1268,13 @@ hb_font_glyph_to_string (hb_font_t *font,
/**
* hb_font_glyph_from_string:
* @font: a font.
* @s: (array length=len) (element-type uint8_t):
* @len:
* @glyph: (out):
* @s: (array length=len) (element-type uint8_t):
* @len:
* @glyph: (out):
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1298,6 +1300,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
1000, /* x_scale */
1000, /* y_scale */
1<<16, /* x_mult */
1<<16, /* y_mult */
0, /* x_ppem */
0, /* y_ppem */
@ -1328,6 +1332,7 @@ _hb_font_create (hb_face_t *face)
font->klass = hb_font_funcs_get_empty ();
font->data.init0 (font);
font->x_scale = font->y_scale = hb_face_get_upem (face);
font->x_mult = font->y_mult = 1 << 16;
return font;
}
@ -1336,9 +1341,9 @@ _hb_font_create (hb_face_t *face)
* hb_font_create: (Xconstructor)
* @face: a face.
*
*
*
* Return value: (transfer full):
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
@ -1347,8 +1352,10 @@ hb_font_create (hb_face_t *face)
{
hb_font_t *font = _hb_font_create (face);
#ifndef HB_NO_OT_FONT
/* Install our in-house, very lightweight, funcs. */
hb_ot_font_set_funcs (font);
#endif
return font;
}
@ -1357,9 +1364,9 @@ hb_font_create (hb_face_t *face)
* hb_font_create_sub_font:
* @parent: parent font.
*
*
*
* Return value: (transfer full):
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
@ -1383,9 +1390,7 @@ hb_font_create_sub_font (hb_font_t *parent)
font->ptem = parent->ptem;
font->num_coords = parent->num_coords;
if (!font->num_coords)
font->coords = nullptr;
else
if (font->num_coords)
{
unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
font->coords = (int *) malloc (size);
@ -1401,7 +1406,7 @@ hb_font_create_sub_font (hb_font_t *parent)
/**
* hb_font_get_empty:
*
*
*
*
* Return value: (transfer full)
*
@ -1417,9 +1422,9 @@ hb_font_get_empty ()
* hb_font_reference: (skip)
* @font: a font.
*
*
*
* Return value: (transfer full):
*
* Return value: (transfer full):
*
* Since: 0.9.2
**/
@ -1433,7 +1438,7 @@ hb_font_reference (hb_font_t *font)
* hb_font_destroy: (skip)
* @font: a font.
*
*
*
*
* Since: 0.9.2
**/
@ -1459,14 +1464,14 @@ hb_font_destroy (hb_font_t *font)
/**
* hb_font_set_user_data: (skip)
* @font: a font.
* @key:
* @data:
* @destroy:
* @replace:
* @key:
* @data:
* @destroy:
* @replace:
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1483,11 +1488,11 @@ hb_font_set_user_data (hb_font_t *font,
/**
* hb_font_get_user_data: (skip)
* @font: a font.
* @key:
* @key:
*
*
*
* Return value: (transfer none):
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
@ -1502,7 +1507,7 @@ hb_font_get_user_data (hb_font_t *font,
* hb_font_make_immutable:
* @font: a font.
*
*
*
*
* Since: 0.9.2
**/
@ -1522,9 +1527,9 @@ hb_font_make_immutable (hb_font_t *font)
* hb_font_is_immutable:
* @font: a font.
*
*
*
* Return value:
*
* Return value:
*
* Since: 0.9.2
**/
@ -1564,9 +1569,9 @@ hb_font_set_parent (hb_font_t *font,
* hb_font_get_parent:
* @font: a font.
*
*
*
* Return value: (transfer none):
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
@ -1597,7 +1602,9 @@ hb_font_set_face (hb_font_t *font,
hb_face_t *old = font->face;
hb_face_make_immutable (face);
font->face = hb_face_reference (face);
font->mults_changed ();
hb_face_destroy (old);
}
@ -1606,9 +1613,9 @@ hb_font_set_face (hb_font_t *font,
* hb_font_get_face:
* @font: a font.
*
*
*
* Return value: (transfer none):
*
* Return value: (transfer none):
*
* Since: 0.9.2
**/
@ -1623,10 +1630,10 @@ hb_font_get_face (hb_font_t *font)
* hb_font_set_funcs:
* @font: a font.
* @klass: (closure font_data) (destroy destroy) (scope notified):
* @font_data:
* @destroy:
* @font_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -1660,9 +1667,9 @@ hb_font_set_funcs (hb_font_t *font,
* hb_font_set_funcs_data:
* @font: a font.
* @font_data: (destroy destroy) (scope notified):
* @destroy:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -1690,10 +1697,10 @@ hb_font_set_funcs_data (hb_font_t *font,
/**
* hb_font_set_scale:
* @font: a font.
* @x_scale:
* @y_scale:
* @x_scale:
* @y_scale:
*
*
*
*
* Since: 0.9.2
**/
@ -1707,15 +1714,16 @@ hb_font_set_scale (hb_font_t *font,
font->x_scale = x_scale;
font->y_scale = y_scale;
font->mults_changed ();
}
/**
* hb_font_get_scale:
* @font: a font.
* @x_scale: (out):
* @y_scale: (out):
* @x_scale: (out):
* @y_scale: (out):
*
*
*
*
* Since: 0.9.2
**/
@ -1731,10 +1739,10 @@ hb_font_get_scale (hb_font_t *font,
/**
* hb_font_set_ppem:
* @font: a font.
* @x_ppem:
* @y_ppem:
* @x_ppem:
* @y_ppem:
*
*
*
*
* Since: 0.9.2
**/
@ -1753,10 +1761,10 @@ hb_font_set_ppem (hb_font_t *font,
/**
* hb_font_get_ppem:
* @font: a font.
* @x_ppem: (out):
* @y_ppem: (out):
* @x_ppem: (out):
* @y_ppem: (out):
*
*
*
*
* Since: 0.9.2
**/
@ -1805,6 +1813,7 @@ hb_font_get_ptem (hb_font_t *font)
return font->ptem;
}
#ifndef HB_NO_VAR
/*
* Variations
*/
@ -1872,6 +1881,33 @@ hb_font_set_var_coords_design (hb_font_t *font,
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
/**
* hb_font_set_var_named_instance:
* @font: a font.
* @instance_index: named instance index.
*
* Sets design coords of a font from a named instance index.
*
* Since: 2.6.0
*/
void
hb_font_set_var_named_instance (hb_font_t *font,
unsigned instance_index)
{
if (hb_object_is_immutable (font))
return;
unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
if (unlikely (coords_length && !coords))
return;
hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
hb_font_set_var_coords_design (font, coords, coords_length);
free (coords);
}
/**
* hb_font_set_var_coords_normalized:
*
@ -1912,8 +1948,9 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
return font->coords;
}
#endif
#ifndef HB_DISABLE_DEPRECATED
/*
* Deprecated get_glyph_func():
*/
@ -2036,3 +2073,4 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
trampoline,
trampoline_destroy);
}
#endif

View file

@ -157,6 +157,11 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
void *user_data);
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
@ -219,7 +224,7 @@ hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 1.2.3
**/
@ -251,7 +256,7 @@ hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 1.2.3
**/
@ -267,7 +272,7 @@ hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -283,7 +288,7 @@ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -299,7 +304,7 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 1.8.6
**/
@ -315,7 +320,7 @@ hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 1.8.6
**/
@ -331,7 +336,7 @@ hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -347,7 +352,7 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -356,6 +361,22 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_v_origin_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_h_kerning_func:
* @ffuncs: font functions.
* @func: (closure user_data) (destroy destroy) (scope notified):
* @user_data:
* @destroy:
*
*
*
* Since: 0.9.2
**/
HB_EXTERN void
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_h_kerning_func_t func,
void *user_data, hb_destroy_func_t destroy);
/**
* hb_font_funcs_set_glyph_extents_func:
* @ffuncs: font functions.
@ -363,7 +384,7 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -379,7 +400,7 @@ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -395,7 +416,7 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -411,7 +432,7 @@ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
* @user_data:
* @destroy:
*
*
*
*
* Since: 0.9.2
**/
@ -469,6 +490,10 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_position_t
hb_font_get_glyph_h_kerning (hb_font_t *font,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents (hb_font_t *font,
hb_codepoint_t glyph,
@ -531,6 +556,12 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN void
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
hb_direction_t direction,
hb_position_t *x, hb_position_t *y);
HB_EXTERN hb_bool_t
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
hb_codepoint_t glyph,
@ -674,6 +705,10 @@ HB_EXTERN const int *
hb_font_get_var_coords_normalized (hb_font_t *font,
unsigned int *length);
HB_EXTERN void
hb_font_set_var_named_instance (hb_font_t *font,
unsigned instance_index);
HB_END_DECLS
#endif /* HB_FONT_H */

View file

@ -52,7 +52,7 @@
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
@ -107,8 +107,10 @@ struct hb_font_t
hb_font_t *parent;
hb_face_t *face;
int x_scale;
int y_scale;
int32_t x_scale;
int32_t y_scale;
int64_t x_mult;
int64_t y_mult;
unsigned int x_ppem;
unsigned int y_ppem;
@ -127,16 +129,16 @@ struct hb_font_t
/* Convert from font-space to user-space */
int dir_scale (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
int64_t dir_mult (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_scale (v, dir_scale (direction)); }
{ return em_mult (v, dir_mult (direction)); }
/* Convert from parent-font user-space to our user-space */
hb_position_t parent_scale_x_distance (hb_position_t v)
@ -304,17 +306,25 @@ struct hb_font_t
hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph)
{
#ifdef HB_DISABLE_DEPRECATED
return 0;
#else
return klass->get.f.glyph_h_kerning (this, user_data,
left_glyph, right_glyph,
klass->user_data.glyph_h_kerning);
#endif
}
hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
hb_codepoint_t bottom_glyph)
{
#ifdef HB_DISABLE_DEPRECATED
return 0;
#else
return klass->get.f.glyph_v_kerning (this, user_data,
top_glyph, bottom_glyph,
klass->user_data.glyph_v_kerning);
#endif
}
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
@ -599,15 +609,19 @@ struct hb_font_t
return false;
}
hb_position_t em_scale (int16_t v, int scale)
void mults_changed ()
{
int upem = face->get_upem ();
int64_t scaled = v * (int64_t) scale;
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
return (hb_position_t) (scaled / upem);
signed upem = face->get_upem ();
x_mult = ((int64_t) x_scale << 16) / upem;
y_mult = ((int64_t) y_scale << 16) / upem;
}
hb_position_t em_mult (int16_t v, int64_t mult)
{
return (hb_position_t) ((v * mult) >> 16);
}
hb_position_t em_scalef (float v, int scale)
{ return (hb_position_t) round (v * scale / face->get_upem ()); }
{ return (hb_position_t) roundf (v * scale / face->get_upem ()); }
float em_fscale (int16_t v, int scale)
{ return (float) v * scale / face->get_upem (); }
};

View file

@ -29,6 +29,8 @@
#include "hb.hh"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#include "hb-font.hh"
@ -96,7 +98,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
ft_font->cached_x_scale.set (0);
ft_font->cached_x_scale.set_relaxed (0);
ft_font->advance_cache.init ();
return ft_font;
@ -228,8 +230,8 @@ hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
done++)
{
first_unicode = &StructAtOffset<hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
}
/* We don't need to do ft_font->symbol dance here, since HB calls the singular
* nominal_glyph() for what we don't handle here. */
@ -292,8 +294,8 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
*first_advance = (v * mult + (1<<9)) >> 10;
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
}
@ -346,6 +348,25 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
return true;
}
#ifndef HB_NO_OT_SHAPE_FALLBACK
static hb_position_t
hb_ft_get_glyph_h_kerning (hb_font_t *font,
void *font_data,
hb_codepoint_t left_glyph,
hb_codepoint_t right_glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
FT_Vector kerningv;
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
return 0;
return kerningv.x;
}
#endif
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font,
void *font_data,
@ -439,7 +460,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
else {
/* Make a nul-terminated version. */
char buf[128];
len = MIN (len, (int) sizeof (buf) - 1);
len = hb_min (len, (int) sizeof (buf) - 1);
strncpy (buf, name, len);
buf[len] = '\0';
*glyph = FT_Get_Name_Index (ft_face, buf);
@ -497,6 +518,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
#ifndef HB_NO_OT_SHAPE_FALLBACK
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
#endif
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
@ -539,7 +564,7 @@ _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
static hb_blob_t *
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
FT_Face ft_face = (FT_Face) user_data;
FT_Byte *buffer;
@ -594,7 +619,7 @@ hb_ft_face_create (FT_Face ft_face,
face = hb_face_create (blob, ft_face->face_index);
hb_blob_destroy (blob);
} else {
face = hb_face_create_for_tables (reference_table, ft_face, destroy);
face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
}
hb_face_set_index (face, ft_face->face_index);
@ -748,7 +773,7 @@ hb_ft_font_create_referenced (FT_Face ft_face)
static void free_static_ft_library ();
#endif
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
hb_ft_library_lazy_loader_t>
{
static FT_Library create ()
@ -854,3 +879,6 @@ hb_ft_font_set_funcs (hb_font_t *font)
_hb_ft_font_set_funcs (font, ft_face, true);
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
}
#endif

73
src/hb-gdi.cc Normal file
View file

@ -0,0 +1,73 @@
/*
* 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.
*/
#include "hb.hh"
#ifdef HAVE_GDI
#include "hb-gdi.h"
static hb_blob_t *
_hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
{
char *buffer = nullptr;
DWORD length = 0;
HDC hdc = GetDC (nullptr);
if (unlikely (!SelectObject (hdc, (HFONT) user_data))) goto fail;
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
buffer = (char *) malloc (length);
if (unlikely (!buffer)) goto fail_with_releasedc;
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
ReleaseDC (nullptr, hdc);
return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free);
fail_with_releasedc_and_free:
free (buffer);
fail_with_releasedc:
ReleaseDC (nullptr, hdc);
fail:
return hb_blob_get_empty ();
}
/**
* hb_gdi_face_create:
* @hdc: a HFONT object.
*
* Return value: #hb_face_t object corresponding to the given input
*
* Since: 2.6.0
**/
hb_face_t *
hb_gdi_face_create (HFONT hfont)
{
return hb_face_create_for_tables (_hb_gdi_reference_table, (void *) hfont, nullptr);
}
#endif

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