Merge with master

This commit is contained in:
Ebrahim Byagowi 2018-02-27 20:15:54 +03:30
commit 101850f9e6
841 changed files with 34398 additions and 9214 deletions

View File

@ -3,6 +3,8 @@
set -x
set -o errexit -o nounset
if test "x$TRAVIS_SECURE_ENV_VARS" != xtrue; then exit; fi
BRANCH="$TRAVIS_BRANCH"
if test "x$BRANCH" != xmaster; then exit; fi
@ -16,18 +18,19 @@ mkdir $DOCSDIR
cd $DOCSDIR
cp ../docs/html/* .
#cp ../docs/CNAME .
git init
git config user.name "Travis CI"
git config user.email "travis@harfbuzz.org"
set +x
echo "git remote add upstream \"https://\$GH_TOKEN@github.com/$TRAVIS_REPO_SLUG.git\""
git remote add upstream "https://$GH_TOKEN@github.com/$TRAVIS_REPO_SLUG.git"
echo "git remote add upstream \"https://\$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git\""
git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.github.io.git"
set -x
git fetch upstream
git reset upstream/gh-pages
git reset upstream/master
touch .
git add -A .
git commit -m "Rebuild docs for $REVISION"
git push -q upstream HEAD:gh-pages
git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION"
git push -q upstream HEAD:master

18
.ci/fail.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
for f in $(find . -name '*.log' -not -name 'config.log'); do
last=$(tail -1 $f)
if [[ $last = FAIL* ]]; then
echo '====' $f '===='
cat $f
elif [[ $last = PASS* ]]; then
# Do nothing.
true
else
# Travis Linux images has an old automake that does not match the
# patterns above, so in case of doubt just print the file.
cat $f
fi
done
exit 1

14
.ci/run-coveralls.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/bash
set -x
set -o errexit -o nounset
if test "x$TRAVIS_SLUG" != x"harfbuzz/harfbuzz"; then exit; fi
pip install --user nose
pip install --user cpp-coveralls
export PATH=$HOME/.local/bin:$PATH
rm -f src/.libs/NONE.gcov
touch src/NONE
coveralls -e docs

13
.ci/trigger-coverity.sh Normal file
View File

@ -0,0 +1,13 @@
#!/bin/bash
set -x
set -o errexit -o nounset
if test "x$TRAVIS_EVENT_TYPE" != x"cron"; then exit; fi
BRANCH="$TRAVIS_BRANCH"
if test "x$BRANCH" != xmaster; then exit; fi
git fetch --unshallow
git remote add upstream "https://$GH_TOKEN@github.com/harfbuzz/harfbuzz.git"
git push -q upstream master:coverity_scan

190
.circleci/config.yml Normal file
View File

@ -0,0 +1,190 @@
version: 2
jobs:
distcheck:
docker:
- image: ubuntu:17.10
steps:
- checkout
- run: apt update && apt install -y ninja-build binutils libtool autoconf automake make cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: ./autogen.sh
- run: make
- run: make distcheck || .ci/fail.sh
- run: rm -rf harfbuzz-*
- run: make distdir && cd harfbuzz-* && cmake -DHB_CHECK=ON -Bbuild -H. -GNinja && ninja -Cbuild && CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test && ninja -Cbuild install
alpine-O3:
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
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O3" CXXFLAGS="-O3" ./autogen.sh
- run: make
- run: make check || .ci/fail.sh
archlinux-debug-O0:
docker:
- image: base/devel
steps:
- checkout
- run: pacman --noconfirm -Syu freetype2 cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python
# C??FLAGS are not needed for a regular build
- run: CFLAGS="-O0" CXXFLAGS="-O0" CPPFLAGS="-DHB_DEBUG" ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: make
- run: make check || .ci/fail.sh
clang-O3-O0:
docker:
- image: multiarch/crossbuild
steps:
- checkout
- run: apt update && apt install -y ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- run: CFLAGS="-O3" CXXFLAGS="-O3" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
- run: CFLAGS="-O0" CXXFLAGS="-O0" CC=clang CXX=clang++ ./autogen.sh --with-freetype --with-glib --with-cairo --with-icu --with-graphite2
- run: make
- run: LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs" make check || .ci/fail.sh
fedora-outoftreebuild:
docker:
- image: fedora
steps:
- checkout
- run: dnf install -y pkg-config ragel gcc gcc-c++ automake autoconf libtool make which glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python || true
- run: NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
- run: mkdir build && cd build && ../configure && make && (make check || ../.ci/fail.sh)
cmake-gcc:
docker:
- image: ubuntu:17.10
steps:
- checkout
- run: apt update && apt install -y ninja-build binutils cmake gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python python-pip
- run: pip install fonttools
- run: cmake -DHB_CHECK=ON -Bbuild -H. -GNinja
- run: ninja -Cbuild
- run: CTEST_OUTPUT_ON_FAILURE=1 ninja -Cbuild test
- run: ninja -Cbuild install
cmake-oracledeveloperstudio:
docker:
- image: fedora
steps:
- checkout
- run: dnf install -y gcc ragel cmake make which glib2-devel freetype-devel cairo-devel libicu-devel graphite2-devel wget tar bzip2 python || true
- run: wget http://$ODSUSER:$ODSPASS@behdad.org/harfbuzz-private/OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 && tar xf OracleDeveloperStudio12.6-linux-x86-bin.tar.bz2 --owner root --group root --no-same-owner
- run: CC=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/suncc CXX=/root/project/OracleDeveloperStudio12.6-linux-x86-bin/developerstudio12.6/bin/sunCC cmake -DHB_HAVE_GRAPHITE2=ON -DHB_BUILTIN_UCDN=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_ICU=ON -DHB_HAVE_FREETYPE=ON -Bbuild -H.
- run: make -Cbuild
- run: CTEST_OUTPUT_ON_FAILURE=1 make -Cbuild test
- run: make -Cbuild install
crosscompile-notest-djgpp:
docker:
- image: quay.io/ebraminio/djgpp
steps:
- checkout
- run: apt update && apt install -y ragel pkg-config libtool autoconf
- run: CFLAGS="-Wno-attributes" CXXFLAGS="-Wno-attributes" ./autogen.sh --prefix=/usr/local/djgpp --host=i586-pc-msdosdjgpp
- run: make
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
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: ./autogen.sh --prefix=/usr/local/vitasdk/arm-vita-eabi --host=arm-vita-eabi
- run: make
crosscompile-cmake-notest-android-arm:
docker:
- image: dockcross/android-arm
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
crosscompile-cmake-notest-browser-asmjs:
docker:
- image: dockcross/browser-asmjs
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
crosscompile-cmake-notest-linux-arm64:
docker:
- image: dockcross/linux-arm64
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
crosscompile-cmake-notest-linux-mips:
docker:
- image: dockcross/linux-mips
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
crosscompile-cmake-notest-windows-x64:
docker:
- image: dockcross/windows-x64
steps:
- checkout
- run: apt update && apt install ragel
- run: cmake -Bbuild -H. -GNinja
- run: ninja -Cbuild
workflows:
version: 2
build:
jobs:
# both autotools and cmake
- distcheck
# autotools based builds
- alpine-O3
- archlinux-debug-O0
- clang-O3-O0
- fedora-outoftreebuild
# cmake based builds
- cmake-gcc
- 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-linux-arm64
- crosscompile-cmake-notest-linux-mips
- crosscompile-cmake-notest-windows-x64

18
.editorconfig Normal file
View File

@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
trim_trailing_whitespace = true
end_of_line = lf
insert_final_newline = true
[*.{c,cc,h,hh}]
indent_size = 2
indent_style = space
tab_width = 8
[*.{py,sh}]
indent_style = tab
[{CMakeLists.txt,*.cmake}]
indent_size = 2

View File

@ -1,40 +1,68 @@
# Build Configuration for Travis
sudo: required # For Trusty beta
os:
- linux
- osx
dist: trusty
language: cpp
compiler:
- clang
- gcc
env:
global:
- CPPFLAGS=""
- CFLAGS="-Werror --coverage"
- CXXFLAGS="-Werror -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning
- CFLAGS="-Werror -Werror=unused-function --coverage"
- CXXFLAGS="-Werror -Werror=unused-function -Wno-deprecated-register --coverage" # glib uses register and clang raises a warning
- LDFLAGS="--coverage"
install:
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then pip install --user nose; fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then pip install --user cpp-coveralls; fi # for coveralls.io code coverage tracking
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then export PATH=$HOME/.local/bin:$PATH; fi # Make sure we can find the above Python packages
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi;
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install ragel freetype glib gobject-introspection cairo icu4c graphite2; fi
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew link --force icu4c; fi # icu4c is keg-only
script:
- NOCONFIGURE=1 ./autogen.sh
- export CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
- if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" == "gcc" ]; then export CONFIGURE_OPTS="$CONFIGURE_OPTS --enable-gtk-doc"; fi
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then export CONFIGURE_OPTS="$CONFIGURE_OPTS --with-coretext"; fi
- ./configure $CONFIGURE_OPTS
- make
- make check
- if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" == "gcc" -a "$TRAVIS_SLUG" == "behdad/harfbuzz" ]; then rm -f src/.libs/NONE.gcov; touch src/NONE; coveralls -e docs; fi
after_success:
- if [ "$TRAVIS_OS_NAME" == "linux" -a "$CC" == "gcc" -a "$TRAVIS_SECURE_ENV_VARS" == "true" ]; then bash .ci/deploy-docs.sh; fi
- CONFIGURE_OPTS="--with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2"
- NOCONFIGURE=1
# COVERITY_SCAN_TOKEN
- secure: "Vw1UUHsAr4t3xuvOqqBsFAORptmNcQRrcGJnzSX7jDODBIRNfnU2LIBTagrPNKfSUhyQgCHqt1gX9iWNWvVfy3sDOXr2MXZeoqmF6Y1mS35J0rA/EPJgRHsdkxygkmFnXVeQkEuI55BINkaSoOpAeunmXKJNw1p9JVw368Fm/tU="
matrix:
include:
- os: linux
compiler: gcc
script:
# Remove these two lines when Travis updated its distro
- wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
- ./autogen.sh
- ./configure $CONFIGURE_OPTS --enable-gtk-doc
- make
- make check || .ci/fail.sh
after_success:
- bash .ci/run-coveralls.sh # for coveralls.io code coverage tracking
- bash .ci/deploy-docs.sh
- bash .ci/trigger-coverity.sh
- os: linux
compiler: clang
script:
# Remove these two lines when Travis updated its distro
- wget http://download.savannah.gnu.org/releases/freetype/freetype-2.9.tar.bz2 && tar xf freetype-2.9.tar.bz2 && cd freetype-2.9 && ./autogen.sh && ./configure && make -j4 && cd ..
- export LD_LIBRARY_PATH="$PWD/freetype-2.9/objs/.libs"
- ./autogen.sh
- ./configure $CONFIGURE_OPTS
- make
- make check || .ci/fail.sh
- os: osx
compiler: clang
install:
# https://github.com/harfbuzz/harfbuzz/issues/345
- export CXXFLAGS="$CXXFLAGS -Wno-deprecated-declarations"
- brew update;
# Workaround Travis/brew bug
- brew uninstall libtool && brew install libtool
- brew install ragel freetype glib gobject-introspection cairo icu4c graphite2
- brew link --force icu4c # icu4c is keg-only
script:
- ./autogen.sh
- ./configure $CONFIGURE_OPTS --with-coretext
- make
- make check || .ci/fail.sh
notifications:
irc: "irc.freenode.org#harfbuzz"
email: harfbuzz@lists.freedesktop.org
email: harfbuzz-bots-chatter@googlegroups.com
addons:
apt:
@ -47,4 +75,14 @@ addons:
- libcairo2-dev # for utils
- libicu-dev # for extra unicode functions
- libgraphite2-dev # for extra shapers
- # libgirepository1.0-dev # for gobject-introspection
#- libgirepository1.0-dev # for gobject-introspection
coverity_scan:
project:
name: HarfBuzz
version: 1.0
description: HarfBuzz OpenType text shaping engine
notification_email: harfbuzz-bots-chatter@googlegroups.com
build_command_prepend: ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2
build_command: make
branch_pattern: coverity_scan

View File

@ -1,107 +0,0 @@
##
## Copyright (C) 2012 The Android Open Source Project
##
## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
#############################################################
# Note:
#
# This file is used to build HarfBuzz within the Android
# platform itself. If you need to compile HarfBuzz to
# ship with your Android NDK app, you can use the autotools
# build system to do so. To do that you need to install a
# "standalone" toolchain with the NDK, eg:
#
# ndk/build/tools/make-standalone-toolchain.sh \
# --platform=android-18 \
# --install-dir=/prefix
#
# Set PLATFORM_PREFIX eng var to that prefix and make sure
# the cross-compile tools from PLATFORM_PREFIX are in path.
# Configure and install HarfBuzz:
#
# ./configure --host=arm-linux-androideabi \
# --prefix=$PLATFORM_PREFIX \
# --enable-static \
# --with-freetype \
# PKG_CONFIG_LIBDIR=$PLATFORM_PREFIX/lib/pkgconfig
# make install
#
# You can first build FreeType the same way:
#
# ./configure --host=arm-linux-androideabi \
# --prefix=$PLATFORM_PREFIX \
# --enable-static \
# --without-png \
# PKG_CONFIG_LIBDIR=$PLATFORM_PREFIX/lib/pkgconfig
# make install
#
LOCAL_PATH:= $(call my-dir)
HARFBUZZ_SRC_FILES = \
src/hb-blob.cc \
src/hb-buffer-serialize.cc \
src/hb-buffer.cc \
src/hb-common.cc \
src/hb-face.cc \
src/hb-font.cc \
src/hb-ot-tag.cc \
src/hb-set.cc \
src/hb-shape.cc \
src/hb-shape-plan.cc \
src/hb-shaper.cc \
src/hb-unicode.cc \
src/hb-warning.cc \
src/hb-ot-font.cc \
src/hb-ot-layout.cc \
src/hb-ot-map.cc \
src/hb-ot-shape.cc \
src/hb-ot-shape-complex-arabic.cc \
src/hb-ot-shape-complex-default.cc \
src/hb-ot-shape-complex-hangul.cc \
src/hb-ot-shape-complex-hebrew.cc \
src/hb-ot-shape-complex-indic.cc \
src/hb-ot-shape-complex-indic-table.cc \
src/hb-ot-shape-complex-myanmar.cc \
src/hb-ot-shape-complex-thai.cc \
src/hb-ot-shape-complex-tibetan.cc \
src/hb-ot-shape-complex-use.cc \
src/hb-ot-shape-complex-use-table.cc \
src/hb-ot-shape-normalize.cc \
src/hb-ot-shape-fallback.cc \
$(NULL)
#############################################################
# build the harfbuzz shared library
#
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
$(HARFBUZZ_SRC_FILES) \
src/hb-icu.cc
LOCAL_CPP_EXTENSION := .cc
LOCAL_SHARED_LIBRARIES := \
libcutils \
libicuuc \
libicui18n \
libutils \
liblog
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/src
LOCAL_CFLAGS += -DHB_NO_MT -DHAVE_OT -DHAVE_ICU -DHAVE_ICU_BUILTIN \
-Wno-unused-parameter -Wno-missing-field-initializers
LOCAL_MODULE:= libharfbuzz_ng
include $(BUILD_SHARED_LIBRARY)

View File

@ -1,36 +1,50 @@
On Linux, install the development packages for FreeType,
Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
* sudo apt-get install gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
sudo apt-get install gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
* sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel
on the Mac, using MacPorts:
* sudo port install freetype glib2 cairo
sudo yum install gcc gcc-c++ freetype-devel glib2-devel cairo-devel
on Windows, consider using [vcpkg](https://github.com/Microsoft/vcpkg),
provided by Microsoft, for building HarfBuzz and other open-source libraries
but if you need to build harfbuzz from source, put ragel binary on your
PATH and follow appveyor CI's cmake
[build steps](https://github.com/harfbuzz/harfbuzz/blob/master/appveyor.yml).
on macOS, using MacPorts:
sudo port install freetype glib2 cairo
or using Homebrew:
* brew install freetype glib cairo
brew install freetype glib cairo
If you are using a tarball, you can now proceed to running configure and make
as with any other standard package. That should leave you with a shared
library in src/, and a few utility programs including hb-view and hb-shape
under util/. From the tarball, NMake Makefiles are also provided in win32/,
which supports building HarfBuzz using Visual Studio, with a README.txt that
gives instructions on building using NMake.
library in `src/`, and a few utility programs including `hb-view` and `hb-shape`
under `util/`.
If you are bootstraping from git, you need a few more tools before you can
run autogen.sh for the first time. Namely, pkg-config and ragel. Again,
on Ubuntu / Debian:
* sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools
run `autogen.sh` for the first time. Namely, `pkg-config` and `ragel`.
Again, on Ubuntu / Debian:
sudo apt-get install autoconf automake libtool pkg-config ragel gtk-doc-tools
and on Fedora, RHEL, CentOS:
* sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc
sudo yum install autoconf automake libtool pkgconfig ragel gtk-doc
on the Mac, using MacPorts:
* sudo port install autoconf automake libtool pkgconfig ragel gtk-doc
sudo port install autoconf automake libtool pkgconfig ragel gtk-doc
or using Homebrew:
* brew install autoconf automake libtool pkgconfig ragel gtk-doc
brew install autoconf automake libtool pkgconfig ragel gtk-doc
To build the Python bindings, you also need:
* brew install pygobject3
brew install pygobject3

860
CMakeLists.txt Normal file
View File

@ -0,0 +1,860 @@
cmake_minimum_required(VERSION 2.8.0)
project(harfbuzz)
enable_testing()
## Limit framework build to Xcode generator
if (BUILD_FRAMEWORK)
# for a framework build on macOS, use:
# cmake -DBUILD_FRAMEWORK=ON -Bbuild -H. -GXcode && cmake --build build
if (NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode")
message(FATAL_ERROR
"You should use Xcode generator with BUILD_FRAMEWORK enabled")
endif ()
set (CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_64_BIT)")
set (CMAKE_MACOSX_RPATH ON)
set (BUILD_SHARED_LIBS ON)
endif ()
## Disallow in-source builds, as CMake generated make files can collide with autotools ones
if (NOT MSVC AND "${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
message(FATAL_ERROR
"
In-source builds are not permitted! Make a separate folder for"
" building, e.g.,"
"
mkdir build; cd build; cmake .."
"
Before that, remove the files created by this failed run with"
"
rm -rf CMakeCache.txt CMakeFiles")
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)
option(HB_HAVE_CORETEXT "Enable CoreText shaper backend on macOS" ON)
set (CMAKE_MACOSX_RPATH ON)
endif ()
if (WIN32)
option(HB_HAVE_UNISCRIBE "Enable Uniscribe shaper backend on Windows" OFF)
option(HB_HAVE_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)
if (HB_BUILD_UTILS)
set (HB_HAVE_GLIB ON)
set (HB_HAVE_FREETYPE ON)
endif ()
option(HB_HAVE_GOBJECT "Enable GObject Bindings" OFF)
if (HB_HAVE_GOBJECT)
set (HB_HAVE_GLIB ON)
endif ()
option(HB_HAVE_INTROSPECTION "Enable building introspection (.gir/.typelib) files" OFF)
if (HB_HAVE_INTROSPECTION)
set (HB_HAVE_GOBJECT ON)
set (HB_HAVE_GLIB ON)
endif ()
option(HB_DISABLE_TEST_PROGS OFF "Do not build some of the test programs, useful for continuous builds")
option(HB_CHECK OFF "Do a configuration suitable for testing (shared library and enable all options)")
if (HB_CHECK)
set (BUILD_SHARED_LIBS ON)
set (HB_BUILD_UTILS ON)
set (HB_BUILTIN_UCDN ON)
set (HB_HAVE_ICU)
set (HB_HAVE_GLIB ON)
#set (HB_HAVE_GOBJECT ON)
#set (HB_HAVE_INTROSPECTION ON)
set (HB_HAVE_FREETYPE ON)
set (HB_HAVE_GRAPHITE2 ON)
if (WIN32)
set (HB_HAVE_UNISCRIBE ON)
set (HB_HAVE_DIRECTWRITE ON)
elseif (APPLE)
set (HB_HAVE_CORETEXT ON)
endif ()
endif ()
include_directories(AFTER
${PROJECT_SOURCE_DIR}/src
${PROJECT_BINARY_DIR}/src
)
add_definitions(-DHAVE_OT)
add_definitions(-DHAVE_FALLBACK)
## Functions and headers
include (CheckFunctionExists)
include (CheckIncludeFile)
macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
foreach (func_name ${ARGN})
string(TOUPPER ${func_name} definiton_to_add)
check_function_exists(${func_name} HAVE_${definiton_to_add})
if (${HAVE_${definiton_to_add}})
add_definitions(-DHAVE_${definiton_to_add})
endif ()
endforeach ()
endmacro ()
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)
endif ()
check_include_file(sys/mman.h HAVE_SYS_MMAN_H)
if (${HAVE_SYS_MMAN_H})
add_definitions(-DHAVE_SYS_MMAN_H)
endif ()
check_include_file(xlocale.h HAVE_XLOCALE_H)
if (${HAVE_XLOCALE_H})
add_definitions(-DHAVE_XLOCALE_H)
endif ()
if (MSVC)
add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
endif ()
if (BUILD_SHARED_LIBS)
if (WIN32 AND NOT MINGW)
add_definitions("-DHB_EXTERN=__declspec(dllexport) extern")
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
endif ()
endif ()
## Detect if we are running inside a distribution or regular repository folder
set (IN_HB_DIST FALSE)
if (EXISTS "${PROJECT_SOURCE_DIR}/ChangeLog")
# perhaps we are on dist directory
set (IN_HB_DIST TRUE)
#set (HB_VERSION_H "${PROJECT_SOURCE_DIR}/src/hb-version.h")
endif ()
## Extract variables from Makefile files
function (extract_make_variable variable makefile_source)
string(REGEX MATCH "${variable} = ([^$]+)\\$" temp ${makefile_source})
string(REGEX MATCHALL "[^ \n\t\\]+" listVar ${CMAKE_MATCH_1})
set (${variable} ${listVar} PARENT_SCOPE)
endfunction ()
# http://stackoverflow.com/a/27630120
function (add_prefix_to_list var prefix)
set (listVar "")
foreach (f ${${var}})
list(APPEND listVar "${prefix}${f}")
endforeach ()
set (${var} "${listVar}" PARENT_SCOPE)
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_OT_sources ${SRCSOURCES})
add_prefix_to_list(HB_OT_sources "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_OT_headers ${SRCSOURCES})
add_prefix_to_list(HB_OT_headers "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_SUBSET_sources ${SRCSOURCES})
add_prefix_to_list(HB_SUBSET_sources "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_SUBSET_headers ${SRCSOURCES})
add_prefix_to_list(HB_SUBSET_headers "${PROJECT_SOURCE_DIR}/src/")
extract_make_variable(HB_BASE_RAGEL_GENERATED_sources ${SRCSOURCES})
extract_make_variable(HB_OT_RAGEL_GENERATED_sources ${SRCSOURCES})
#if (IN_HB_DIST)
add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/")
add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/")
#else ()
# add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/")
# add_prefix_to_list(HB_OT_RAGEL_GENERATED_sources "${PROJECT_BINARY_DIR}/src/")
#endif ()
extract_make_variable(HB_VIEW_sources ${UTILSOURCES})
add_prefix_to_list(HB_VIEW_sources "${PROJECT_SOURCE_DIR}/util/")
extract_make_variable(HB_SHAPE_sources ${UTILSOURCES})
add_prefix_to_list(HB_SHAPE_sources "${PROJECT_SOURCE_DIR}/util/")
extract_make_variable(HB_SUBSET_CLI_sources ${UTILSOURCES})
add_prefix_to_list(HB_SUBSET_CLI_sources "${PROJECT_SOURCE_DIR}/util/")
extract_make_variable(HB_OT_SHAPE_CLOSURE_sources ${UTILSOURCES})
add_prefix_to_list(HB_OT_SHAPE_CLOSURE_sources "${PROJECT_SOURCE_DIR}/util/")
extract_make_variable(LIBHB_UCDN_sources ${UCDNSOURCES})
add_prefix_to_list(LIBHB_UCDN_sources "${PROJECT_SOURCE_DIR}/src/hb-ucdn/")
file(READ configure.ac CONFIGUREAC)
string(REGEX MATCH "\\[(([0-9]+)\\.([0-9]+)\\.([0-9]+))\\]" HB_VERSION_MATCH ${CONFIGUREAC})
set (HB_VERSION ${CMAKE_MATCH_1})
set (HB_VERSION_MAJOR ${CMAKE_MATCH_2})
set (HB_VERSION_MINOR ${CMAKE_MATCH_3})
set (HB_VERSION_MICRO ${CMAKE_MATCH_4})
## Define ragel tasks
if (NOT IN_HB_DIST)
find_program(RAGEL "ragel" CMAKE_FIND_ROOT_PATH_BOTH)
if (RAGEL)
message(STATUS "ragel found at: ${RAGEL}")
else ()
message(FATAL_ERROR "ragel not found, get it here -- http://www.complang.org/ragel/ or, use harfbuzz releases https://github.com/harfbuzz/harfbuzz/releases")
endif ()
foreach (ragel_output IN ITEMS ${HB_BASE_RAGEL_GENERATED_sources} ${HB_OT_RAGEL_GENERATED_sources})
string(REGEX MATCH "([^/]+)\\.hh" temp ${ragel_output})
set (target_name ${CMAKE_MATCH_1})
add_custom_command(OUTPUT ${ragel_output}
COMMAND ${RAGEL} -G2 -o ${ragel_output} ${PROJECT_SOURCE_DIR}/src/${target_name}.rl -I ${PROJECT_SOURCE_DIR} ${ARGN}
DEPENDS ${PROJECT_SOURCE_DIR}/src/${target_name}.rl
)
add_custom_target(harfbuzz_${target_name} DEPENDS ${PROJECT_BINARY_DIR}/src/${target_name})
endforeach ()
mark_as_advanced(RAGEL)
endif ()
## Generate hb-version.h
#if (NOT IN_HB_DIST)
# set (HB_VERSION_H_IN "${PROJECT_SOURCE_DIR}/src/hb-version.h.in")
# set (HB_VERSION_H "${PROJECT_BINARY_DIR}/src/hb-version.h")
# set_source_files_properties("${HB_VERSION_H}" PROPERTIES GENERATED true)
# configure_file("${HB_VERSION_H_IN}" "${HB_VERSION_H}.tmp" @ONLY)
# execute_process(COMMAND "${CMAKE_COMMAND}" -E copy_if_different
# "${HB_VERSION_H}.tmp"
# "${HB_VERSION_H}"
# )
# file(REMOVE "${HB_VERSION_H}.tmp")
#endif ()
## Define sources and headers of the project
set (project_sources
${HB_BASE_sources}
${HB_BASE_RAGEL_GENERATED_sources}
${HB_FALLBACK_sources}
${HB_OT_sources}
${HB_OT_RAGEL_GENERATED_sources}
)
set (subset_project_sources
${HB_SUBSET_sources}
)
set (project_extra_sources)
set (project_headers
#${HB_VERSION_H}
${HB_BASE_headers}
${HB_OT_headers}
)
set (subset_project_headers
${HB_SUBSET_headers}
)
## Find and include needed header folders and libraries
if (HB_HAVE_FREETYPE)
include (FindFreetype)
if (NOT FREETYPE_FOUND)
message(FATAL_ERROR "HB_HAVE_FREETYPE was set, but we failed to find it. Maybe add a CMAKE_PREFIX_PATH= to your Freetype2 install prefix")
endif ()
list(APPEND THIRD_PARTY_LIBS ${FREETYPE_LIBRARIES})
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
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${FREETYPE_INCLUDE_DIRS})
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${FREETYPE_LIBRARIES})
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
endif ()
if (HB_HAVE_GRAPHITE2)
add_definitions(-DHAVE_GRAPHITE2)
find_path(GRAPHITE2_INCLUDE_DIR graphite2/Font.h)
find_library(GRAPHITE2_LIBRARY 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})
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)
# https://github.com/WebKit/webkit/blob/master/Source/cmake/FindGLIB.cmake
find_package(PkgConfig)
pkg_check_modules(PC_GLIB QUIET glib-2.0)
find_library(GLIB_LIBRARIES NAMES glib-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS})
find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0/include)
find_path(GLIB_INCLUDE_DIR NAMES glib.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0)
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})
mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
endif ()
if (HB_HAVE_ICU)
add_definitions(-DHAVE_ICU)
# https://github.com/WebKit/webkit/blob/master/Source/cmake/FindICU.cmake
find_package(PkgConfig)
pkg_check_modules(PC_ICU QUIET icu-uc)
find_path(ICU_INCLUDE_DIR NAMES unicode/utypes.h HINTS ${PC_ICU_INCLUDE_DIRS} ${PC_ICU_INCLUDEDIR})
find_library(ICU_LIBRARY NAMES libicuuc cygicuuc cygicuuc32 icuuc HINTS ${PC_ICU_LIBRARY_DIRS} ${PC_ICU_LIBDIR})
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})
mark_as_advanced(ICU_INCLUDE_DIR ICU_LIBRARY)
endif ()
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)
find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
if (APPLICATION_SERVICES_FRAMEWORK)
list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
endif (APPLICATION_SERVICES_FRAMEWORK)
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
endif ()
if (WIN32 AND HB_HAVE_UNISCRIBE)
add_definitions(-DHAVE_UNISCRIBE)
list(APPEND project_sources ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.cc)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-uniscribe.h)
list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
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 ()
if (HB_HAVE_GOBJECT)
include (FindPythonInterp)
include (FindPerl)
# Use the hints from glib-2.0.pc to find glib-mkenums
find_package(PkgConfig)
pkg_check_modules(PC_GLIB QUIET glib-2.0)
find_program(GLIB_MKENUMS glib-mkenums
HINTS ${PC_glib_mkenums}
)
set (GLIB_MKENUMS_CMD)
if (WIN32 AND NOT MINGW)
# In Visual Studio builds, shebang lines are not supported
# in the standard cmd.exe shell that we use, so we need to
# first determine whether glib-mkenums is a Python or PERL
# script
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}" --version
RESULT_VARIABLE GLIB_MKENUMS_PYTHON
OUTPUT_QUIET ERROR_QUIET
)
if (GLIB_MKENUMS_PYTHON EQUAL 0)
message("${GLIB_MKENUMS} is a Python script.")
set (GLIB_MKENUMS_CMD "${PYTHON_EXECUTABLE}" "${GLIB_MKENUMS}")
else ()
execute_process(COMMAND "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}" --version
RESULT_VARIABLE GLIB_MKENUMS_PERL
OUTPUT_QUIET ERROR_QUIET
)
if (GLIB_MKENUMS_PERL EQUAL 0)
message("${GLIB_MKENUMS} is a PERL script.")
set (GLIB_MKENUMS_CMD "${PERL_EXECUTABLE}" "${GLIB_MKENUMS}")
endif ()
if (NOT GLIB_MKENUMS_PERL EQUAL 0 AND NOT GLIB_MKENUMS_PYTHON EQUAL 0)
message(FATAL_ERROR "Unable to determine type of glib-mkenums script")
endif ()
endif ()
else ()
set (GLIB_MKENUMS_CMD "${GLIB_MKENUMS}")
endif ()
if (NOT GLIB_MKENUMS_CMD)
message(FATAL_ERROR "HB_HAVE_GOBJECT was set, but we failed to find glib-mkenums, which is required")
endif ()
pkg_check_modules(PC_GOBJECT QUIET gobject-2.0)
find_library(GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${PC_GLIB_LIBDIR} ${PC_GLIB_LIBRARY_DIRS})
find_path(GOBJECT_INCLUDE_DIR NAMES glib-object.h HINTS ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} PATH_SUFFIXES glib-2.0)
include_directories(${GOBJECTCONFIG_INCLUDE_DIR} ${GOBJECT_INCLUDE_DIR})
mark_as_advanced(GOBJECT_LIBRARIES GOBJECT_INCLUDE_DIR)
list(APPEND hb_gobject_sources ${PROJECT_SOURCE_DIR}/src/hb-gobject-structs.cc)
list(APPEND hb_gobject_gen_sources
${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc
)
list(APPEND hb_gobject_structs_headers
${PROJECT_SOURCE_DIR}/src/hb-gobject-structs.h
)
list(APPEND hb_gobject_headers
${PROJECT_SOURCE_DIR}/src/hb-gobject.h
${hb_gobject_structs_headers}
)
list(APPEND hb_gobject_gen_headers
${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
COMMAND ${GLIB_MKENUMS_CMD}
--template=${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.h.tmpl
--identifier-prefix hb_
--symbol-prefix hb_gobject
${hb_gobject_structs_headers}
${project_headers}
> ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h.tmp
COMMAND "${CMAKE_COMMAND}"
"-DENUM_INPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h.tmp"
"-DENUM_OUTPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h"
-P ${PROJECT_SOURCE_DIR}/replace-enum-strings.cmake
DEPENDS ${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.h.tmpl
${hb_gobject_header}
${project_headers}
)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc
COMMAND ${GLIB_MKENUMS_CMD}
--template=${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.cc.tmpl
--identifier-prefix hb_
--symbol-prefix hb_gobject
${hb_gobject_header}
${project_headers}
> ${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc.tmp
COMMAND "${CMAKE_COMMAND}"
"-DENUM_INPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc.tmp"
"-DENUM_OUTPUT_SRC=${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.cc"
-P ${PROJECT_SOURCE_DIR}/replace-enum-strings.cmake
DEPENDS ${PROJECT_SOURCE_DIR}/src/hb-gobject-enums.cc.tmpl
${CMAKE_CURRENT_BINARY_DIR}/src/hb-gobject-enums.h
${hb_gobject_header}
${project_headers}
)
endif ()
## Atomic ops availability detection
file(WRITE "${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c"
" void memory_barrier (void) { __sync_synchronize (); }
int atomic_add (int *i) { return __sync_fetch_and_add (i, 1); }
int mutex_trylock (int *m) { return __sync_lock_test_and_set (m, 1); }
void mutex_unlock (int *m) { __sync_lock_release (m); }
int main () { return 0; }
")
try_compile(HB_HAVE_INTEL_ATOMIC_PRIMITIVES
${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives
${PROJECT_BINARY_DIR}/try_compile_intel_atomic_primitives.c)
if (HB_HAVE_INTEL_ATOMIC_PRIMITIVES)
add_definitions(-DHAVE_INTEL_ATOMIC_PRIMITIVES)
endif ()
file(WRITE "${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c"
" #include <atomic.h>
/* This requires Solaris Studio 12.2 or newer: */
#include <mbarrier.h>
void memory_barrier (void) { __machine_rw_barrier (); }
int atomic_add (volatile unsigned *i) { return atomic_add_int_nv (i, 1); }
void *atomic_ptr_cmpxchg (volatile void **target, void *cmp, void *newval) { return atomic_cas_ptr (target, cmp, newval); }
int main () { return 0; }
")
try_compile(HB_HAVE_SOLARIS_ATOMIC_OPS
${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops
${PROJECT_BINARY_DIR}/try_compile_solaris_atomic_ops.c)
if (HB_HAVE_SOLARIS_ATOMIC_OPS)
add_definitions(-DHAVE_SOLARIS_ATOMIC_OPS)
endif ()
## Define harfbuzz library
add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})
target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
## Define harfbuzz-subset library
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
add_dependencies(harfbuzz-subset harfbuzz)
target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
if (UNIX OR MINGW)
# Make symbols link locally
link_libraries(-Bsymbolic-functions)
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Make sure we don't link to libstdc++
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
set (CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "m") # libm
set (CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
set_target_properties(harfbuzz PROPERTIES LINKER_LANGUAGE C)
set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C)
# No threadsafe statics as we do it ourselves
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics")
endif ()
endif ()
## Define harfbuzz-gobject library
if (HB_HAVE_GOBJECT)
add_library(harfbuzz-gobject
${hb_gobject_sources}
${hb_gobject_gen_sources}
${hb_gobject_headers}
${hb_gobject_gen_headers}
)
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/src)
add_dependencies(harfbuzz-gobject harfbuzz)
target_link_libraries(harfbuzz-gobject harfbuzz ${GOBJECT_LIBRARIES} ${THIRD_PARTY_LIBS})
endif ()
# On Windows, g-ir-scanner requires a DLL build in order for it to work
if (WIN32)
if (NOT BUILD_SHARED_LIBS)
message("Building introspection files on Windows requires BUILD_SHARED_LIBS to be enabled.")
set (HB_HAVE_INTROSPECTION OFF)
endif ()
endif ()
if (HB_HAVE_INTROSPECTION)
find_package(PkgConfig)
pkg_check_modules(PC_GI QUIET gobject-introspection-1.0)
find_program(G_IR_SCANNER g-ir-scanner
HINTS ${PC_g_ir_scanner}
)
find_program(G_IR_COMPILER g-ir-compiler
HINTS ${PC_g_ir_compiler}
)
if (WIN32 AND NOT MINGW)
# Note that since we already enable HB_HAVE_GOBJECT
# we would already have PYTHON_EXECUTABLE handy
set (G_IR_SCANNER_CMD "${PYTHON_EXECUTABLE}" "${G_IR_SCANNER}")
else ()
set (G_IR_SCANNER_CMD "${G_IR_SCANNER}")
endif ()
# We need to account for the varying output directories
# when we build using Visual Studio projects
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
else ()
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
endif ()
# Get the CFlags that we used to build HarfBuzz/HarfBuzz-GObject
set (hb_defines_cflags "")
foreach (hb_cflag ${hb_cflags})
list(APPEND hb_defines_cflags "-D${hb_cflag}")
endforeach (hb_cflag)
# Get the other dependent libraries we used to build HarfBuzz/HarfBuzz-GObject
set (extra_libs "")
foreach (extra_lib ${THIRD_PARTY_LIBS})
# We don't want the .lib extension here...
string(REPLACE ".lib" "" extra_lib_stripped "${extra_lib}")
list(APPEND extra_libs "--extra-library=${extra_lib_stripped}")
endforeach ()
set (introspected_sources)
foreach (f
${project_headers}
${project_sources}
${hb_gobject_gen_sources}
${hb_gobject_gen_headers}
${hb_gobject_sources}
${hb_gobject_headers}
)
if (WIN32)
# Nasty issue: We need to make drive letters lower case,
# otherwise g-ir-scanner won't like it and give us a bunch
# of invalid items and unresolved types...
STRING(SUBSTRING "${f}" 0 1 drive)
STRING(SUBSTRING "${f}" 1 -1 path)
if (drive MATCHES "[A-Z]")
STRING(TOLOWER ${drive} drive_lower)
list(APPEND introspected_sources "${drive_lower}${path}")
else ()
list(APPEND introspected_sources "${f}")
endif ()
else ()
list(APPEND introspected_sources "${f}")
endif ()
endforeach ()
# Finally, build the introspection files...
add_custom_command(
TARGET harfbuzz-gobject
POST_BUILD
COMMAND ${G_IR_SCANNER_CMD}
--warn-all --no-libtool --verbose
-n hb
--namespace=HarfBuzz
--nsversion=0.0
--identifier-prefix=hb_
--include GObject-2.0
--pkg-export=harfbuzz
--cflags-begin
-I${PROJECT_SOURCE_DIR}/src
-I${PROJECT_BINARY_DIR}/src
${hb_includedir_cflags}
${hb_defines_cflags}
-DHB_H
-DHB_H_IN
-DHB_OT_H
-DHB_OT_H_IN
-DHB_GOBJECT_H
-DHB_GOBJECT_H_IN
-DHB_EXTERN=
--cflags-end
--library=harfbuzz-gobject
--library=harfbuzz
-L${hb_libpath}
${extra_libs}
${introspected_sources}
-o ${hb_libpath}/HarfBuzz-0.0.gir
DEPENDS harfbuzz-gobject harfbuzz
)
add_custom_command(
TARGET harfbuzz-gobject
POST_BUILD
COMMAND "${G_IR_COMPILER}"
--verbose --debug
--includedir ${CMAKE_CURRENT_BINARY_DIR}
${hb_libpath}/HarfBuzz-0.0.gir
-o ${hb_libpath}/HarfBuzz-0.0.typelib
DEPENDS ${hb_libpath}/HarfBuzz-0.0.gir harfbuzz-gobject
)
endif ()
## Additional framework build configs
if (BUILD_FRAMEWORK)
set (CMAKE_MACOSX_RPATH ON)
set_target_properties(harfbuzz PROPERTIES
FRAMEWORK TRUE
PUBLIC_HEADER "${project_headers}"
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
)
set (MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz")
set (MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}")
set (MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}")
endif ()
## Additional harfbuzz build artifacts
if (HB_BUILD_UTILS)
# https://github.com/WebKit/webkit/blob/master/Source/cmake/FindCairo.cmake
find_package(PkgConfig)
pkg_check_modules(PC_CAIRO QUIET cairo)
find_path(CAIRO_INCLUDE_DIRS NAMES cairo.h HINTS ${PC_CAIRO_INCLUDEDIR} ${PC_CAIRO_INCLUDE_DIRS} PATH_SUFFIXES cairo)
find_library(CAIRO_LIBRARIESNAMES cairo HINTS ${PC_CAIRO_LIBDIR} ${PC_CAIRO_LIBRARY_DIRS})
add_definitions("-DPACKAGE_NAME=\"HarfBuzz\"")
add_definitions("-DPACKAGE_VERSION=\"${HB_VERSION}\"")
include_directories(${CAIRO_INCLUDE_DIRS})
add_executable(hb-view ${HB_VIEW_sources})
target_link_libraries(hb-view harfbuzz ${CAIRO_LIBRARIESNAMES})
add_executable(hb-shape ${HB_SHAPE_sources})
target_link_libraries(hb-shape harfbuzz)
add_executable(hb-subset ${HB_SUBSET_CLI_sources})
target_link_libraries(hb-subset harfbuzz harfbuzz-subset)
add_executable(hb-ot-shape-closure ${HB_OT_SHAPE_CLOSURE_sources})
target_link_libraries(hb-ot-shape-closure harfbuzz)
mark_as_advanced(CAIRO_INCLUDE_DIRS CAIRO_LIBRARIESNAMES)
endif ()
## Install
include (GNUInstallDirs)
if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
install(FILES ${project_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz)
if (HB_HAVE_GOBJECT)
install(FILES ${hb_gobject_headers} ${hb_gobject_gen_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz)
endif ()
endif ()
if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS harfbuzz
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
if (HB_BUILD_UTILS)
install(TARGETS hb-view
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(TARGETS hb-view
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(TARGETS hb-shape
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
install(TARGETS hb-ot-shape-closure
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
endif ()
if (HB_HAVE_GOBJECT)
install(TARGETS harfbuzz-gobject
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if (HB_HAVE_INTROSPECTION)
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
else ()
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
endif ()
install(FILES "${hb_libpath}/HarfBuzz-0.0.gir"
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gir-1.0
)
install(FILES "${hb_libpath}/HarfBuzz-0.0.typelib"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/girepository-1.0
)
endif ()
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 ()
## src/ executables
if (NOT HB_DISABLE_TEST_PROGS)
foreach (prog main test test-would-substitute test-size-params test-buffer-serialize hb-ot-tag test-unicode-ranges)
set (prog_name ${prog})
if (${prog_name} STREQUAL "test")
# test can not be used as a valid executable name on cmake, lets special case it
set (prog_name test-test)
endif ()
add_executable(${prog_name} ${PROJECT_SOURCE_DIR}/src/${prog}.cc)
target_link_libraries(${prog_name} harfbuzz ${THIRD_PARTY_LIBS})
endforeach ()
set_target_properties(hb-ot-tag PROPERTIES COMPILE_FLAGS "-DMAIN")
endif ()
## Tests
if (UNIX OR MINGW)
if (BUILD_SHARED_LIBS)
# generate harfbuzz.def after build completion
string(REPLACE ";" " " space_separated_headers "${project_headers}")
add_custom_command(TARGET harfbuzz POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env "headers=${space_separated_headers}" python ${PROJECT_SOURCE_DIR}/src/gen-def.py ${PROJECT_BINARY_DIR}/harfbuzz.def
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src)
add_test(NAME check-static-inits.sh
COMMAND ${PROJECT_SOURCE_DIR}/src/check-static-inits.sh
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/harfbuzz.dir/src # ugly hack
)
add_test(NAME check-libstdc++.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-libstdc++.sh)
add_test(NAME check-symbols.sh COMMAND ${PROJECT_SOURCE_DIR}/src/check-symbols.sh)
set_tests_properties(
check-static-inits.sh check-libstdc++.sh check-symbols.sh
PROPERTIES
ENVIRONMENT "libs=.;srcdir=${PROJECT_SOURCE_DIR}/src"
SKIP_RETURN_CODE 77)
endif ()
add_test(NAME check-c-linkage-decls.sh COMMAND ./check-c-linkage-decls.sh)
add_test(NAME check-header-guards.sh COMMAND ./check-header-guards.sh)
add_test(NAME check-externs.sh COMMAND ./check-externs.sh)
add_test(NAME check-includes.sh COMMAND ./check-includes.sh)
set_tests_properties(
check-c-linkage-decls.sh check-header-guards.sh check-externs.sh check-includes.sh
PROPERTIES
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
SKIP_RETURN_CODE 77)
endif ()
# Needs to come last so that variables defined above are passed to
# subdirectories.
add_subdirectory(test)

View File

@ -4,14 +4,16 @@ NULL =
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src util test docs win32
SUBDIRS = src util test docs
EXTRA_DIST = \
autogen.sh \
harfbuzz.doap \
Android.mk \
README.python \
BUILD.md \
RELEASING.md \
CMakeLists.txt \
replace-enum-strings.cmake \
$(NULL)
MAINTAINERCLEANFILES = \

393
NEWS
View File

@ -1,7 +1,376 @@
Overview of changes leading to 1.2.8
Not yet released
=======
Overview of changes leading to 1.7.5
Tuesday, January 30, 2018
====================================
- Implemented 'CPAL' table in hb-ot-color.
- Separate Khmer shaper from Indic.
- First stab at AAT morx. Not hooked up.
- Misc bug fixes.
Overview of changes leading to 1.7.4
Wednesday, December 20, 2017
====================================
- Fix collect_glyphs() regression caused by hb_set_t changes.
Overview of changes leading to 1.7.3
Monday, December 18, 2017
====================================
- hb_set_t performance tuning and optimizations.
- Speed up collect_glyphs() and reject garbage data.
- In hb_coretext_font_create() set font point-size (ptem).
- Misc fixes.
Overview of changes leading to 1.7.2
Monday, December 4, 2017
====================================
- Optimize hb_set_add_range().
- Misc fixes.
- New API:
hb_coretext_font_create()
Overview of changes leading to 1.7.1
Tuesday, November 14, 2017
====================================
- Fix atexit object destruction regression.
- Fix minor integer-overflow.
Overview of changes leading to 1.7.0
Monday, November 13, 2017
====================================
- Minor Indic fixes.
- Implement kerning and glyph names in hb-ot-font.
- Various DSO optimization re .data and .bss sizes.
- Make C++11 optional; build fixes.
- Mark all other backends "unsafe-to-break".
- Graphite fix.
Overview of changes leading to 1.6.3
Thursday, October 26th, 2017
====================================
- Fix hb_set_t some more. Should be solid now.
- Implement get_glyph_name() for hb-ot-font.
- Misc fixes.
Overview of changes leading to 1.6.2
Monday, October 23nd, 2017
====================================
- Yesterday's release had a bad crasher; don't use it. That's what
happens when one works on Sunday...
https://github.com/harfbuzz/harfbuzz/issues/578
- Build fixes for FreeBSD and Chrome Android.
Overview of changes leading to 1.6.1
Sunday, October 22nd, 2017
====================================
- Don't skip over COMBINING GRAPHEME JOINER when ligating, etc.
To be refined: https://github.com/harfbuzz/harfbuzz/issues/554
- Faster hb_set_t implementation.
- Don't use deprecated ICU API.
- Fix undefined-behavior in Myanmar shaper, introduced in 1.6.0
- Deprecated API:
hb_set_invert()
Overview of changes leading to 1.6.0
Friday, October the 13th, 2017
====================================
- Update to Unicode 10.
- Various Indic and Universal Shaping Engine fixes as a result of
HarfBuzz Hackfest with Jonathan Kew at Web Engines Hackfest at
the Igalia offices in A Coruña, Spain. Thanks Igalia for having
us!
- Implement Unicode Arabic Mark Ordering Algorithm UTR#53.
- Implement optical sizing / tracking in CoreText backend, using
new API hb_font_set_ptem().
- Allow notifying hb_font_t that underlying FT_Face changed sizing,
using new API hb_ft_font_changed().
- More Graphite backend RTL fixes.
- Fix caching of variable font shaping plans.
- hb-view / hb-shape now accept following new arguments:
o --unicodes: takes a list of hex numbers that represent Unicode
codepoints.
New API:
+hb_face_get_table_tags()
+hb_font_set_ptem()
+hb_font_get_ptem()
+hb_ft_font_changed()
Overview of changes leading to 1.5.1
Tuesday, September 5, 2017
====================================
- Fix "unsafe-to-break" in fallback shaping and other corner cases.
All our tests pass with --verify now, meaning unsafe-to-break API
works as expected.
- Add --unicodes to hb-view / hb-shape.
- [indic] Treat Consonant_With_Stacker as consonant. This will need
further tweaking.
- hb_buffer_diff() tweaks.
Overview of changes leading to 1.5.0
Wednesday, August 23, 2017
====================================
- Misc new API, for appending a buffer to another, and for comparing
contents of two buffers for types of differences.
- New "unsafe-to-break" API. Can be used to speed up reshaping
in line-breaking situations. Essentially, after shaping, it returns
positions in the input string (some of the cluster boundaries) that
are "safe to break" in that if the text is segmented at that position
and two sides reshaped and concatenated, the shaping result is
exactly the same as shaping the text in one piece.
hb-view and hb-shape and hb-shape now take --verify, which verifies
the above property.
Some corner cases of the implementation are still not quite working.
Those will be fixed in subsequent releases.
- New API:
hb_buffer_append()
hb_glyph_flags_t
HB_GLYPH_FLAG_UNSAFE_TO_BREAK
HB_GLYPH_FLAG_DEFINED
hb_glyph_info_get_glyph_flags()
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
hb_buffer_diff_flags_t
HB_BUFFER_DIFF_FLAG_EQUAL
HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH
HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH
HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT
HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH
HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH
HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH
HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH
hb_buffer_diff
Overview of changes leading to 1.4.8
Tuesday, August 8, 2017
====================================
- Major fix to avar table handling.
- Rename hb-shape --show-message to --trace.
- Build fixes.
Overview of changes leading to 1.4.7
Tuesday, July 18, 2017
====================================
- Multiple Indic, Tibetan, and Cham fixes.
- CoreText: Allow disabling kerning.
- Adjust Arabic feature order again.
- Misc build fixes.
Overview of changes leading to 1.4.6
Sunday, April 23, 2017
====================================
- Graphite2: Fix RTL positioning issue.
- Backlist GDEF of more versions of Padauk and Tahoma.
- New, experimental, cmake alternative build system.
Overview of changes leading to 1.4.5
Friday, March 10, 2017
====================================
- Revert "Fix Context lookup application when moving back after a glyph..."
This introduced memory access problems. To be fixed properly soon.
Overview of changes leading to 1.4.4
Sunday, March 5, 2017
====================================
- Fix Context lookup application when moving back after a glyph deletion.
- Fix buffer-overrun in Bengali.
Overview of changes leading to 1.4.3
Saturday, February 25, 2017
====================================
- Route Adlam script to Arabic shaper.
- Misc fixes.
- New API:
hb_font_set_face()
- Deprecate API:
hb_graphite2_font_get_gr_font()
Overview of changes leading to 1.4.2
Monday, January 23, 2017
====================================
- Implement OpenType Font Variation tables avar/fvar/HVAR/VVAR.
- hb-shape and hb-view now accept --variations.
- New API:
hb_variation_t
hb_variation_from_string()
hb_variation_to_string()
hb_font_set_variations()
hb_font_set_var_coords_design()
hb_font_get_var_coords_normalized()
hb-ot-var.h:
hb_ot_var_axis_t
hb_ot_var_has_data()
hb_ot_var_get_axis_count()
hb_ot_var_get_axes()
hb_ot_var_find_axis()
hb_ot_var_normalize_variations()
hb_ot_var_normalize_coords()
- MVAR to be implemented later. Access to named instances to be
implemented later as well.
- Misc fixes.
Overview of changes leading to 1.4.1
Thursday, January 5, 2017
====================================
- Always build and use UCDN for Unicode data by default.
Reduces dependence on version of Unicode data in glib,
specially in the Windows bundles we are shipping, which
have very old glib.
Overview of changes leading to 1.4.0
Thursday, January 5, 2017
====================================
- Merged "OpenType GX" branch which adds core of support for
OpenType 1.8 Font Variations. To that extent, the relevant
new API is:
New API:
hb_font_set_var_coords_normalized()
with supporting API:
New API:
HB_OT_LAYOUT_NO_VARIATIONS_INDEX
hb_ot_layout_table_find_feature_variations()
hb_ot_layout_feature_with_variations_get_lookups()
hb_shape_plan_create2()
hb_shape_plan_create_cached2()
Currently variations in GSUB/GPOS/GDEF are fully supported,
and no other tables are supported. In particular, fvar/avar
are NOT supported, hence the hb_font_set_var_coords_normalized()
taking normalized coordinates. API to take design coordinates
will be added in the future.
HVAR/VVAR/MVAR support will also be added to hb-ot-font in the
future.
- Fix regression in GDEF glyph class processing.
- Add decompositions for Chakma, Limbu, and Balinese in USE shaper.
- Misc fixes.
Overview of changes leading to 1.3.4
Monday, December 5, 2016
====================================
- Fix vertical glyph origin in hb-ot-font.
- Implement CBDT/CBLC color font glyph extents in hb-ot-font.
Overview of changes leading to 1.3.3
Wednesday, September 28, 2016
====================================
- Implement parsing of OpenType MATH table.
New API:
HB_OT_TAG_MATH
HB_OT_MATH_SCRIPT
hb_ot_math_constant_t
hb_ot_math_kern_t
hb_ot_math_glyph_variant_t
hb_ot_math_glyph_part_flags_t
hb_ot_math_glyph_part_t
hb_ot_math_has_data
hb_ot_math_get_constant
hb_ot_math_get_glyph_italics_correction
hb_ot_math_get_glyph_top_accent_attachment
hb_ot_math_get_glyph_kerning
hb_ot_math_is_glyph_extended_shape
hb_ot_math_get_glyph_variants
hb_ot_math_get_min_connector_overlap
hb_ot_math_get_glyph_assembly
Overview of changes leading to 1.3.2
Wednesday, September 27, 2016
====================================
- Fix build of hb-coretext on older OS X versions.
Overview of changes leading to 1.3.1
Wednesday, September 7, 2016
====================================
- Blacklist bad GDEF of more fonts (Padauk).
- More CoreText backend crash fixes with OS X 10.9.5.
- Misc fixes.
Overview of changes leading to 1.3.0
Thursday, July 21, 2016
====================================
- Update to Unicode 9.0.0
- Move Javanese from Indic shaper to Universal Shaping Engine.
- Allow MultipleSubst to delete a glyph (matching Windows engine).
- Update Universal Shaping Engine to latest draft from Microsoft.
- DirectWrite backend improvements. Note: this backend is for testing ONLY.
- CoreText backend improvements with unreachable fonts.
- Implement symbol fonts (cmap 3.0.0) in hb-ft and hb-ot-font.
- Blacklist bad GDEF of more fonts (Tahoma & others).
- Misc fixes.
Overview of changes leading to 1.2.7
Monday, May 2, 2016
@ -109,7 +478,7 @@ Tuesday, February 23, 2016
- CoreText: Drastically speed up font initialization.
- CoreText: Fix tiny leak.
- Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
https://github.com/behdad/harfbuzz/issues/217
https://github.com/harfbuzz/harfbuzz/issues/217
- Add test/shaping/README.md about how to add tests to the suite.
@ -125,8 +494,8 @@ Friday, February 19, 2016
- Allow GPOS cursive connection on marks, and fix the interaction with
mark attachment. This work resulted in some changes to how mark
attachments work. See:
https://github.com/behdad/harfbuzz/issues/211
https://github.com/behdad/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
https://github.com/harfbuzz/harfbuzz/issues/211
https://github.com/harfbuzz/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
- Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
- Add nmake-based build system for Windows.
- Minor speedup.
@ -167,7 +536,7 @@ Wednesday, November 26, 2015
====================================
- Fix badly-broken fallback shaper that affected terminology.
https://github.com/behdad/harfbuzz/issues/187
https://github.com/harfbuzz/harfbuzz/issues/187
- Fix y_scaling in Graphite shaper.
- API changes:
* An unset glyph_h_origin() function in font-funcs now (sensibly)
@ -189,11 +558,11 @@ Wednesday, November 18, 2015
====================================
- Implement 'stch' stretch feature for Syriac Abbreviation Mark.
https://github.com/behdad/harfbuzz/issues/141
https://github.com/harfbuzz/harfbuzz/issues/141
- Disable use of decompose_compatibility() callback.
- Implement "shaping" of various Unicode space characters, even
if the font does not support them.
https://github.com/behdad/harfbuzz/issues/153
https://github.com/harfbuzz/harfbuzz/issues/153
- If font does not support U+2011 NO-BREAK HYPHEN, fallback to
U+2010 HYPHEN.
- Changes resulting from libFuzzer continuous fuzzing:
@ -216,7 +585,7 @@ Thursday, October 15, 2015
- Revert default load-flags of fonts created using hb_ft_font_create()
back to FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING. This was changed in
last release (1.0.5), but caused major issues, so revert.
https://github.com/behdad/harfbuzz/issues/143
https://github.com/harfbuzz/harfbuzz/issues/143
Overview of changes leading to 1.0.5
@ -224,7 +593,7 @@ Tuesday, October 13, 2015
====================================
- Fix multiple memory access bugs discovered using libFuzzer.
https://github.com/behdad/harfbuzz/issues/139
https://github.com/harfbuzz/harfbuzz/issues/139
Everyone should upgrade to this version as soon as possible.
We now have continuous fuzzing set up, to avoid issues like
these creeping in again.
@ -495,7 +864,7 @@ Wednesday, July 16, 2014
U+FFFD REPLACEMENT CHARACTER now.
- With all changes in this release, the buffer will contain fully
valid Unicode after hb_buffer_add_utf8/16/32 no matter how
broken the input is. This can be overriden though. See below.
broken the input is. This can be overridden though. See below.
- Fix Mongolian Variation Selectors for fonts without GDEF.
- Fix minor invalid buffer access.
- Accept zh-Hant and zh-Hans language tags. hb_ot_tag_to_language()

9
README
View File

@ -1,5 +1,8 @@
[![Build Status](https://travis-ci.org/behdad/harfbuzz.svg)](https://travis-ci.org/behdad/harfbuzz)
[![Coverage Status](https://img.shields.io/coveralls/behdad/harfbuzz.svg)](https://coveralls.io/r/behdad/harfbuzz)
[![Build Status](https://travis-ci.org/harfbuzz/harfbuzz.svg)](https://travis-ci.org/harfbuzz/harfbuzz)
[![Build status](https://ci.appveyor.com/api/projects/status/0t0flrxpstj9lb9w?svg=true)](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
[![CircleCI](https://circleci.com/gh/harfbuzz/harfbuzz.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz)
[![Coverity](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
[![Coverage Status](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
This is HarfBuzz, a text shaping library.
@ -9,3 +12,5 @@ For bug reports, mailing list, and other information please visit:
http://harfbuzz.org/
For license information, see the file COPYING.
Documentation: https://harfbuzz.github.io

99
RELEASING.md Normal file
View File

@ -0,0 +1,99 @@
HarfBuzz release walk-through checklist:
1. Open gitk and review changes since last release.
* `git diff $(git describe | sed 's/-.*//').. src/*.h` prints all public API
changes.
Document them in NEWS. All API and API semantic changes should be clearly
marked as API additions, API changes, or API deletions. Document
deprecations.
If there's a backward-incompatible API change (including deletions for API
used anywhere), that's a release blocker. Do NOT release.
2. Based on severity of changes, decide whether it's a minor or micro release
number bump,
3. Make sure you have correct date and new version at the top of NEWS file,
4. Bump version in configure.ac line 3,
5. Do "make distcheck", if it passes, you get a tarball.
Otherwise, fix things and commit them separately before making release,
6. "make release-files". Enter your GPG password. This creates a sha256 hash
and signs it.
7. Now that you have release files built, commit NEWS and configure.ac changes.
The commit message is simply the release number. Eg. "1.4.7"
8. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your
GPG password again.
9. Build win32 bundle.
a. Put contents of [this](https://drive.google.com/open?id=0B3_fQkxDZZXXbWltRGd5bjVrUDQ) on your `~/.local/i686-w64-mingw32`,
b. Run `../mingw32.sh --with-uniscribe` script (available below) to configure harfbuzz with mingw in a subdirector (eg. winbuild/),
c. make
d. Back in the parent directory, run `./UPDATE.sh` (available below) to build win32 bundle.
10. Copy all artefacts to users.freedesktop.org and move them into
`/srv/www.freedesktop.org/www/software/harfbuzz/release` There should be four
files. Eg.:
```
-rw-r--r-- 1 behdad eng 1592693 Jul 18 11:25 harfbuzz-1.4.7.tar.bz2
-rw-r--r-- 1 behdad eng 89 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256
-rw-r--r-- 1 behdad eng 339 Jul 18 11:34 harfbuzz-1.4.7.tar.bz2.sha256.asc
-rw-r--r-- 1 behdad eng 2895619 Jul 18 11:34 harfbuzz-1.4.7-win32.zip
```
11. While doing that, quickly double-check the size of the .tar.bz2 and .zip
files against their previous releases to make sure nothing bad happened.
They should be in the ballpark, perhaps slightly larger. Sometimes they
do shrink, that's not by itself a stopper.
12. Push the commit and tag out: "git push --follow-tags". Make sure it's
pushed both to freedesktop repo and github.
13. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
edit the tag, upload artefacts and NEWS entry and save.
## 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
```

29
TODO
View File

@ -1,24 +1,14 @@
General fixes:
=============
- AAT 'morx' implementation.
- Return "safe-to-break" bit from shaping.
- Implement 'rand' feature.
- mask propagation? (when ligation, "or" the masks).
API issues:
===========
- API to accept a list of languages?
- Add init_func to font_funcs. Adjust ft.
- 'const' for getter APIs? (use mutable internally)
- Remove hb_ot_shape_glyphs_closure()?
@ -39,7 +29,7 @@ API additions
- Add query / enumeration API for aalt-like features?
- SFNT api? get_num_faces? get_table_tags? (there's something in stash)
- SFNT api? get_num_faces?
- Add segmentation API
@ -50,20 +40,3 @@ hb-view / hb-shape enhancements:
===============================
- Add --width, --height, --auto-size, --ink-box, --align, etc?
Tests to write:
==============
- ot-layout enumeration API (needs font)
- Finish test-shape.c, grep for TODO
- Finish test-unicode.c, grep for TODO
- GObject, FreeType, etc
- hb_cache_t and relatives
- hb_feature_to/from_string
- hb_buffer_[sg]et_contents

61
appveyor.yml Normal file
View File

@ -0,0 +1,61 @@
platform: x64
environment:
matrix:
- compiler: msvc
generator: Visual Studio 14
platform: Win32
configuration: Debug
triplet: x86-windows
- compiler: msvc
generator: Visual Studio 14 Win64
platform: x64
configuration: Debug
triplet: x64-windows
- compiler: msvc
generator: Visual Studio 14 ARM
platform: ARM
configuration: Debug
- compiler: msys2
MINGW_PREFIX: /c/msys2/mingw64/
MINGW_CHOST: x86_64-w64-mingw32
MSYS2_ARCH: x86_64
- compiler: msys2
MINGW_PREFIX: /c/msys2/mingw32/
MINGW_CHOST: i686-w64-mingw32
MSYS2_ARCH: i686
install:
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-ragel"
build_script:
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" vcpkg install glib:%triplet% freetype:%triplet% cairo:%triplet%'
- 'if "%compiler%"=="msvc" md build'
- 'if "%compiler%"=="msvc" cd build'
- 'if "%compiler%"=="msvc" set PATH=%PATH%;C:\Program Files (x86)\MSBuild\14.0\Bin;c:\msys64\mingw64\bin' # msys2 is added just for having "ragel" on PATH
- 'if "%compiler%"=="msvc" if "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -G "%generator%" ../'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" cmake -DHB_HAVE_UNISCRIBE=ON -DHB_HAVE_DIRECTWRITE=ON -DHB_HAVE_GLIB=ON -DHB_HAVE_FREETYPE=ON -DHB_BUILD_UTILS=ON -G "%generator%" -DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake ../'
- 'if "%compiler%"=="msvc" msbuild harfbuzz.sln /p:Configuration=%configuration% /p:Platform=%platform%'
- 'if "%compiler%"=="msvc" if not "%platform%"=="ARM" ctest --output-on-failure -C %configuration%'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-$MSYS2_ARCH-{freetype,cairo,icu,gettext,gobject-introspection,gcc,gcc-libs,glib2,graphite2,pkg-config,python2}"'
- 'if "%compiler%"=="msys2" C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; ./autogen.sh --with-uniscribe --with-freetype --with-glib --with-gobject --with-cairo --with-icu --with-graphite2 --build=%MINGW_CHOST% --host=%MINGW_CHOST% --prefix=%MINGW_PREFIX%; make; make check || .ci/fail.sh"'
cache:
- c:\tools\vcpkg\installed\
notifications:
- provider: Email
to:
- harfbuzz-bots-chatter@googlegroups.com
on_build_success: false
on_build_failure: true
on_build_status_changed: true
# disable automatic tests
test: off

View File

@ -7,11 +7,11 @@ test -n "$srcdir" || srcdir=.
olddir=`pwd`
cd $srcdir
echo -n "checking for ragel... "
which ragel || {
echo "You need to install ragel... See http://www.complang.org/ragel/"
exit 1
}
#echo -n "checking for ragel... "
#which ragel || {
# echo "You need to install ragel... See http://www.complang.org/ragel/"
# exit 1
#}
echo -n "checking for pkg-config... "
which pkg-config || {
@ -42,5 +42,7 @@ echo "running autoreconf --force --install --verbose"
autoreconf --force --install --verbose || exit $?
cd $olddir
echo "running configure $@"
test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
test -n "$NOCONFIGURE" || {
echo "running configure $@"
"$srcdir/configure" "$@"
}

View File

@ -1,7 +1,7 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[1.2.7],
[https://github.com/behdad/harfbuzz/issues/new],
[1.7.5],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@ -9,8 +9,7 @@ AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.11.1 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
AM_CONDITIONAL(AUTOMAKE_OLDER_THAN_1_13, test $am__api_version = 1.11 -o $am__api_version = 1.12)
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-bzip2 no-dist-gzip -Wall no-define color-tests -Wno-portability])
AM_SILENT_RULES([yes])
# Initialize libtool
@ -19,9 +18,13 @@ LT_PREREQ([2.2])
LT_INIT([disable-static])
# Check for programs
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CC_C99
AM_PROG_CC_C_O
AC_PROG_CXX
dnl AX_CXX_COMPILE_STDCXX(11, noext, optional)
AC_SYS_LARGEFILE
PKG_PROG_PKG_CONFIG([0.20])
AM_MISSING_PROG([RAGEL], [ragel])
AM_MISSING_PROG([GIT], [git])
@ -55,6 +58,13 @@ m4_define([hb_libtool_current],
HB_LIBTOOL_VERSION_INFO=hb_libtool_current:hb_libtool_revision:hb_libtool_age
AC_SUBST(HB_LIBTOOL_VERSION_INFO)
AC_ARG_WITH([libstdc++],
[AS_HELP_STRING([--with-libstdc++=@<:@yes/no@:>@],
[Allow linking with libstdc++ @<:@default=no@:>@])],
[with_libstdcxx=$withval],
[with_libstdcxx=no])
AM_CONDITIONAL(WITH_LIBSTDCXX, [test "x$with_libstdcxx" = "xyes"])
# Documentation
have_gtk_doc=false
m4_ifdef([GTK_DOC_CHECK], [
@ -66,9 +76,9 @@ GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
AM_CONDITIONAL([ENABLE_GTK_DOC], false)
])
# Functions and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty)
AC_CHECK_HEADERS(unistd.h sys/mman.h)
# Functions, and headers
AC_CHECK_FUNCS(atexit mprotect sysconf getpagesize mmap isatty newlocale strtod_l setlinebuf)
AC_CHECK_HEADERS(unistd.h sys/mman.h xlocale.h)
# Compiler flags
AC_CANONICAL_HOST
@ -78,9 +88,6 @@ if test "x$GCC" = "xyes"; then
# Make symbols link locally
LDFLAGS="$LDFLAGS -Bsymbolic-functions"
# Make sure we don't link to libstdc++
CXXFLAGS="$CXXFLAGS -fno-rtti -fno-exceptions"
# Assorted warnings
CXXFLAGS="$CXXFLAGS -Wcast-align"
@ -145,7 +152,7 @@ AC_ARG_WITH(glib,
[Use glib @<:@default=auto@:>@])],,
[with_glib=auto])
have_glib=false
GLIB_DEPS="glib-2.0 >= 2.16"
GLIB_DEPS="glib-2.0 >= 2.19.1"
AC_SUBST(GLIB_DEPS)
if test "x$with_glib" = "xyes" -o "x$with_glib" = "xauto"; then
PKG_CHECK_MODULES(GLIB, $GLIB_DEPS, have_glib=true, :)
@ -162,7 +169,7 @@ dnl ===========================================================================
AC_ARG_WITH(gobject,
[AS_HELP_STRING([--with-gobject=@<:@yes/no/auto@:>@],
[Use gobject @<:@default=auto@:>@])],,
[Use gobject @<:@default=no@:>@])],,
[with_gobject=no])
have_gobject=false
if test "x$with_gobject" = "xyes" -o "x$with_gobject" = "xauto"; then
@ -177,6 +184,7 @@ if $have_gobject; then
AC_SUBST(GLIB_MKENUMS)
fi
AM_CONDITIONAL(HAVE_GOBJECT, $have_gobject)
AC_SUBST(have_gobject)
dnl ===========================================================================
@ -287,9 +295,13 @@ AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin")
dnl ===========================================================================
have_ucdn=true
if $have_glib || $have_icu && test "x$with_icu" = "xbuiltin"; then
have_ucdn=false
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])
@ -307,6 +319,16 @@ GRAPHITE2_DEPS="graphite2"
AC_SUBST(GRAPHITE2_DEPS)
if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then
PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :)
if test "x$have_graphite2" != "xtrue"; then
# If pkg-config is not available, graphite2 can still be there
ac_save_CFLAGS="$CFLAGS"
ac_save_CPPFLAGS="$CPPFLAGS"
CFLAGS="$CFLAGS $GRAPHITE2_CFLAGS"
CPPFLAGS="$CPPFLAGS $GRAPHITE2_CFLAGS"
AC_CHECK_HEADER(graphite2/Segment.h, have_graphite2=true, :)
CPPFLAGS="$ac_save_CPPFLAGS"
CFLAGS="$ac_save_CFLAGS"
fi
fi
if test "x$with_graphite2" = "xyes" -a "x$have_graphite2" != "xtrue"; then
AC_MSG_ERROR([graphite2 support requested but libgraphite2 not found])
@ -334,6 +356,10 @@ if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then
fi
if $have_freetype; then
AC_DEFINE(HAVE_FREETYPE, 1, [Have FreeType 2 library])
save_libs=$LIBS
LIBS="$LIBS $FREETYPE_LIBS"
AC_CHECK_FUNCS(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
LIBS=$save_libs
fi
AM_CONDITIONAL(HAVE_FREETYPE, $have_freetype)
@ -401,12 +427,13 @@ if test "x$with_coretext" = "xyes" -o "x$with_coretext" = "xauto"; then
else
# On iOS CoreText and CoreGraphics are stand-alone frameworks
if test "x$have_coretext" != "xtrue"; then
AC_CHECK_TYPE(CTFontRef, have_coretext=true,, [#include <CoreText/CoreText.h>])
# Check for a different symbol to avoid getting cached result.
AC_CHECK_TYPE(CTRunRef, have_coretext=true,, [#include <CoreText/CoreText.h>])
fi
if $have_coretext; then
CORETEXT_CFLAGS=
CORETEXT_LIBS="-framework CoreText -framework CoreGraphics"
CORETEXT_LIBS="-framework CoreText -framework CoreGraphics -framework CoreFoundation"
AC_SUBST(CORETEXT_CFLAGS)
AC_SUBST(CORETEXT_LIBS)
fi
@ -465,16 +492,20 @@ AC_CONFIG_FILES([
Makefile
src/Makefile
src/hb-version.h
src/harfbuzz-config.cmake
src/hb-ucdn/Makefile
util/Makefile
test/Makefile
test/api/Makefile
test/fuzzing/Makefile
test/shaping/Makefile
test/shaping/data/Makefile
test/shaping/data/in-house/Makefile
test/shaping/data/text-rendering-tests/Makefile
test/subset/Makefile
test/subset/data/Makefile
docs/Makefile
docs/version.xml
win32/Makefile
win32/config.h.win32
])
AC_OUTPUT
@ -484,18 +515,18 @@ AC_MSG_NOTICE([
Build configuration:
Unicode callbacks (you want at least one):
Builtin (UCDN): ${have_ucdn}
Glib: ${have_glib}
ICU: ${have_icu}
UCDN: ${have_ucdn}
Font callbacks (the more the better):
Font callbacks (the more the merrier):
FreeType: ${have_freetype}
Tools used for command-line utilities:
Cairo: ${have_cairo}
Fontconfig: ${have_fontconfig}
Additional shapers (the more the better):
Additional shapers (the more the merrier):
Graphite2: ${have_graphite2}
Platform shapers (not normally needed):
@ -504,7 +535,7 @@ Platform shapers (not normally needed):
DirectWrite: ${have_directwrite}
Other features:
Documentation: ${have_gtk_doc}
Documentation: ${enable_gtk_doc}
GObject bindings: ${have_gobject}
Introspection: ${have_introspection}
])

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

277
docs/HarfBuzz.svg Normal file
View File

@ -0,0 +1,277 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="682.66669"
height="682.66669"
viewBox="0 0 682.66669 682.66669"
sodipodi:docname="harfbuzz2.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
inkscape:export-filename="harfbuzz2.png"
inkscape:export-xdpi="72"
inkscape:export-ydpi="72">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6">
<g
id="g50">
<symbol
id="glyph0-0"
overflow="visible"
style="overflow:visible">
<path
id="path26"
d="M 32,0 V -192 H 224 V 0 Z M 48,-16 H 208 V -176 H 48 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-1"
overflow="visible"
style="overflow:visible">
<path
id="path29"
d="m 52.5,-64.875 c -0.08594,2.25 -0.9375,6.335938 -2.5625,12.25 -1.625,5.917969 -3.75,12.375 -6.375,19.375 -2.625,7 -4.9375,12.292969 -6.9375,15.875 -2,3.585938 -4.1875,6.3125 -6.5625,8.1875 -2.375,1.875 -6.210938,3.585938 -11.5,5.125 -5.292969,1.542969 -9.542969,2.585938 -12.75,3.125 -3.210938,0.542969 -5.230469,0.8125 -6.0625,0.8125 -0.832031,-0.082031 -1.332031,-0.414062 -1.5,-1 -0.164062,-0.582031 0.085938,-1.332031 0.75,-2.25 0.9179688,-1.414062 3.226562,-3.269531 6.9375,-5.5625 3.707031,-2.289062 8.019531,-5.164062 12.9375,-8.625 4.914062,-3.457031 8.414062,-6.476562 10.5,-9.0625 2.082031,-2.582031 4.4375,-6.457031 7.0625,-11.625 2.625,-5.164062 5,-10.375 7.125,-15.625 2.125,-5.25 3.644531,-8.832031 4.5625,-10.75 0.914062,-1.914062 1.914062,-2.832031 3,-2.75 0.914062,0.167969 1.375,1 1.375,2.5 z M 41.75,-117.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-2"
overflow="visible"
style="overflow:visible">
<path
id="path32"
d="m 19.75,-47.125 c -0.167969,3.167969 -0.5,6.023438 -1,8.5625 -0.5,2.542969 -1.167969,4.710938 -2,6.5 -0.835938,1.792969 -1.898438,3.125 -3.1875,4 -1.292969,0.875 -2.855469,1.1875 -4.6875,0.9375 0.082031,-6.5 0.769531,-15.5625 2.0625,-27.1875 1.289062,-11.625 3.226562,-24.476562 5.8125,-38.5625 1.332031,-4.082031 4.039062,-11.28906 8.125,-21.625 0.414062,-1 0.851562,-1.41406 1.3125,-1.25 0.457031,0.16797 0.6875,0.58594 0.6875,1.25 -0.25,5.08594 -1.292969,14.792969 -3.125,29.125 -1.835938,14.335938 -2.960938,24.167969 -3.375,29.5 -0.417969,5.335938 -0.625,8.25 -0.625,8.75 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-3"
overflow="visible"
style="overflow:visible">
<path
id="path35"
d="m -10.875,-27.25 c 1.667969,-7.164062 3.5625,-12.457031 5.6875,-15.875 2.125,-3.414062 3.855469,-5.289062 5.1875,-5.625 v 5.5 c 0,7 1.875,11.875 5.625,14.625 2.25,1.5 4.5,2 6.75,1.5 2.25,-0.5 3.976562,-1.664062 5.1875,-3.5 1.207031,-1.832031 2.226562,-3.976562 3.0625,-6.4375 0.832031,-2.457031 1.625,-3.6875 2.375,-3.6875 0.914062,0 1.289062,0.875 1.125,2.625 -0.08594,3 -1.023438,7.875 -2.8125,14.625 C 19.519531,-16.75 17.082031,-11.207031 14,-6.875 10.914062,-2.539062 7.164062,-0.25 2.75,0 c -4.5,-0.164062 -8,-2.707031 -10.5,-7.625 -2.25,-4.832031 -3.289062,-11.082031 -3.125,-18.75 z m 6.625,111.5 c 0,-1.835938 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.644531 8,4.1875 3.5,3.539062 5.375,6.3125 5.625,8.3125 0,2.664062 -1.460938,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 C 8.875,94.375 7.144531,93.269531 4.1875,91.3125 1.226562,89.351562 -0.957031,87.875 -2.375,86.875 -3.625,86.039062 -4.25,85.164062 -4.25,84.25 Z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-4"
overflow="visible"
style="overflow:visible">
<path
id="path38"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-5"
overflow="visible"
style="overflow:visible">
<path
id="path41"
d="m 118.5,-33 c 15.33203,-3.914062 27.375,-8.289062 36.125,-13.125 7.5,-4.082031 11.25,-7.5 11.25,-10.25 0,-0.832031 -0.5625,-1.894531 -1.6875,-3.1875 -1.125,-1.289062 -1.9375,-1.9375 -2.4375,-1.9375 -0.83594,0 -2.02344,0.148438 -3.5625,0.4375 -1.54297,0.292969 -2.64844,0.4375 -3.3125,0.4375 -2.91797,0 -4.98047,-0.769531 -6.1875,-2.3125 -1.21094,-1.539062 -1.8125,-3.601562 -1.8125,-6.1875 0,-1.5 2.16406,-6.539062 6.5,-15.125 1.66406,-3.414062 3.0625,-5.8125 4.1875,-7.1875 1.125,-1.375 2.76953,-2.0625 4.9375,-2.0625 3.58203,0 6.91406,1.9375 10,5.8125 3.08203,3.875 4.625,8.855469 4.625,14.9375 0,6 -0.8125,11.4375 -2.4375,16.3125 -1.625,4.875 -4.14844,9.605469 -7.5625,14.1875 -3.41797,4.585938 -7.83594,9.042969 -13.25,13.375 -8.08594,6.085938 -17.625,11.230469 -28.625,15.4375 -11,4.210938 -23.83594,7.5 -38.5,9.875 C 72.082031,-1.1875 58.082031,0 44.75,0 37.082031,0 30.082031,-0.375 23.75,-1.125 17.414062,-1.875 12.582031,-3.289062 9.25,-5.375 3.082031,-8.789062 0.25,-14.5 0.75,-22.5 c 0.332031,-4.082031 0.832031,-8.4375 1.5,-13.0625 0.664062,-4.625 1.351562,-8.3125 2.0625,-11.0625 0.707031,-2.75 1.5625,-4.125 2.5625,-4.125 0.832031,0 1.332031,1.75 1.5,5.25 0.164062,3.5 0.6875,6.0625 1.5625,7.6875 0.875,1.625 2.207031,3 4,4.125 1.789062,1.125 4.6875,2.210938 8.6875,3.25 4,1.042969 8.6875,1.855469 14.0625,2.4375 5.375,0.585938 12.519531,0.875 21.4375,0.875 12.414062,0 23.019531,-0.4375 31.8125,-1.3125 C 98.726562,-29.3125 108.25,-30.832031 118.5,-33 Z m -38.75,-86.75 c 0,-1.83203 1.5625,-5.8125 4.6875,-11.9375 3.125,-6.125 5.144531,-9.1875 6.0625,-9.1875 1.832031,-0.75 4.5,0.64844 8,4.1875 3.5,3.54297 5.375,6.3125 5.625,8.3125 0,2.66797 -1.46094,6.5 -4.375,11.5 -2.917969,5 -5.042969,7.5 -6.375,7.5 -0.5,-0.25 -2.230469,-1.35156 -5.1875,-3.3125 -2.960938,-1.95703 -5.148438,-3.4375 -6.5625,-4.4375 -1.25,-0.83203 -1.875,-1.70703 -1.875,-2.625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-6"
overflow="visible"
style="overflow:visible">
<path
id="path44"
d="m 78,-56.875 c -1.335938,2.25 -2.25,3.875 -2.75,4.875 -1.417969,2.335938 -2.875,4.210938 -4.375,5.625 -1.75,1.75 -4.042969,3.292969 -6.875,4.625 -6.085938,2.917969 -10.460938,5.75 -13.125,8.5 -1.75,1.75 -3.792969,4.960938 -6.125,9.625 -4.25,8.585938 -8.417969,14.292969 -12.5,17.125 -4.085938,2.917969 -11.417969,5 -22,6.25 C 9.414062,-0.0820312 8.414062,0 7.25,0 H 4.375 c -1.5,0 -2.25,-0.164062 -2.25,-0.5 0,-1.914062 2.539062,-4.5 7.625,-7.75 4,-2.414062 7,-4.207031 9,-5.375 6,-3.414062 10.414062,-6.125 13.25,-8.125 4,-2.914062 6.625,-5.75 7.875,-8.5 4.164062,-8.5 7.625,-14.414062 10.375,-17.75 3.082031,-3.664062 6.625,-6.5 10.625,-8.5 C 67.289062,-60.082031 71,-62.207031 72,-62.875 l 10,2.375 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-7"
overflow="visible"
style="overflow:visible">
<path
id="path47"
d="m 13,-17.625 c -1,1.75 -2.0625,3.480469 -3.1875,5.1875 C 8.6875,-10.726562 7.539062,-9.082031 6.375,-7.5 5.207031,-5.914062 4.0625,-4.476562 2.9375,-3.1875 1.8125,-1.894531 0.832031,-0.832031 0,0 c -0.5,-2.582031 -0.832031,-5.125 -1,-7.625 -0.164062,-2.5 0.167969,-5.039062 1,-7.625 1.25,-0.75 2.207031,-1.414062 2.875,-2 1.664062,-1.5 5.375,-6.582031 11.125,-15.25 -0.667969,-0.664062 -2.585938,-1.601562 -5.75,-2.8125 -3.167969,-1.207031 -6.167969,-1.894531 -9,-2.0625 -2.582031,-0.164062 -4.726562,0.3125 -6.4375,1.4375 -1.707031,1.125 -3.25,2.710938 -4.625,4.75 -1.375,2.042969 -2.5625,2.980469 -3.5625,2.8125 -0.332031,-0.164062 -0.375,-0.851562 -0.125,-2.0625 0.25,-1.207031 0.625,-2.394531 1.125,-3.5625 2.085938,-4.832031 4.480469,-8.4375 7.1875,-10.8125 2.710938,-2.375 5.9375,-3.5625 9.6875,-3.5625 2.75,0 6.164062,0.667969 10.25,2 2.582031,0.917969 4.789062,1.375 6.625,1.375 3.832031,0 7.625,-1.375 11.375,-4.125 0.832031,0 1.125,0.542969 0.875,1.625 -0.25,1.085938 -0.605469,2.355469 -1.0625,3.8125 -0.460938,1.460938 -0.773438,2.4375 -0.9375,2.9375 -0.835938,2.585938 -1.5,4.085938 -2,4.5 -0.5,0.417969 -1.960938,1.5 -4.375,3.25 -1.335938,1 -2.480469,2.148438 -3.4375,3.4375 -0.960938,1.292969 -1.9375,2.835938 -2.9375,4.625 -1,1.792969 -2.292969,4.230469 -3.875,7.3125 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
</g>
<g
id="g184">
<symbol
id="glyph0-0-3"
overflow="visible"
style="overflow:visible">
<path
id="path163"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-1-6"
overflow="visible"
style="overflow:visible">
<path
id="path166"
d="m 79.625,-103.25 c -3.585938,22 -6.8125,38.417969 -9.6875,49.25 -2.875,10.835938 -5.480469,19.105469 -7.8125,24.8125 -2.335938,5.710938 -4.898438,10.0625 -7.6875,13.0625 -2.792969,3 -7.917969,5.855469 -15.375,8.5625 -7.460938,2.710938 -13.6875,4.605469 -18.6875,5.6875 -5,1.085938 -8.125,1.667969 -9.375,1.75 C 9.75,-0.207031 8.957031,-0.4375 8.625,-0.8125 8.289062,-1.1875 8.582031,-2.082031 9.5,-3.5 c 1.582031,-2.25 4.894531,-5.332031 9.9375,-9.25 5.039062,-3.914062 11,-8.789062 17.875,-14.625 6.875,-5.832031 12.019531,-10.976562 15.4375,-15.4375 3.414062,-4.457031 6.4375,-10.539062 9.0625,-18.25 C 64.4375,-68.769531 67,-76.832031 69.5,-85.25 c 2.5,-8.414062 4.3125,-14.125 5.4375,-17.125 1.125,-3 2.269531,-4.45703 3.4375,-4.375 1.332031,0.25 1.75,1.41797 1.25,3.5 z m 8.875,-68.625 c 0.664062,2.41797 0.644531,4.91797 -0.0625,7.5 -0.710938,2.58594 -2.023438,5.29297 -3.9375,8.125 -1.167969,1.91797 -2.398438,3.64844 -3.6875,5.1875 -1.292969,1.54297 -2.648438,3.02344 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.960938,1.14844 -2.875,1.4375 -0.917969,0.29297 -1.585938,0.1875 -2,-0.3125 -3,-2.41406 -5.960938,-4.875 -8.875,-7.375 -2.917969,-2.5 -6.125,-4.83203 -9.625,-7 -0.585938,-0.41406 -0.855469,-0.8125 -0.8125,-1.1875 0.03906,-0.375 0.269531,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.83203 1.164062,-1.22656 1.75,-1.1875 0.582031,0.043 1.207031,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-2-7"
overflow="visible"
style="overflow:visible">
<path
id="path169"
d="m 29.625,-70.625 c -0.667969,8.335938 -2.542969,15.417969 -5.625,21.25 -3.085938,5.835938 -6.585938,8.75 -10.5,8.75 0,-3.164062 1.019531,-13 3.0625,-29.5 2.039062,-16.5 3.582031,-28.3125 4.625,-35.4375 1.039062,-7.125 2.226562,-14.6875 3.5625,-22.6875 1.332031,-8 2.625,-14.45703 3.875,-19.375 1.414062,-4.08203 2.9375,-8.20703 4.5625,-12.375 1.625,-4.16406 3.3125,-8.28906 5.0625,-12.375 1.164062,-1.83203 1.914062,-1.53906 2.25,0.875 -2.085938,13.83594 -4,28.1875 -5.75,43.0625 -1.75,14.875 -2.9375,25.52344 -3.5625,31.9375 -0.625,6.417969 -0.9375,10.167969 -0.9375,11.25 -0.417969,6.835938 -0.625,11.710938 -0.625,14.625 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-3-5"
overflow="visible"
style="overflow:visible">
<path
id="path172"
d="m -16.125,-40.625 c 1.25,-5.332031 2.625,-10 4.125,-14 1.5,-4 2.960938,-7.3125 4.375,-9.9375 1.417969,-2.625 2.792969,-4.644531 4.125,-6.0625 1.335938,-1.414062 2.5,-2.25 3.5,-2.5 v 8.25 c 0,10.5 2.789062,17.835938 8.375,22 3.414062,2.25 6.8125,3 10.1875,2.25 3.375,-0.75 5.957031,-2.5 7.75,-5.25 1.789062,-2.75 3.3125,-5.976562 4.5625,-9.6875 1.25,-3.707031 2.457031,-5.5625 3.625,-5.5625 1.332031,0 1.875,1.335938 1.625,4 -0.08594,4.5 -1.480469,11.8125 -4.1875,21.9375 -2.710938,10.125 -6.375,18.4375 -11,24.9375 -4.625,6.5 -10.230469,9.917969 -16.8125,10.25 -6.75,-0.25 -12,-4.039062 -15.75,-11.375 -3.414062,-7.25 -4.914062,-16.625 -4.5,-28.125 z M 28.5,82.125 c 0.664062,2.414062 0.644531,4.914062 -0.0625,7.5 -0.710938,2.582031 -2.023438,5.289062 -3.9375,8.125 -1.167969,1.914062 -2.398438,3.64453 -3.6875,5.1875 -1.292969,1.53906 -2.648438,3.01953 -4.0625,4.4375 -0.417969,0.5 -1.085938,1.125 -2,1.875 -0.917969,0.75 -1.875,1.45703 -2.875,2.125 -1,0.66406 -1.960938,1.14453 -2.875,1.4375 C 8.082031,113.10156 7.414062,113 7,112.5 c -3,-2.41797 -5.960938,-4.875 -8.875,-7.375 -2.914062,-2.5 -6.125,-4.83594 -9.625,-7 -0.582031,-0.417969 -0.851562,-0.8125 -0.8125,-1.1875 0.04297,-0.375 0.273438,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.582031,-0.835938 1.164062,-1.230469 1.75,-1.1875 0.582031,0.03906 1.207031,0.269531 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.601562 4.875,4.0625 1.5,1.457031 2.8125,3.039062 3.9375,4.75 1.125,1.707031 1.9375,3.601562 2.4375,5.6875 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-4-3"
overflow="visible"
style="overflow:visible">
<path
id="path175"
d=""
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-5-5"
overflow="visible"
style="overflow:visible">
<path
id="path178"
d="M 72.125,0.125 C 58.039062,0.0390625 47.164062,-0.582031 39.5,-1.75 26.164062,-3.832031 16.664062,-7.832031 11,-13.75 5.914062,-18.332031 3.375,-24.582031 3.375,-32.5 c 0,-3.082031 0.289062,-7.5 0.875,-13.25 0.582031,-5.75 1.375,-11.5 2.375,-17.25 0.414062,-2.414062 0.789062,-4.582031 1.125,-6.5 0.25,-1.332031 0.582031,-2.414062 1,-3.25 0.414062,-0.832031 0.875,-1.3125 1.375,-1.4375 0.5,-0.125 0.976562,0.210938 1.4375,1 0.457031,0.792969 0.894531,2.148438 1.3125,4.0625 0.332031,2.085938 0.789062,4.25 1.375,6.5 1.332031,5.417969 4.957031,9.460938 10.875,12.125 15,6.417969 37.914062,9.75 68.75,10 12.75,-0.164062 24.58203,-0.625 35.5,-1.375 11.16406,-0.832031 23.75,-2.789062 37.75,-5.875 14,-3.082031 25.14453,-6.457031 33.4375,-10.125 8.28906,-3.664062 15.35156,-7.625 21.1875,-11.875 4.58203,-3.332031 6.875,-6.539062 6.875,-9.625 0,-1.25 -1.1875,-2.726562 -3.5625,-4.4375 -2.375,-1.707031 -3.9375,-2.5625 -4.6875,-2.5625 -1.41797,0.667969 -3.08594,1.1875 -5,1.5625 -1.91797,0.375 -3.66797,0.480469 -5.25,0.3125 -4.41797,-0.5 -7.71094,-1.875 -9.875,-4.125 -2.16797,-2.25 -3.25,-5.289062 -3.25,-9.125 0,-2.41406 3.20703,-10 9.625,-22.75 2.58203,-5.16406 4.85156,-8.76953 6.8125,-10.8125 1.95703,-2.03906 4.64453,-3.0625 8.0625,-3.0625 5.41406,0 10.4375,2.91797 15.0625,8.75 4.625,5.83594 6.9375,13.29297 6.9375,22.375 0,9 -1.21094,16.792969 -3.625,23.375 -3,9 -7.08594,17.335938 -12.25,25 -6.5,9.25 -13.625,16.5625 -21.375,21.9375 -7.75,5.375 -15.58594,9.648438 -23.5,12.8125 -7.08594,3.5 -16.23047,6.773438 -27.4375,9.8125 -11.21094,3.042969 -24.8125,5.523438 -40.8125,7.4375 -15.835938,1.917969 -29.960938,2.9140625 -42.375,3 z m 82.375,-172 c 0.66406,2.41797 0.64453,4.91797 -0.0625,7.5 -0.71094,2.58594 -2.02344,5.29297 -3.9375,8.125 -1.16797,1.91797 -2.39844,3.64844 -3.6875,5.1875 -1.29297,1.54297 -2.64844,3.02344 -4.0625,4.4375 -0.41797,0.5 -1.08594,1.125 -2,1.875 -0.91797,0.75 -1.875,1.46094 -2.875,2.125 -1,0.66797 -1.96094,1.14844 -2.875,1.4375 -0.91797,0.29297 -1.58594,0.1875 -2,-0.3125 -3,-2.41406 -5.96094,-4.875 -8.875,-7.375 -2.91797,-2.5 -6.125,-4.83203 -9.625,-7 -0.58594,-0.41406 -0.85547,-0.8125 -0.8125,-1.1875 0.0391,-0.375 0.26953,-0.9375 0.6875,-1.6875 l 20,-30.5 c 0.58203,-0.83203 1.16406,-1.22656 1.75,-1.1875 0.58203,0.043 1.20703,0.27344 1.875,0.6875 1.75,1 3.5,2.125 5.25,3.375 1.75,1.25 3.375,2.60547 4.875,4.0625 1.5,1.46094 2.8125,3.04297 3.9375,4.75 1.125,1.71094 1.9375,3.60547 2.4375,5.6875 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
<symbol
id="glyph0-6-6"
overflow="visible"
style="overflow:visible">
<path
id="path181"
d="m 115,-102.5 c -1.83594,3.25 -3.75,6.523438 -5.75,9.8125 -2,3.292969 -4.23047,6.398438 -6.6875,9.3125 -2.46094,2.917969 -5.167969,5.5625 -8.125,7.9375 -2.960938,2.375 -6.3125,4.273438 -10.0625,5.6875 -3.085938,1.25 -5.710938,2.648438 -7.875,4.1875 -2.167969,1.542969 -3.960938,3.1875 -5.375,4.9375 -2.167969,2.335938 -4.042969,5.5625 -5.625,9.6875 -1.585938,4.125 -3.230469,8.480469 -4.9375,13.0625 -1.710938,4.585938 -3.585938,9.0625 -5.625,13.4375 -2.042969,4.375 -4.605469,7.980469 -7.6875,10.8125 C 43,-9.125 36.707031,-6.082031 28.375,-4.5 L 5.5,-0.625 C 4.832031,-0.539062 4.019531,-0.476562 3.0625,-0.4375 2.101562,-0.394531 1.414062,-0.414062 1,-0.5 -0.914062,-1.082031 -1.5,-2.351562 -0.75,-4.3125 0,-6.269531 1.957031,-8.25 5.125,-10.25 c 6.414062,-4.25 11.539062,-7.6875 15.375,-10.3125 3.832031,-2.625 6.957031,-4.769531 9.375,-6.4375 2.414062,-1.664062 4.351562,-3.039062 5.8125,-4.125 1.457031,-1.082031 3.019531,-2.289062 4.6875,-3.625 6.75,-5.082031 11.414062,-10.414062 14,-16 1.5,-2.914062 2.875,-5.75 4.125,-8.5 1.25,-2.75 2.5625,-5.457031 3.9375,-8.125 1.375,-2.664062 2.851562,-5.3125 4.4375,-7.9375 1.582031,-2.625 3.414062,-5.269531 5.5,-7.9375 2.164062,-2.664062 5.082031,-5.269531 8.75,-7.8125 3.664062,-2.539062 8.082031,-5.0625 13.25,-7.5625 0.582031,-0.25 1.539062,-0.8125 2.875,-1.6875 1.332031,-0.875 2.95703,-2.26953 4.875,-4.1875 1.91406,-1.91406 4.10156,-4.51953 6.5625,-7.8125 2.45703,-3.28906 5.0625,-7.47656 7.8125,-12.5625 -1,-1 -3.875,-2.375 -8.625,-4.125 -4.75,-1.83203 -9.25,-2.875 -13.5,-3.125 -3.917969,-0.25 -7.148438,0.46094 -9.6875,2.125 -2.542969,1.66797 -4.855469,4.04297 -6.9375,7.125 -2.085938,3.08594 -3.875,4.5 -5.375,4.25 -0.5,-0.25 -0.585938,-1.28906 -0.25,-3.125 0.414062,-1.83203 1,-3.625 1.75,-5.375 3.164062,-7.25 6.75,-12.625 10.75,-16.125 4.082031,-3.58203 8.957031,-5.375 14.625,-5.375 4.08203,0 9.20703,1 15.375,3 3.83203,1.33594 7.125,2 9.875,2 5.75,0 11.45703,-2.03906 17.125,-6.125 1.25,0 1.6875,0.8125 1.3125,2.4375 -0.375,1.625 -0.9375,3.52344 -1.6875,5.6875 -0.66797,2.16797 -1.125,3.625 -1.375,4.375 -1.25,3.91797 -2.25,6.21094 -3,6.875 -0.75,0.58594 -2.91797,2.16797 -6.5,4.75 -2,1.5 -3.73047,3.23047 -5.1875,5.1875 -1.46094,1.96094 -2.9375,4.27344 -4.4375,6.9375 -1.5,2.66797 -3.41797,6.33594 -5.75,11 z m 0,0"
style="stroke:none"
inkscape:connector-curvature="0" />
</symbol>
</g>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1471"
id="namedview4"
showgrid="false"
inkscape:zoom="0.59454973"
inkscape:cx="-165.7731"
inkscape:cy="361.75575"
inkscape:window-x="0"
inkscape:window-y="55"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
id="path871"
d="m 205.59223,196.11402 c -5.97657,36.66667 -11.35417,64.02995 -16.14583,82.08333 -4.79167,18.0599 -9.13412,31.84245 -13.02084,41.35417 -3.89323,9.51823 -8.16406,16.77083 -12.8125,21.77083 -4.65495,5 -13.19661,9.75912 -25.625,14.27083 -12.43489,4.51823 -22.8125,7.67579 -31.14583,9.47917 -8.333331,1.8099 -13.541664,2.77995 -15.624997,2.91667 -2.083334,-0.13672 -3.404949,-0.52084 -3.958334,-1.14584 -0.559896,-0.625 -0.07161,-2.11588 1.458334,-4.47916 2.636718,-3.75 8.157551,-8.88672 16.562497,-15.41667 8.39844,-6.52344 18.33333,-14.64844 29.79167,-24.375 11.45833,-9.72005 20.03255,-18.29427 25.72916,-25.72916 5.69011,-7.42839 10.72917,-17.56511 15.10417,-30.41667 4.375,-12.84505 8.64583,-26.28255 12.8125,-40.3125 4.16667,-14.02343 7.1875,-23.54166 9.0625,-28.54166 1.875,-5 3.78255,-7.42839 5.72916,-7.29167 2.22006,0.41667 2.91667,2.36328 2.08334,5.83333 z M 220.38389,81.739028 c 1.10677,4.02995 1.07422,8.196616 -0.10416,12.5 -1.1849,4.309899 -3.3724,8.821612 -6.5625,13.541662 -1.94662,3.19662 -3.9974,6.08074 -6.14584,8.64584 -2.15494,2.57161 -4.41406,5.03906 -6.77083,7.39583 -0.69661,0.83333 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.4349 -4.79167,3.54167 -1.66666,1.11328 -3.26823,1.91406 -4.79166,2.39583 -1.52995,0.48828 -2.64323,0.3125 -3.33334,-0.52083 -5,-4.02344 -9.93489,-8.125 -14.79166,-12.29167 -4.86329,-4.16667 -10.20834,-8.05338 -16.04167,-11.66667 -0.97656,-0.6901 -1.42578,-1.35416 -1.35417,-1.97916 0.0651,-0.625 0.44922,-1.5625 1.14584,-2.8125 l 33.33333,-50.833334 c 0.97005,-1.386717 1.9401,-2.044267 2.91667,-1.979167 0.97005,0.07167 2.01171,0.455734 3.125,1.145834 2.91666,1.666666 5.83333,3.541666 8.74999,5.624999 2.91667,2.083334 5.625,4.34245 8.125,6.770833 2.5,2.4349 4.6875,5.071617 6.5625,7.916667 1.875,2.851566 3.22917,6.009116 4.0625,9.479166 z m 0,0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
d="m 256.21722,250.48902 c -1.11328,13.89323 -4.23828,25.69662 -9.375,35.41667 -5.14323,9.72656 -10.97656,14.58333 -17.5,14.58333 0,-5.27344 1.69922,-21.66667 5.10417,-49.16667 3.39843,-27.49999 5.97005,-47.18749 7.70833,-59.06249 1.73177,-11.875 3.71094,-24.47917 5.9375,-37.8125 2.22005,-13.33333 4.375,-24.09505 6.45833,-32.29167 2.35677,-6.80338 4.89583,-13.67838 7.60417,-20.625 2.70833,-6.940096 5.52083,-13.815095 8.4375,-20.624995 1.9401,-3.053383 3.1901,-2.5651 3.75,1.458333 -3.47657,23.059902 -6.66667,46.979162 -9.58334,71.770832 -2.91666,24.79166 -4.89583,42.53906 -5.9375,53.22916 -1.04166,10.69662 -1.5625,16.94662 -1.5625,18.75 -0.69661,11.39323 -1.04166,19.51823 -1.04166,24.375 z m 0,0"
id="path875" />
<path
id="path945"
d="m 229.34222,300.48902 c 2.08333,-8.88672 4.375,-16.66667 6.875,-23.33333 2.5,-6.66667 4.9349,-12.1875 7.29167,-16.5625 2.36328,-4.375 4.65495,-7.74089 6.875,-10.10417 2.22656,-2.35677 4.16666,-3.75 5.83333,-4.16667 v 13.75 c 0,17.5 4.64844,29.72657 13.95833,36.66667 5.69011,3.75 11.35417,5 16.97917,3.75 5.625,-1.25 9.92838,-4.16667 12.91666,-8.75 2.98177,-4.58333 5.52084,-9.96094 7.60417,-16.14583 2.08333,-6.17839 4.09505,-9.27084 6.04167,-9.27084 2.22005,0 3.125,2.22657 2.70833,6.66667 -0.14323,7.5 -2.46745,19.6875 -6.97917,36.5625 -4.51823,16.875 -10.625,30.72916 -18.33333,41.5625 -7.70833,10.83333 -17.05078,16.52995 -28.02083,17.08333 -11.25,-0.41667 -20,-6.73177 -26.25,-18.95833 -5.6901,-12.08334 -8.1901,-27.70833 -7.5,-46.875 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
id="path943"
d="m 286.78334,583.03989 c 1.10677,4.02343 1.07422,8.1901 -0.10416,12.5 -1.1849,4.30338 -3.3724,8.8151 -6.5625,13.54167 -1.94662,3.1901 -3.9974,6.07421 -6.14584,8.64583 -2.15495,2.5651 -4.41406,5.03255 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33333,3.125 -1.52995,1.25 -3.125,2.42839 -4.79167,3.54167 -1.66667,1.10677 -3.26823,1.90755 -4.79167,2.39583 -1.52994,0.48177 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02995 -9.9349,-8.125 -14.79167,-12.29167 -4.85677,-4.16666 -10.20833,-8.0599 -16.04166,-11.66666 -0.97005,-0.69662 -1.41927,-1.35417 -1.35417,-1.97917 0.0716,-0.625 0.45573,-1.5625 1.14583,-2.8125 l 33.33334,-50.83333 c 0.97005,-1.39323 1.9401,-2.05078 2.91666,-1.97917 0.97006,0.0652 2.01172,0.44922 3.125,1.14584 2.91667,1.66666 5.83334,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.33593 8.125,6.77083 2.5,2.42838 4.6875,5.0651 6.5625,7.91667 1.875,2.84505 3.22917,6.00259 4.0625,9.47916 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
id="path879"
d="M 303.71722,505.07234"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path925"
d="m 168.42167,500.82557 c -23.47656,-0.14323 -41.60156,-1.17838 -54.375,-3.125 -22.226562,-3.47005 -38.059894,-10.13671 -47.499997,-20 -8.476563,-7.63671 -12.708333,-18.05338 -12.708333,-31.24999 0,-5.13672 0.48177,-12.5 1.458333,-22.08334 0.970052,-9.58333 2.291667,-19.16666 3.958333,-28.75 0.690104,-4.02343 1.315104,-7.63671 1.875,-10.83333 0.416667,-2.22005 0.970052,-4.02344 1.666667,-5.41667 0.690103,-1.38671 1.458333,-2.1875 2.291666,-2.39583 0.833334,-0.20833 1.627604,0.35156 2.395834,1.66667 0.761718,1.32161 1.490885,3.58073 2.187499,6.77083 0.553385,3.47656 1.315104,7.08333 2.291667,10.83333 2.220052,9.02995 8.261718,15.76823 18.124999,20.20834 25.000002,10.69661 63.190102,16.25 114.583332,16.66666 21.25,-0.27343 40.97005,-1.04166 59.16666,-2.29166 18.60677,-1.38672 39.58333,-4.64844 62.91667,-9.79167 23.33333,-5.13672 41.90754,-10.76172 55.72916,-16.875 13.8151,-6.10677 25.58593,-12.70833 35.3125,-19.79167 7.63671,-5.55338 11.45833,-10.89843 11.45833,-16.04166 0,-2.08333 -1.97917,-4.54427 -5.9375,-7.39583 -3.95833,-2.84506 -6.5625,-4.27084 -7.8125,-4.27084 -2.36328,1.11328 -5.14323,1.97917 -8.33333,2.60417 -3.19662,0.625 -6.11328,0.80078 -8.75,0.52083 -7.36328,-0.83333 -12.85157,-3.125 -16.45833,-6.875 -3.61329,-3.75 -5.41667,-8.8151 -5.41667,-15.20833 0,-4.02343 5.34505,-16.66667 16.04167,-37.91667 4.30338,-8.60676 8.08593,-14.61588 11.35416,-18.02083 3.26172,-3.39843 7.74089,-5.10416 13.4375,-5.10416 9.02343,0 17.39583,4.86328 25.10417,14.58333 7.70833,9.72656 11.5625,22.15495 11.5625,37.29166 0,15 -2.01824,27.98828 -6.04167,38.95834 -5,14.99999 -11.8099,28.89322 -20.41667,41.66666 -10.83333,15.41667 -22.70833,27.60417 -35.62499,36.5625 -12.91667,8.95833 -25.97657,16.08073 -39.16667,21.35416 -11.8099,5.83334 -27.05078,11.28907 -45.72916,16.35417 -18.6849,5.07162 -41.35417,9.20573 -68.02083,12.39583 -26.39323,3.19662 -49.9349,4.85677 -70.625,5 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
<path
inkscape:connector-curvature="0"
id="path923"
d="m 430.22191,133.16177 c 1.10676,4.02995 1.07421,8.19662 -0.10417,12.5 -1.1849,4.3099 -3.3724,8.82162 -6.5625,13.54167 -1.94661,3.19661 -3.9974,6.08073 -6.14583,8.64583 -2.15495,2.57162 -4.41407,5.03907 -6.77083,7.39583 -0.69662,0.83334 -1.8099,1.875 -3.33334,3.125 -1.52995,1.25 -3.125,2.4349 -4.79166,3.54167 -1.66667,1.11328 -3.26824,1.91407 -4.79167,2.39583 -1.52995,0.48829 -2.64323,0.3125 -3.33333,-0.52083 -5,-4.02343 -9.9349,-8.125 -14.79167,-12.29167 -4.86328,-4.16666 -10.20833,-8.05338 -16.04167,-11.66666 -0.97656,-0.6901 -1.42578,-1.35417 -1.35416,-1.97917 0.0652,-0.625 0.44921,-1.5625 1.14583,-2.8125 l 33.33333,-50.83333 c 0.97005,-1.38672 1.9401,-2.04427 2.91667,-1.97917 0.97005,0.0717 2.01172,0.45574 3.125,1.14584 2.91667,1.66666 5.83333,3.54166 8.75,5.625 2.91667,2.08333 5.625,4.34245 8.125,6.77083 2.5,2.4349 4.6875,5.07162 6.5625,7.91667 1.875,2.85156 3.22916,6.00911 4.0625,9.47916 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
<path
inkscape:connector-curvature="0"
id="path883"
d="M 305.71333,214.15892"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663" />
<path
id="path887"
d="m 599.12998,319.78391 c -3.0599,5.41667 -6.25,10.8724 -9.58333,16.35417 -3.33334,5.48828 -7.05079,10.66406 -11.14584,15.52083 -4.10156,4.86328 -8.61328,9.27084 -13.54166,13.22917 -4.9349,3.95833 -10.52084,7.12239 -16.77084,9.47916 -5.14323,2.08334 -9.51823,4.41407 -13.125,6.97917 -3.61328,2.57162 -6.60156,5.3125 -8.95833,8.22917 -3.61328,3.89323 -6.73828,9.27083 -9.375,16.14583 -2.64323,6.875 -5.38411,14.13411 -8.22916,21.77083 -2.85157,7.64323 -5.97657,15.10417 -9.375,22.39583 -3.40495,7.29167 -7.67579,13.30079 -12.8125,18.02084 -7.08334,7.5 -17.57162,12.57161 -31.45834,15.20833 l -38.12499,6.45833 c -1.11329,0.14323 -2.46745,0.2474 -4.0625,0.3125 -1.60157,0.0716 -2.7474,0.0391 -3.4375,-0.10416 -3.19011,-0.97005 -4.16667,-3.08594 -2.91667,-6.35417 1.25,-3.26172 4.51172,-6.5625 9.79167,-9.89583 10.6901,-7.08334 19.23177,-12.8125 25.625,-17.1875 6.38671,-4.375 11.59505,-7.94922 15.62499,-10.72917 4.02344,-2.77343 7.25261,-5.0651 9.6875,-6.875 2.42839,-1.80338 5.03256,-3.8151 7.8125,-6.04166 11.25,-8.47006 19.02344,-17.35677 23.33334,-26.66667 2.5,-4.85677 4.79166,-9.58333 6.875,-14.16667 2.08333,-4.58333 4.27083,-9.09505 6.5625,-13.54166 2.29166,-4.44011 4.7526,-8.85417 7.39583,-13.22917 2.63672,-4.375 5.6901,-8.78255 9.16667,-13.22916 3.60677,-4.44011 8.47005,-8.78256 14.58333,-13.02084 6.10677,-4.23177 13.47005,-8.4375 22.08333,-12.60416 0.97005,-0.41667 2.5651,-1.35417 4.79167,-2.8125 2.22005,-1.45834 4.92838,-3.78255 8.125,-6.97917 3.1901,-3.1901 6.83593,-7.53255 10.9375,-13.02083 4.09505,-5.48177 8.4375,-12.46094 13.02083,-20.9375 -1.66667,-1.66667 -6.45833,-3.95833 -14.375,-6.875 -7.91667,-3.05338 -15.41667,-4.79167 -22.5,-5.20833 -6.52995,-0.41667 -11.91406,0.76823 -16.14583,3.54166 -4.23828,2.77995 -8.09245,6.73829 -11.5625,11.875 -3.47657,5.14323 -6.45833,7.5 -8.95833,7.08333 -0.83334,-0.41666 -0.97657,-2.14843 -0.41667,-5.20833 0.6901,-3.05338 1.66667,-6.04166 2.91667,-8.95833 5.27343,-12.08333 11.24999,-21.04167 17.91666,-26.875 6.80339,-5.97005 14.92839,-8.95833 24.375,-8.95833 6.80338,0 15.34505,1.66666 25.625,5 6.38672,2.22656 11.875,3.33333 16.45833,3.33333 9.58333,0 19.09505,-3.39843 28.54167,-10.20833 2.08333,0 2.8125,1.35416 2.1875,4.0625 -0.625,2.70833 -1.5625,5.8724 -2.8125,9.47916 -1.11329,3.61329 -1.875,6.04167 -2.29167,7.29167 -2.08333,6.52995 -3.75,10.35157 -5,11.45833 -1.25,0.97657 -4.86328,3.61329 -10.83333,7.91667 -3.33334,2.5 -6.21745,5.38411 -8.64584,8.64583 -2.43489,3.26823 -4.89583,7.1224 -7.39583,11.5625 -2.5,4.44662 -5.69661,10.5599 -9.58333,18.33333 z m 0,0"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66666663"
inkscape:connector-curvature="0" />
<use
style="fill:#000000;fill-opacity:1"
id="use62"
y="291"
x="119.25"
xlink:href="#glyph0-4"
width="100%"
height="100%"
transform="matrix(1.3333333,0,0,1.3333333,72.589732,-189.32751)" />
<use
style="fill:#000000;fill-opacity:1"
id="use196"
y="391"
x="168.375"
xlink:href="#glyph0-4-3"
width="100%"
height="100%"
transform="matrix(1.3333333,0,0,1.3333333,-861.41828,-631.73483)" />
</svg>

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -67,7 +67,8 @@ EXTRA_HFILES=$(top_builddir)/src/hb-version.h
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES= \
HarfBuzz.png
HarfBuzz.png \
HarfBuzz.svg
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
@ -110,7 +111,7 @@ EXTRA_DIST += version.xml.in
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
#DISTCLEANFILES +=
# Comment this out if you want 'make check' to test you doc status
# Comment this out if you don't want 'make check' to test you doc status
# and run some sanity checks
if ENABLE_GTK_DOC
TESTS_ENVIRONMENT = cd $(srcdir) && \

View File

@ -22,7 +22,7 @@
source tree is available
<ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
Also available on
<ulink url="https://github.com/behdad/harfbuzz">github</ulink>.
<ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
See <xref linkend="download" endterm="download.title"/> for release tarballs.
</para>
<para>
@ -60,7 +60,7 @@
</partinfo>
<title>Reference manual</title>
<chapter>
<title>Harfbuzz API</title>
<title>HarfBuzz API</title>
<xi:include href="xml/hb.xml"/>
<xi:include href="xml/hb-common.xml"/>
<xi:include href="xml/hb-unicode.xml"/>
@ -80,6 +80,7 @@
<xi:include href="xml/hb-ot-tag.xml"/>
<xi:include href="xml/hb-ot-font.xml"/>
<xi:include href="xml/hb-ot-shape.xml"/>
<xi:include href="xml/hb-ot-math.xml"/>
<xi:include href="xml/hb-shape-plan.xml"/>
@ -175,6 +176,30 @@
<title>Index of new symbols in 1.1.3</title>
<xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-1-2-3" role="1.2.3">
<title>Index of new symbols in 1.2.3</title>
<xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-1-3-3" role="1.3.3">
<title>Index of new symbols in 1.3.3</title>
<xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-1-4-2" role="1.4.2">
<title>Index of new symbols in 1.4.2</title>
<xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-1-4-3" role="1.4.3">
<title>Index of new symbols in 1.4.3</title>
<xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-1-5-0" role="1.5.0">
<title>Index of new symbols in 1.5.0</title>
<xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include>
</index>
<index id="api-index-1-6-0" role="1.6.0">
<title>Index of new symbols in 1.6.0</title>
<xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include>
</index>
<index id="deprecated-api-index" role="deprecated">
<title>Index of deprecated API</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>

View File

@ -9,6 +9,7 @@ HB_EXTERN
<FILE>hb-blob</FILE>
hb_blob_create
hb_blob_create_sub_blob
hb_blob_copy_writable_or_fail
hb_blob_destroy
hb_blob_get_data
hb_blob_get_data_writable
@ -41,6 +42,7 @@ hb_buffer_add_utf32
hb_buffer_add_utf16
hb_buffer_add_utf8
hb_buffer_add_latin1
hb_buffer_append
hb_buffer_set_content_type
hb_buffer_get_content_type
hb_buffer_set_direction
@ -77,9 +79,12 @@ hb_buffer_serialize_format_to_string
hb_buffer_serialize_list_formats
hb_segment_properties_equal
hb_segment_properties_hash
hb_buffer_diff
hb_buffer_set_message_func
hb_buffer_t
hb_glyph_info_get_glyph_flags
hb_glyph_info_t
hb_glyph_flags_t
hb_glyph_position_t
hb_buffer_content_type_t
hb_buffer_flags_t
@ -87,6 +92,7 @@ hb_buffer_cluster_level_t
hb_segment_properties_t
hb_buffer_serialize_format_t
hb_buffer_serialize_flags_t
hb_buffer_diff_flags_t
hb_buffer_message_func_t
</SECTION>
@ -144,13 +150,18 @@ uint8_t
HB_BUFFER_FLAGS_DEFAULT
HB_BUFFER_SERIALIZE_FLAGS_DEFAULT
HB_SCRIPT_CANADIAN_ABORIGINAL
hb_font_funcs_set_glyph_func
hb_font_get_glyph_func_t
hb_set_invert
</SECTION>
<SECTION>
<FILE>hb-coretext</FILE>
HB_CORETEXT_TAG_KERX
HB_CORETEXT_TAG_MORT
HB_CORETEXT_TAG_MORX
hb_coretext_face_create
hb_coretext_font_create
hb_coretext_face_get_cg_font
hb_coretext_font_get_ct_font
</SECTION>
@ -161,6 +172,7 @@ hb_face_create
hb_face_create_for_tables
hb_face_destroy
hb_face_get_empty
hb_face_get_table_tags
hb_face_get_glyph_count
hb_face_get_index
hb_face_get_upem
@ -193,7 +205,6 @@ hb_font_funcs_reference
hb_font_funcs_set_glyph_contour_point_func
hb_font_funcs_set_glyph_extents_func
hb_font_funcs_set_glyph_from_name_func
hb_font_funcs_set_glyph_func
hb_font_funcs_set_glyph_h_advance_func
hb_font_funcs_set_glyph_h_kerning_func
hb_font_funcs_set_glyph_h_origin_func
@ -201,7 +212,9 @@ hb_font_funcs_set_glyph_name_func
hb_font_funcs_set_glyph_v_advance_func
hb_font_funcs_set_glyph_v_kerning_func
hb_font_funcs_set_glyph_v_origin_func
hb_font_funcs_set_nominal_glyph_func
hb_font_funcs_set_user_data
hb_font_funcs_set_variation_glyph_func
hb_font_funcs_t
hb_font_get_empty
hb_font_get_face
@ -216,7 +229,6 @@ hb_font_get_glyph_extents_for_origin
hb_font_get_glyph_extents_func_t
hb_font_get_glyph_from_name
hb_font_get_glyph_from_name_func_t
hb_font_get_glyph_func_t
hb_font_get_glyph_h_advance
hb_font_get_glyph_h_advance_func_t
hb_font_get_glyph_h_kerning
@ -235,20 +247,35 @@ hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
hb_font_get_glyph_v_origin
hb_font_get_glyph_v_origin_func_t
hb_font_get_nominal_glyph
hb_font_get_nominal_glyph_func_t
hb_font_get_parent
hb_font_get_ppem
hb_font_get_ptem
hb_font_get_scale
hb_font_get_user_data
hb_font_get_variation_glyph
hb_font_get_variation_glyph_func_t
hb_font_get_var_coords_normalized
hb_font_glyph_from_string
hb_font_glyph_to_string
hb_font_is_immutable
hb_font_make_immutable
hb_font_reference
hb_font_set_face
hb_font_set_funcs
hb_font_set_funcs_data
hb_font_set_parent
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_subtract_glyph_origin_for_direction
hb_font_t
hb_reference_table_func_t
@ -260,7 +287,6 @@ hb_font_get_font_h_extents_func_t
hb_font_get_font_v_extents_func_t
hb_font_get_h_extents
hb_font_get_v_extents
hb_font_set_parent
</SECTION>
<SECTION>
@ -270,6 +296,7 @@ hb_ft_face_create_cached
hb_ft_face_create_referenced
hb_ft_font_create
hb_ft_font_create_referenced
hb_ft_font_changed
hb_ft_font_get_face
hb_ft_font_set_load_flags
hb_ft_font_get_load_flags
@ -289,6 +316,7 @@ hb_glib_blob_create
HB_GOBJECT_TYPE_BLOB
HB_GOBJECT_TYPE_BUFFER
HB_GOBJECT_TYPE_BUFFER_CONTENT_TYPE
HB_GOBJECT_TYPE_BUFFER_DIFF_FLAGS
HB_GOBJECT_TYPE_BUFFER_FLAGS
HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FLAGS
HB_GOBJECT_TYPE_BUFFER_SERIALIZE_FORMAT
@ -296,8 +324,14 @@ HB_GOBJECT_TYPE_DIRECTION
HB_GOBJECT_TYPE_FACE
HB_GOBJECT_TYPE_FONT
HB_GOBJECT_TYPE_FONT_FUNCS
HB_GOBJECT_TYPE_GLYPH_FLAGS
HB_GOBJECT_TYPE_MEMORY_MODE
HB_GOBJECT_TYPE_OT_LAYOUT_GLYPH_CLASS
HB_GOBJECT_TYPE_OT_MATH_CONSTANT
HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART
HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART_FLAGS
HB_GOBJECT_TYPE_OT_MATH_GLYPH_VARIANT
HB_GOBJECT_TYPE_OT_MATH_KERN
HB_GOBJECT_TYPE_SCRIPT
HB_GOBJECT_TYPE_SHAPE_PLAN
HB_GOBJECT_TYPE_UNICODE_COMBINING_CLASS
@ -312,6 +346,7 @@ HB_GOBJECT_TYPE_SET
HB_GOBJECT_TYPE_USER_DATA_KEY
hb_gobject_blob_get_type
hb_gobject_buffer_content_type_get_type
hb_gobject_buffer_diff_flags_get_type
hb_gobject_buffer_flags_get_type
hb_gobject_buffer_get_type
hb_gobject_buffer_serialize_flags_get_type
@ -320,8 +355,14 @@ hb_gobject_direction_get_type
hb_gobject_face_get_type
hb_gobject_font_funcs_get_type
hb_gobject_font_get_type
hb_gobject_glyph_flags_get_type
hb_gobject_memory_mode_get_type
hb_gobject_ot_layout_glyph_class_get_type
hb_gobject_ot_math_constant_get_type
hb_gobject_ot_math_glyph_part_get_type
hb_gobject_ot_math_glyph_part_flags_get_type
hb_gobject_ot_math_glyph_variant_get_type
hb_gobject_ot_math_kern_get_type
hb_gobject_script_get_type
hb_gobject_shape_plan_get_type
hb_gobject_unicode_combining_class_get_type
@ -378,12 +419,14 @@ hb_ot_shape_glyphs_closure
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
HB_OT_LAYOUT_NO_FEATURE_INDEX
HB_OT_LAYOUT_NO_SCRIPT_INDEX
HB_OT_LAYOUT_NO_VARIATIONS_INDEX
HB_OT_TAG_GDEF
HB_OT_TAG_GPOS
HB_OT_TAG_GSUB
HB_OT_TAG_JSTF
hb_ot_layout_collect_lookups
hb_ot_layout_feature_get_lookups
hb_ot_layout_feature_with_variations_get_lookups
hb_ot_layout_get_attach_points
hb_ot_layout_get_glyph_class
hb_ot_layout_get_glyphs_in_class
@ -404,6 +447,7 @@ hb_ot_layout_lookup_would_substitute
hb_ot_layout_script_find_language
hb_ot_layout_script_get_language_tags
hb_ot_layout_table_choose_script
hb_ot_layout_table_find_feature_variations
hb_ot_layout_table_find_script
hb_ot_layout_table_get_feature_tags
hb_ot_layout_table_get_script_tags
@ -416,6 +460,43 @@ Xhb_ot_layout_lookup_position
Xhb_ot_layout_lookup_substitute
</SECTION>
<SECTION>
<FILE>hb-ot-var</FILE>
HB_OT_TAG_VAR_AXIS_ITALIC
HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
HB_OT_TAG_VAR_AXIS_SLANT
HB_OT_TAG_VAR_AXIS_WEIGHT
HB_OT_TAG_VAR_AXIS_WIDTH
HB_OT_VAR_NO_AXIS_INDEX
hb_ot_var_axis_t
hb_ot_var_has_data
hb_ot_var_find_axis
hb_ot_var_get_axis_count
hb_ot_var_get_axes
hb_ot_var_normalize_variations
hb_ot_var_normalize_coords
</SECTION>
<SECTION>
<FILE>hb-ot-math</FILE>
HB_OT_TAG_MATH
HB_OT_MATH_SCRIPT
hb_ot_math_constant_t
hb_ot_math_kern_t
hb_ot_math_glyph_variant_t
hb_ot_math_glyph_part_flags_t
hb_ot_math_glyph_part_t
hb_ot_math_has_data
hb_ot_math_get_constant
hb_ot_math_get_glyph_italics_correction
hb_ot_math_get_glyph_top_accent_attachment
hb_ot_math_get_glyph_kerning
hb_ot_math_is_glyph_extended_shape
hb_ot_math_get_glyph_variants
hb_ot_math_get_min_connector_overlap
hb_ot_math_get_glyph_assembly
</SECTION>
<SECTION>
<FILE>hb-ot-tag</FILE>
HB_OT_TAG_DEFAULT_LANGUAGE
@ -444,11 +525,12 @@ hb_set_get_population
hb_set_get_user_data
hb_set_has
hb_set_intersect
hb_set_invert
hb_set_is_empty
hb_set_is_equal
hb_set_next
hb_set_previous
hb_set_next_range
hb_set_previous_range
hb_set_reference
hb_set_set
hb_set_set_user_data
@ -460,8 +542,8 @@ hb_set_union
<SECTION>
<FILE>hb-shape</FILE>
hb_feature_from_string
hb_feature_t
hb_feature_from_string
hb_feature_to_string
hb_shape
hb_shape_full
@ -472,6 +554,8 @@ hb_shape_list_shapers
<FILE>hb-shape-plan</FILE>
hb_shape_plan_create
hb_shape_plan_create_cached
hb_shape_plan_create2
hb_shape_plan_create_cached2
hb_shape_plan_destroy
hb_shape_plan_execute
hb_shape_plan_get_empty
@ -526,6 +610,8 @@ hb_unicode_script_func_t
<FILE>hb-uniscribe</FILE>
hb_uniscribe_font_get_hfont
hb_uniscribe_font_get_logfontw
<SUBSECTION Private>
hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>

View File

@ -1,7 +1,7 @@
<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 HarfBuzz is a series of Unicode characters, stored in a
buffer. In this chapter, we'll look at how to set up a buffer with
the text that we want and then customize the properties of the
buffer.
@ -15,7 +15,7 @@
default values and ready to accept your Unicode strings.
</para>
<para>
Harfbuzz manages the memory of objects that it creates (such as
HarfBuzz manages the memory of objects that it creates (such as
buffers), so you don't have to. When you have finished working on
a buffer, you can call <literal>hb_buffer_destroy()</literal>:
</para>
@ -27,7 +27,7 @@
<para>
This will destroy the object and free its associated memory -
unless some other part of the program holds a reference to this
buffer. If you acquire a Harfbuzz buffer from another subsystem
buffer. If you acquire a HarfBuzz buffer from another subsystem
and want to ensure that it is not garbage collected by someone
else destroying it, you should increase its reference count:
</para>
@ -53,8 +53,8 @@ void somefunc(hb_buffer_t *buffer) {
<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
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)
</para>

View File

@ -290,11 +290,11 @@
0 ,3,2,4
</programlisting>
<para>
There's no way to differentitate between these two scenarios based
There's no way to differentiate between these two scenarios based
on the cluster numbers alone.
</para>
<para>
Another problem appens with ligatures under level 2 if the
Another problem happens with ligatures under level 2 if the
direction of the text is forced to opposite of its natural
direction (e.g. left-to-right Arabic). But that's too much of a
corner case to worry about.

View File

@ -6,7 +6,7 @@
</para>
</section>
<section id="using-harfbuzzs-native-opentype-implementation">
<title>Using Harfbuzz's native OpenType implementation</title>
<title>Using HarfBuzz's native OpenType implementation</title>
<para>
</para>
</section>

View File

@ -1,7 +1,7 @@
<chapter id="hello-harfbuzz">
<title>Hello, Harfbuzz</title>
<title>Hello, HarfBuzz</title>
<para>
Here's the simplest Harfbuzz that can possibly work. We will improve
Here's the simplest HarfBuzz that can possibly work. We will improve
it later.
</para>
<orderedlist numeration="arabic">
@ -91,23 +91,23 @@
hb_font_destroy(hb_ft_font);
</programlisting>
<section id="what-harfbuzz-doesnt-do">
<title>What Harfbuzz doesn't do</title>
<title>What HarfBuzz doesn't do</title>
<para>
The code above will take a UTF8 string, shape it, and give you the
information required to lay it out correctly on a single
horizontal (or vertical) line using the font provided. That is the
extent of Harfbuzz's responsibility.
extent of HarfBuzz's responsibility.
</para>
<para>
If you are implementing a text layout engine you may have other
responsibilities, that Harfbuzz will not help you with:
responsibilities, that HarfBuzz will not help you with:
</para>
<itemizedlist>
<listitem>
<para>
Harfbuzz won't help you with bidirectionality. If you want to
HarfBuzz won't help you with bidirectionality. If you want to
lay out text with mixed Hebrew and English, you will need to
ensure that the buffer provided to Harfbuzz has those
ensure that the buffer provided to HarfBuzz has those
characters in the correct layout order. This will be different
from the logical order in which the Unicode text is stored. In
other words, the user will hit the keys in the following
@ -127,30 +127,30 @@ ABC אבג DEF
(&quot;bidi&quot; is short for bidirectional), and there's an
algorithm as an annex to the Unicode Standard which tells you how
to reorder a string from logical order into presentation order.
Before sending your string to Harfbuzz, you may need to apply the
Before sending your string to HarfBuzz, you may need to apply the
bidi algorithm to it. Libraries such as ICU and fribidi can do
this for you.
</para>
</listitem>
<listitem>
<para>
Harfbuzz won't help you with text that contains different font
HarfBuzz won't help you with text that contains different font
properties. For instance, if you have the string &quot;a
<emphasis>huge</emphasis> breakfast&quot;, and you expect
&quot;huge&quot; to be italic, you will need to send three
strings to Harfbuzz: <literal>a</literal>, in your Roman font;
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
<literal>huge</literal> using your italic font; and
<literal>breakfast</literal> using your Roman font again.
Similarly if you change font, font size, script, language or
direction within your string, you will need to shape each run
independently and then output them independently. Harfbuzz
independently and then output them independently. HarfBuzz
expects to shape a run of characters sharing the same
properties.
</para>
</listitem>
<listitem>
<para>
Harfbuzz won't help you with line breaking, hyphenation or
HarfBuzz won't help you with line breaking, hyphenation or
justification. As mentioned above, it lays out the string
along a <emphasis>single line</emphasis> of, notionally,
infinite length. If you want to find out where the potential
@ -158,12 +158,12 @@ ABC אבג DEF
could use the ICU library's break iterator functions.
</para>
<para>
Harfbuzz can tell you how wide a shaped piece of text is, which is
HarfBuzz can tell you how wide a shaped piece of text is, which is
useful input to a justification algorithm, but it knows nothing
about paragraphs, lines or line lengths. Nor will it adjust the
space between words to fit them proportionally into a line. If you
want to layout text in paragraphs, you will probably want to send
each word of your text to Harfbuzz to determine its shaped width
each word of your text to HarfBuzz to determine its shaped width
after glyph substitutions, then work out how many words will fit
on a line, and then finally output each word of the line separated
by a space of the correct size to fully justify the paragraph.
@ -171,12 +171,12 @@ ABC אבג DEF
</listitem>
</itemizedlist>
<para>
As a layout engine implementor, Harfbuzz will help you with the
As a layout engine implementor, HarfBuzz will help you with the
interface between your text and your font, and that's something
that you'll need - what you then do with the glyphs that your font
returns is up to you. The example we saw above enough to get us
started using Harfbuzz. Now we are going to use the remainder of
Harfbuzz's API to refine that example and improve our text shaping
started using HarfBuzz. Now we are going to use the remainder of
HarfBuzz's API to refine that example and improve our text shaping
capabilities.
</para>
</section>

View File

@ -1,5 +1,5 @@
<chapter id="install-harfbuzz">
<title>Install Harfbuzz</title>
<title>Install HarfBuzz</title>
<section id="download">
<title id="download.title">Download</title>
<para>
@ -12,7 +12,7 @@
<para>
The canonical source tree is available
<ulink url="http://cgit.freedesktop.org/harfbuzz/">here</ulink>.
Also available on <ulink url="https://github.com/behdad/harfbuzz">github</ulink>.
Also available on <ulink url="https://github.com/harfbuzz/harfbuzz">github</ulink>.
</para>
<para>
The API that comes with <filename class='headerfile'>hb.h</filename> will
@ -50,7 +50,7 @@
and hb-shape under <filename>util/</filename>.
</para>
<para>
If you are bootstraping from git, you need a few more tools before you
If you are bootstrapping from git, you need a few more tools before you
can run <filename>autogen.sh</filename> for the first time. Namely,
pkg-config and <ulink url="http://www.complang.org/ragel/">ragel</ulink>.
Again, on Ubuntu / Debian:

View File

@ -1,7 +1,7 @@
<chapter id="what-is-harfbuzz">
<title>What is Harfbuzz?</title>
<title>What is HarfBuzz?</title>
<para>
Harfbuzz is a <emphasis>text shaping engine</emphasis>. It solves
HarfBuzz is a <emphasis>text shaping engine</emphasis>. It solves
the problem of selecting and positioning glyphs from a font given a
Unicode string.
</para>
@ -9,17 +9,17 @@
<title>Why do I need it?</title>
<para>
Text shaping is an integral part of preparing text for display. It
is a fairly low level operation; Harfbuzz is used directly by
is a fairly low level operation; HarfBuzz is used directly by
graphic rendering libraries such as Pango, and the layout engines
in Firefox, LibreOffice and Chromium. Unless you are
<emphasis>writing</emphasis> one of these layout engines yourself,
you will probably not need to use Harfbuzz - normally higher level
you will probably not need to use HarfBuzz - normally higher level
libraries will turn text into glyphs for you.
</para>
<para>
However, if you <emphasis>are</emphasis> writing a layout engine
or graphics library yourself, you will need to perform text
shaping, and this is where Harfbuzz can help you. Here are some
shaping, and this is where HarfBuzz can help you. Here are some
reasons why you need it:
</para>
<itemizedlist>
@ -95,20 +95,20 @@
<para>
If this is something that you need to do, then you need a text
shaping engine: you could use Uniscribe if you are using Windows;
you could use CoreText on OS X; or you could use Harfbuzz. In the
you could use CoreText on OS X; or you could use HarfBuzz. In the
rest of this manual, we are going to assume that you are the
implementor of a text layout engine.
</para>
</section>
<section id="why-is-it-called-harfbuzz">
<title>Why is it called Harfbuzz?</title>
<title>Why is it called HarfBuzz?</title>
<para>
Harfbuzz began its life as text shaping code within the FreeType
HarfBuzz began its life as text shaping code within the FreeType
project, (and you will see references to the FreeType authors
within the source code copyright declarations) but was then
abstracted out to its own project. This project is maintained by
Behdad Esfahbod, and named Harfbuzz. Originally, it was a shaping
engine for OpenType fonts - &quot;Harfbuzz&quot; is the Persian
Behdad Esfahbod, and named HarfBuzz. Originally, it was a shaping
engine for OpenType fonts - &quot;HarfBuzz&quot; is the Persian
for &quot;open type&quot;.
</para>
</section>

57
git.mk
View File

@ -48,7 +48,7 @@ GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
#
# This file knows how to handle autoconf, automake, libtool, gtk-doc,
# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
# appstream.
# appstream, hotdoc.
#
# This makefile provides the following targets:
#
@ -86,6 +86,7 @@ GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \
ar-lib \
compile \
config.guess \
config.rpath \
config.sub \
depcomp \
install-sh \
@ -120,6 +121,47 @@ GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \
lt~obsolete.m4 \
; do echo "$$MACRO_DIR/$$x"; done; \
fi`
#
# Modules that use gettext and use AC_CONFIG_MACRO_DIR() may also include this,
# though it's harmless to include regardless.
GITIGNORE_MAINTAINERCLEANFILES_M4_GETTEXT = \
`MACRO_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_MACRO_DIR:$$1' ./configure.ac); \
if test "x$$MACRO_DIR" != "x$(srcdir)/"; then \
for x in \
codeset.m4 \
extern-inline.m4 \
fcntl-o.m4 \
gettext.m4 \
glibc2.m4 \
glibc21.m4 \
iconv.m4 \
intdiv0.m4 \
intl.m4 \
intldir.m4 \
intlmacosx.m4 \
intmax.m4 \
inttypes-pri.m4 \
inttypes_h.m4 \
lcmessage.m4 \
lib-ld.m4 \
lib-link.m4 \
lib-prefix.m4 \
lock.m4 \
longlong.m4 \
nls.m4 \
po.m4 \
printf-posix.m4 \
progtest.m4 \
size_max.m4 \
stdint_h.m4 \
threadlib.m4 \
uintmax_t.m4 \
visibility.m4 \
wchar_t.m4 \
wint_t.m4 \
xsize.m4 \
; do echo "$$MACRO_DIR/$$x"; done; \
fi`
@ -208,6 +250,15 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
"*/*.omf.out" \
; do echo /$$x; done; \
fi; \
if test "x$(HOTDOC)" = x; then :; else \
$(foreach project, $(HOTDOC_PROJECTS),echo "/$(call HOTDOC_TARGET,$(project))"; \
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-conf-path output)" ; \
echo "/$(shell $(call HOTDOC_PROJECT_COMMAND,$(project)) --get-private-folder)" ; \
) \
for x in \
.hotdoc.d \
; do echo "/$$x"; done; \
fi; \
if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
for lc in $(HELP_LINGUAS); do \
for x in \
@ -235,6 +286,7 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
fi; \
if test -f $(srcdir)/po/Makefile.in.in; then \
for x in \
ABOUT-NLS \
po/Makefile.in.in \
po/Makefile.in.in~ \
po/Makefile.in \
@ -243,6 +295,7 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
po/POTFILES \
po/Rules-quot \
po/stamp-it \
po/stamp-po \
po/.intltool-merge-cache \
"po/*.gmo" \
"po/*.header" \
@ -274,7 +327,7 @@ $(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
if test "x$(am__dirstamp)" = x; then :; else \
echo "$(am__dirstamp)"; \
fi; \
if test "x$(LTCOMPILE)" = x -a "x$(LTCXXCOMPILE)" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
if test "x$(findstring libtool,$(LTCOMPILE))" = x -a "x$(findstring libtool,$(LTCXXCOMPILE))" = x -a "x$(GTKDOC_RUN)" = x; then :; else \
for x in \
"*.lo" \
".libs" "_libs" \

View File

@ -13,7 +13,7 @@
<!--download-page
rdf:resource=""/-->
<bug-database
rdf:resource="http://bugs.freedesktop.org/enter_bug.cgi?product=harfbuzz"/>
rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
<maintainer>
<foaf:Person>

982
m4/ax_cxx_compile_stdcxx.m4 Normal file
View File

@ -0,0 +1,982 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXX and
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
# or '14' (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 7
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AX_REQUIRE_DEFINED([AC_MSG_WARN])
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for alternative in ${ax_cxx_compile_alternatives}; do
switch="-std=gnu++${alternative}"
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for alternative in ${ax_cxx_compile_alternatives}; do
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXX="$CXX"
CXX="$CXX $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXX="$ac_save_CXX"])
if eval test x\$$cachevar = xyes; then
CXX="$CXX $switch"
if test -n "$CXXCPP" ; then
CXXCPP="$CXXCPP $switch"
fi
ac_success=yes
break
fi
done
if test x$ac_success = xyes; then
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
fi
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual void f() {}
};
struct Derived : public Base
{
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_separators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])
dnl Tests for new features in C++17
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
// If the compiler admits that it is not ready for C++17, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus <= 201402L
#error "This is not a C++17 compiler"
#else
#if defined(__clang__)
#define REALLY_CLANG
#else
#if defined(__GNUC__)
#define REALLY_GCC
#endif
#endif
#include <initializer_list>
#include <utility>
#include <type_traits>
namespace cxx17
{
#if !defined(REALLY_CLANG)
namespace test_constexpr_lambdas
{
// TODO: test it with clang++ from git
constexpr int foo = [](){return 42;}();
}
#endif // !defined(REALLY_CLANG)
namespace test::nested_namespace::definitions
{
}
namespace test_fold_expression
{
template<typename... Args>
int multiply(Args... args)
{
return (args * ... * 1);
}
template<typename... Args>
bool all(Args... args)
{
return (args && ...);
}
}
namespace test_extended_static_assert
{
static_assert (true);
}
namespace test_auto_brace_init_list
{
auto foo = {5};
auto bar {5};
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
static_assert(std::is_same<int, decltype(bar)>::value);
}
namespace test_typename_in_template_template_parameter
{
template<template<typename> typename X> struct D;
}
namespace test_fallthrough_nodiscard_maybe_unused_attributes
{
int f1()
{
return 42;
}
[[nodiscard]] int f2()
{
[[maybe_unused]] auto unused = f1();
switch (f1())
{
case 17:
f1();
[[fallthrough]];
case 42:
f1();
}
return f1();
}
}
namespace test_extended_aggregate_initialization
{
struct base1
{
int b1, b2 = 42;
};
struct base2
{
base2() {
b3 = 42;
}
int b3;
};
struct derived : base1, base2
{
int d;
};
derived d1 {{1, 2}, {}, 4}; // full initialization
derived d2 {{}, {}, 4}; // value-initialized bases
}
namespace test_general_range_based_for_loop
{
struct iter
{
int i;
int& operator* ()
{
return i;
}
const int& operator* () const
{
return i;
}
iter& operator++()
{
++i;
return *this;
}
};
struct sentinel
{
int i;
};
bool operator== (const iter& i, const sentinel& s)
{
return i.i == s.i;
}
bool operator!= (const iter& i, const sentinel& s)
{
return !(i == s);
}
struct range
{
iter begin() const
{
return {0};
}
sentinel end() const
{
return {5};
}
};
void f()
{
range r {};
for (auto i : r)
{
[[maybe_unused]] auto v = i;
}
}
}
namespace test_lambda_capture_asterisk_this_by_value
{
struct t
{
int i;
int foo()
{
return [*this]()
{
return i;
}();
}
};
}
namespace test_enum_class_construction
{
enum class byte : unsigned char
{};
byte foo {42};
}
namespace test_constexpr_if
{
template <bool cond>
int f ()
{
if constexpr(cond)
{
return 13;
}
else
{
return 42;
}
}
}
namespace test_selection_statement_with_initializer
{
int f()
{
return 13;
}
int f2()
{
if (auto i = f(); i > 0)
{
return 3;
}
switch (auto i = f(); i + 4)
{
case 17:
return 2;
default:
return 1;
}
}
}
#if !defined(REALLY_CLANG)
namespace test_template_argument_deduction_for_class_templates
{
// TODO: test it with clang++ from git
template <typename T1, typename T2>
struct pair
{
pair (T1 p1, T2 p2)
: m1 {p1},
m2 {p2}
{}
T1 m1;
T2 m2;
};
void f()
{
[[maybe_unused]] auto p = pair{13, 42u};
}
}
#endif // !defined(REALLY_CLANG)
namespace test_non_type_auto_template_parameters
{
template <auto n>
struct B
{};
B<5> b1;
B<'a'> b2;
}
#if !defined(REALLY_CLANG)
namespace test_structured_bindings
{
// TODO: test it with clang++ from git
int arr[2] = { 1, 2 };
std::pair<int, int> pr = { 1, 2 };
auto f1() -> int(&)[2]
{
return arr;
}
auto f2() -> std::pair<int, int>&
{
return pr;
}
struct S
{
int x1 : 2;
volatile double y1;
};
S f3()
{
return {};
}
auto [ x1, y1 ] = f1();
auto& [ xr1, yr1 ] = f1();
auto [ x2, y2 ] = f2();
auto& [ xr2, yr2 ] = f2();
const auto [ x3, y3 ] = f3();
}
#endif // !defined(REALLY_CLANG)
#if !defined(REALLY_CLANG)
namespace test_exception_spec_type_system
{
// TODO: test it with clang++ from git
struct Good {};
struct Bad {};
void g1() noexcept;
void g2();
template<typename T>
Bad
f(T*, T*);
template<typename T1, typename T2>
Good
f(T1*, T2*);
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
}
#endif // !defined(REALLY_CLANG)
namespace test_inline_variables
{
template<class T> void f(T)
{}
template<class T> inline T g(T)
{
return T{};
}
template<> inline void f<>(int)
{}
template<> int g<>(int)
{
return 5;
}
}
} // namespace cxx17
#endif // __cplusplus <= 201402L
]])

View File

@ -1,5 +1,5 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
@ -19,10 +19,10 @@
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# but also to link with them as well. For example, you might link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# If you are only building threaded programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
@ -30,8 +30,8 @@
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
@ -67,7 +67,7 @@
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
@ -82,35 +82,40 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 18
#serial 24
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([AC_PROG_SED])
AC_LANG_PUSH([C])
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# requires special compiler flags (e.g. on Tru64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
ax_pthread_save_CC="$CC"
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
AC_MSG_RESULT([$ax_pthread_ok])
if test "x$ax_pthread_ok" = "xno"; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
CC="$ax_pthread_save_CC"
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
fi
# We must check for the threads library under a number of different
@ -123,7 +128,7 @@ fi
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
@ -132,68 +137,225 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
# (Note: HP C rejects this with "bad form for `-t' option")
# -pthreads: Solaris/gcc (Note: HP C also rejects)
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# doesn't hurt to check since this sometimes defines pthreads and
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
# is present but should not be used directly; and before -mthreads,
# because the compiler interprets this as "-mt" + "-hreads")
# -mthreads: Mingw32/gcc, Lynx/gcc
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case ${host_os} in
case $host_os in
freebsd*)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
;;
hpux*)
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
# multi-threading and also sets -lpthread."
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
;;
openedition*)
# IBM z/OS requires a feature-test macro to be defined in order to
# enable POSIX threads at all, so give the user a hint if this is
# not set. (We don't define these ourselves, as they can affect
# other portions of the system API in unpredictable ways.)
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
[
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
AX_PTHREAD_ZOS_MISSING
# endif
],
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
;;
solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
# tests will erroneously succeed. (N.B.: The stubs are missing
# pthread_cleanup_push, or rather a function called by this macro,
# so we could check for that, but who knows whether they'll stub
# that too in a future libc.) So we'll check first for the
# standard Solaris way of linking pthreads (-mt -lpthread).
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
darwin*)
ax_pthread_flags="-pthread $ax_pthread_flags"
ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
;;
esac
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
case $flag in
AS_IF([test "x$GCC" = "xyes"],
[ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
# The presence of a feature test macro requesting re-entrant function
# definitions is, on some systems, a strong hint that pthreads support is
# correctly enabled
case $host_os in
darwin* | hpux* | linux* | osf* | solaris*)
ax_pthread_check_macro="_REENTRANT"
;;
aix*)
ax_pthread_check_macro="_THREAD_SAFE"
;;
*)
ax_pthread_check_macro="--"
;;
esac
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
[ax_pthread_check_cond=0],
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
# Are we compiling with Clang?
AC_CACHE_CHECK([whether $CC is Clang],
[ax_cv_PTHREAD_CLANG],
[ax_cv_PTHREAD_CLANG=no
# Note that Autoconf sets GCC=yes for Clang as well as GCC
if test "x$GCC" = "xyes"; then
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
# if defined(__clang__) && defined(__llvm__)
AX_PTHREAD_CC_IS_CLANG
# endif
],
[ax_cv_PTHREAD_CLANG=yes])
fi
])
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
ax_pthread_clang_warning=no
# Clang needs special handling, because older versions handle the -pthread
# option in a rather... idiosyncratic way
if test "x$ax_pthread_clang" = "xyes"; then
# Clang takes -pthread; it has never supported any other flag
# (Note 1: This will need to be revisited if a system that Clang
# supports has POSIX threads in a separate library. This tends not
# to be the way of modern systems, but it's conceivable.)
# (Note 2: On some systems, notably Darwin, -pthread is not needed
# to get POSIX threads support; the API is always present and
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
# -pthread does define _REENTRANT, and while the Darwin headers
# ignore this macro, third-party headers might not.)
PTHREAD_CFLAGS="-pthread"
PTHREAD_LIBS=
ax_pthread_ok=yes
# However, older versions of Clang make a point of warning the user
# that, in an invocation where only linking and no compilation is
# taking place, the -pthread option has no effect ("argument unused
# during compilation"). They expect -pthread to be passed in only
# when source code is being compiled.
#
# Problem is, this is at odds with the way Automake and most other
# C build frameworks function, which is that the same flags used in
# compilation (CFLAGS) are also used in linking. Many systems
# supported by AX_PTHREAD require exactly this for POSIX threads
# support, and in fact it is often not straightforward to specify a
# flag that is used only in the compilation phase and not in
# linking. Such a scenario is extremely rare in practice.
#
# Even though use of the -pthread flag in linking would only print
# a warning, this can be a nuisance for well-run software projects
# that build with -Werror. So if the active version of Clang has
# this misfeature, we search for an option to squash it.
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
# Create an alternate version of $ac_link that compiles and
# links in two steps (.c -> .o, .o -> exe) instead of one
# (.c -> exe), because the warning occurs only in the second
# step
ax_pthread_save_ac_link="$ac_link"
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
ax_pthread_save_CFLAGS="$CFLAGS"
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
ac_link="$ax_pthread_save_ac_link"
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
[ac_link="$ax_pthread_2step_ac_link"
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
[break])
])
done
ac_link="$ax_pthread_save_ac_link"
CFLAGS="$ax_pthread_save_CFLAGS"
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
])
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
no | unknown) ;;
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
esac
fi # $ax_pthread_clang = yes
if test "x$ax_pthread_ok" = "xno"; then
for ax_pthread_try_flag in $ax_pthread_flags; do
case $ax_pthread_try_flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-mt,pthread)
AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
PTHREAD_CFLAGS="-mt"
PTHREAD_LIBS="-lpthread"
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
PTHREAD_CFLAGS="$ax_pthread_try_flag"
;;
pthread-config)
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
PTHREAD_LIBS="-l$ax_pthread_try_flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
@ -204,7 +366,11 @@ for flag in $ax_pthread_flags; do
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
# if $ax_pthread_check_cond
# error "$ax_pthread_check_macro must be defined"
# endif
static void routine(void *a) { a = 0; }
static void *start_routine(void *a) { return a; }],
[pthread_t th; pthread_attr_t attr;
@ -213,16 +379,14 @@ for flag in $ax_pthread_flags; do
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_cleanup_pop(0) /* ; */])],
[ax_pthread_ok=yes],
[])
[ax_pthread_ok=yes],
[])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
AC_MSG_RESULT([$ax_pthread_ok])
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
@ -230,76 +394,88 @@ done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
if test "x$ax_pthread_ok" = "xyes"; then
ax_pthread_save_CFLAGS="$CFLAGS"
ax_pthread_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $attr; return attr /* ; */])],
[attr_name=$attr; break],
[])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_CACHE_CHECK([for joinable pthread attribute],
[ax_cv_PTHREAD_JOINABLE_ATTR],
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
[int attr = $ax_pthread_attr; return attr /* ; */])],
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
[])
done
])
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
[$ax_cv_PTHREAD_JOINABLE_ATTR],
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
ax_pthread_joinable_attr_defined=yes
])
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case ${host_os} in
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
osf* | hpux*) flag="-D_REENTRANT";;
solaris*)
if test "$GCC" = "yes"; then
flag="-D_REENTRANT"
else
flag="-mt -D_REENTRANT"
fi
;;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
AC_CACHE_CHECK([whether more special flags are required for pthreads],
[ax_cv_PTHREAD_SPECIAL_FLAGS],
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
case $host_os in
solaris*)
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
;;
esac
])
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
test "x$ax_pthread_special_flags_added" != "xyes"],
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
ax_pthread_special_flags_added=yes])
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
ax_cv_PTHREAD_PRIO_INHERIT, [
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
[ax_cv_PTHREAD_PRIO_INHERIT],
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
[[int i = PTHREAD_PRIO_INHERIT;]])],
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
[ax_cv_PTHREAD_PRIO_INHERIT=no])
])
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
ax_pthread_prio_inherit_defined=yes
])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
CFLAGS="$ax_pthread_save_CFLAGS"
LIBS="$ax_pthread_save_LIBS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
# More AIX lossage: compile with *_r variant
if test "x$GCC" != "xyes"; then
case $host_os in
aix*)
AS_CASE(["x/$CC"],
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
[#handle absolute path differently from PATH based program lookup
AS_CASE(["x$CC"],
[x/*],
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
;;
esac
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
AC_SUBST([PTHREAD_LIBS])
AC_SUBST([PTHREAD_CFLAGS])
AC_SUBST([PTHREAD_CC])
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
if test "x$ax_pthread_ok" = "xyes"; then
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
:
else
ax_pthread_ok=no

22
mingw32.sh Executable file
View File

@ -0,0 +1,22 @@
#!/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 "$@"

22
mingw64.sh Executable file
View File

@ -0,0 +1,22 @@
#!/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 "$@"

View File

@ -0,0 +1,21 @@
# CMake script to replace items
# in sources generated by glib-mkenums
FILE(READ ${ENUM_INPUT_SRC} enum_in)
STRING(REPLACE
"_t_get_type"
"_get_type"
enum_out_tmp
"${enum_in}"
)
STRING(REPLACE
"_T ("
" ("
enum_out
"${enum_out_tmp}"
)
FILE(WRITE ${ENUM_OUTPUT_SRC} "${enum_out}")
FILE(REMOVE ${ENUM_INPUT_SRC})

View File

@ -1,5 +1,6 @@
# Process this file with automake to produce Makefile.in
NULL =
SUBDIRS =
DIST_SUBDIRS =
BUILT_SOURCES =
@ -8,12 +9,14 @@ CLEANFILES =
DISTCLEANFILES =
MAINTAINERCLEANFILES =
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS =
check_PROGRAMS =
# The following warning options are useful for debugging: -Wpadded
#AM_CXXFLAGS =
# Convenience targets:
lib: $(BUILT_SOURCES) libharfbuzz.la
lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la
lib_LTLIBRARIES = libharfbuzz.la
@ -25,11 +28,21 @@ HBLIBS =
HBNONPCLIBS =
HBDEPS =
HBSOURCES = $(HB_BASE_sources)
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
HBHEADERS = $(HB_BASE_headers)
HBNODISTHEADERS = $(HB_NODIST_headers)
if WITH_LIBSTDCXX
HBNOLIBCXXCFLAGS =
else
# Make sure we don't link to libstdc++
# No threadsafe statics in C++ as we do it ourselves
HBCFLAGS += -fno-exceptions
HBNOLIBCXXFLAGS = -fno-threadsafe-statics -fno-rtti
endif
if HAVE_OT
HBSOURCES += $(HB_OT_sources)
HBSOURCES += $(HB_OT_RAGEL_GENERATED_sources)
HBHEADERS += $(HB_OT_headers)
endif
@ -97,6 +110,9 @@ 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
@ -108,40 +124,69 @@ HBLIBS += $(HBNONPCLIBS)
if OS_WIN32
export_symbols = -export-symbols harfbuzz.def
harfbuzz_def_dependency = harfbuzz.def
libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
export_symbols_subset = -export-symbols harfbuzz-subset.def
harfbuzz_subset_def_dependency = harfbuzz-subset.def
export_symbols_icu = -export-symbols harfbuzz-icu.def
harfbuzz_icu_def_dependency = harfbuzz-icu.def
export_symbols_gobject = -export-symbols harfbuzz-gobject.def
harfbuzz_gobject_def_dependency = harfbuzz-gobject.def
chosen_linker = $(CXXLINK)
else
if WITH_LIBSTDCXX
chosen_linker = $(CXXLINK)
else
# Use a C linker for GCC, not C++; Don't link to libstdc++
if HAVE_GCC
libharfbuzz_la_LINK = $(LINK) $(libharfbuzz_la_LDFLAGS)
# Use a C linker for GCC, not C++; Don't link to libstdc++
chosen_linker = $(LINK)
else
libharfbuzz_la_LINK = $(CXXLINK) $(libharfbuzz_la_LDFLAGS)
chosen_linker = $(CXXLINK)
endif
endif
endif
libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS) $(HBNODISTHEADERS)
libharfbuzz_la_CPPFLAGS = $(HBCFLAGS)
libharfbuzz_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) $(export_symbols) -no-undefined
base_link_flags = $(AM_LDFLAGS) -lm -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
libharfbuzz_la_LINK = $(chosen_linker) $(libharfbuzz_la_LDFLAGS)
libharfbuzz_la_SOURCES = $(HBSOURCES) $(HBHEADERS)
libharfbuzz_la_CPPFLAGS = $(HBCFLAGS) $(HBNOLIBCXXFLAGS)
libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols)
libharfbuzz_la_LIBADD = $(HBLIBS)
EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
pkginclude_HEADERS = $(HBHEADERS)
nodist_pkginclude_HEADERS = $(HBNODISTHEADERS)
nodist_pkginclude_HEADERS =
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
EXTRA_DIST += harfbuzz.pc.in
cmakedir = $(libdir)/cmake/harfbuzz
cmake_DATA = harfbuzz-config.cmake
EXTRA_DIST += harfbuzz.pc.in harfbuzz-config.cmake.in
FUZZING_CPPFLAGS= \
lib_LTLIBRARIES += libharfbuzz-subset.la
libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources)
libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS)
libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset)
libharfbuzz_subset_la_LIBADD = libharfbuzz.la
EXTRA_libharfbuzz_subset_la_DEPENDENCIES = $(harfbuzz_subset_def_dependency)
pkginclude_HEADERS += $(HB_SUBSET_headers)
pkgconfig_DATA += harfbuzz-subset.pc
EXTRA_DIST += harfbuzz-subset.pc.in
FUZZING_CPPFLAGS = \
-DHB_NDEBUG \
-DHB_MAX_NESTING_LEVEL=3 \
-DHB_SANITIZE_MAX_EDITS=3 \
-DHB_BUFFER_MAX_EXPANSION_FACTOR=3 \
-DHB_SANITIZE_MAX_OPS_FACTOR=3 \
-DHB_SANITIZE_MAX_OPS_MIN=128 \
-DHB_BUFFER_MAX_LEN_FACTOR=3 \
-DHB_BUFFER_MAX_LEN_MIN=8 \
-DHB_BUFFER_MAX_LEN_DEFAULT=128 \
-DHB_BUFFER_MAX_OPS_FACTOR=8 \
-DHB_BUFFER_MAX_OPS_MIN=64 \
-DHB_BUFFER_MAX_OPS_DEFAULT=1024 \
$(NULL)
EXTRA_LTLIBRARIES = libharfbuzz-fuzzing.la
libharfbuzz_fuzzing_la_LINK = $(libharfbuzz_la_LINK)
libharfbuzz_fuzzing_la_LINK = $(chosen_linker) $(libharfbuzz_fuzzing_la_LDFLAGS)
libharfbuzz_fuzzing_la_SOURCES = $(libharfbuzz_la_SOURCES)
libharfbuzz_fuzzing_la_CPPFLAGS = $(libharfbuzz_la_CPPFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_fuzzing_la_LDFLAGS = $(libharfbuzz_la_LDFLAGS)
libharfbuzz_fuzzing_la_CPPFLAGS = $(HBCFLAGS) $(FUZZING_CPPFLAGS)
libharfbuzz_fuzzing_la_LDFLAGS = $(AM_LDFLAGS)
libharfbuzz_fuzzing_la_LIBADD = $(libharfbuzz_la_LIBADD)
EXTRA_libharfbuzz_fuzzing_la_DEPENDENCIES = $(EXTRA_libharfbuzz_la_DEPENDENCIES)
CLEANFILES += libharfbuzz-fuzzing.la
@ -155,9 +200,10 @@ HBHEADERS += $(HB_ICU_headers)
else
lib_LTLIBRARIES += libharfbuzz-icu.la
libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
libharfbuzz_icu_la_CPPFLAGS = $(ICU_CFLAGS)
libharfbuzz_icu_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS)
libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu)
libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la
EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency)
pkginclude_HEADERS += $(HB_ICU_headers)
pkgconfig_DATA += harfbuzz-icu.pc
endif
@ -166,13 +212,15 @@ EXTRA_DIST += harfbuzz-icu.pc.in
if HAVE_GOBJECT
lib_LTLIBRARIES += libharfbuzz-gobject.la
libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_sources)
nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_ENUM_sources)
libharfbuzz_gobject_la_CPPFLAGS = $(GOBJECT_CFLAGS)
libharfbuzz_gobject_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(HB_LIBTOOL_VERSION_INFO) -no-undefined
libharfbuzz_gobject_la_LINK = $(chosen_linker) $(libharfbuzz_gobject_la_LDFLAGS)
libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_DIST_sources)
nodist_libharfbuzz_gobject_la_SOURCES = $(HB_GOBJECT_NODIST_sources)
libharfbuzz_gobject_la_CPPFLAGS = $(HBCFLAGS) $(HBNOLIBCXXFLAGS) $(GOBJECT_CFLAGS)
libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags)
libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
pkginclude_HEADERS += $(HB_GOBJECT_headers)
nodist_pkginclude_HEADERS += $(HB_GOBJECT_ENUM_headers)
EXTRA_libharfbuzz_gobject_la_DEPENDENCIES = $(harfbuzz_gobject_def_dependency)
pkginclude_HEADERS += $(HB_GOBJECT_DIST_headers)
nodist_pkginclude_HEADERS += $(HB_GOBJECT_NODIST_headers)
pkgconfig_DATA += harfbuzz-gobject.pc
BUILT_SOURCES += \
@ -212,23 +260,27 @@ EXTRA_DIST += \
CLEANFILES += $(pkgconfig_DATA)
CLEANFILES += harfbuzz.def
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def
if HAVE_GOBJECT
DEF_FILES += harfbuzz-gobject.def
endif
check: $(DEF_FILES) # For check-symbols.sh
CLEANFILES += $(DEF_FILES)
harfbuzz.def: $(HBHEADERS) $(HBNODISTHEADERS)
$(AM_V_GEN) (echo EXPORTS; \
(cat $^ || echo 'hb_ERROR ()' ) | \
$(EGREP) '^hb_.* \(' | \
sed -e 's/ (.*//' | \
LANG=C sort; \
echo LIBRARY libharfbuzz-0.dll; \
) >"$@"
@ ! grep -q hb_ERROR "$@" \
|| ($(RM) "$@"; false)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
harfbuzz-subset.def: $(HB_SUBSET_headers)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
harfbuzz-icu.def: $(HB_ICU_headers)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
harfbuzz-gobject.def: $(HB_GOBJECT_headers)
$(AM_V_GEN) headers="$^" $(srcdir)/gen-def.py $@
GENERATORS = \
gen-arabic-table.py \
gen-indic-table.py \
gen-use-table.py \
gen-def.py \
$(NULL)
EXTRA_DIST += $(GENERATORS)
@ -251,21 +303,16 @@ built-sources: $(BUILT_SOURCES)
.PHONY: unicode-tables arabic-table indic-table use-table built-sources
RAGEL_GENERATED = \
$(srcdir)/hb-buffer-deserialize-json.hh \
$(srcdir)/hb-buffer-deserialize-text.hh \
$(srcdir)/hb-ot-shape-complex-indic-machine.hh \
$(srcdir)/hb-ot-shape-complex-myanmar-machine.hh \
$(srcdir)/hb-ot-shape-complex-use-machine.hh \
$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
$(patsubst %,$(srcdir)/%,$(HB_OT_RAGEL_GENERATED_sources)) \
$(NULL)
BUILT_SOURCES += $(RAGEL_GENERATED)
EXTRA_DIST += \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text.rl \
hb-ot-shape-complex-indic-machine.rl \
hb-ot-shape-complex-myanmar-machine.rl \
hb-ot-shape-complex-use-machine.rl \
$(HB_BASE_RAGEL_sources) \
$(HB_OT_RAGEL_sources) \
$(NULL)
MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
# We decided to add ragel-generated files to git...
#MAINTAINERCLEANFILES += $(RAGEL_GENERATED)
$(srcdir)/%.hh: $(srcdir)/%.rl
$(AM_V_GEN)(cd $(srcdir) && $(RAGEL) -e -F1 -o "$*.hh" "$*.rl") \
|| ($(RM) "$@"; false)
@ -301,30 +348,55 @@ test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
dist_check_SCRIPTS = \
check-c-linkage-decls.sh \
check-defs.sh \
check-externs.sh \
check-header-guards.sh \
check-includes.sh \
check-libstdc++.sh \
check-static-inits.sh \
check-symbols.sh \
$(NULL)
TESTS += $(dist_check_SCRIPTS)
check_PROGRAMS = \
test-ot-tag \
if !WITH_LIBSTDCXX
dist_check_SCRIPTS += \
check-libstdc++.sh \
$(NULL)
test_ot_color_SOURCES = hb-ot-color.cc
test_ot_color_CPPFLAGS = $(HBCFLAGS) -DMAIN
test_ot_color_LDADD = libharfbuzz.la $(HBLIBS)
endif
check_PROGRAMS += \
dump-indic-data \
dump-khmer-data \
dump-myanmar-data \
dump-use-data \
$(NULL)
dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
dump_indic_data_CPPFLAGS = $(HBCFLAGS)
dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)
dump_khmer_data_SOURCES = dump-khmer-data.cc hb-ot-shape-complex-indic-table.cc
dump_khmer_data_CPPFLAGS = $(HBCFLAGS)
dump_khmer_data_LDADD = libharfbuzz.la $(HBLIBS)
dump_myanmar_data_SOURCES = dump-myanmar-data.cc hb-ot-shape-complex-indic-table.cc
dump_myanmar_data_CPPFLAGS = $(HBCFLAGS)
dump_myanmar_data_LDADD = libharfbuzz.la $(HBLIBS)
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)
check_PROGRAMS += test-ot-tag test-unicode-ranges
TESTS += test-ot-tag test-unicode-ranges
test_ot_tag_SOURCES = hb-ot-tag.cc
test_ot_tag_CPPFLAGS = $(HBCFLAGS) -DMAIN
test_ot_tag_LDADD = libharfbuzz.la $(HBLIBS)
TESTS = $(dist_check_SCRIPTS) $(check_PROGRAMS)
test_unicode_ranges_SOURCES = test-unicode-ranges.cc
test_unicode_ranges_LDADD = libharfbuzz.la $(HBLIBS)
TESTS_ENVIRONMENT = \
srcdir="$(srcdir)" \
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
HBSOURCES="$(HBSOURCES)" \
HBHEADERS="$(HBHEADERS) $(HBNODISTHEADERS)" \
HBHEADERS="$(HBHEADERS)" \
$(NULL)
if HAVE_INTROSPECTION
@ -354,12 +426,9 @@ HarfBuzz_0_0_gir_LIBS = \
$(NULL)
HarfBuzz_0_0_gir_FILES = \
$(HBHEADERS) \
$(HBNODISTHEADERS) \
$(HBSOURCES) \
$(HB_GOBJECT_ENUM_sources) \
$(HB_GOBJECT_ENUM_headers) \
$(HB_GOBJECT_sources) \
$(HB_GOBJECT_STRUCTS_headers) \
$(HB_GOBJECT_headers) \
$(NULL)
girdir = $(datadir)/gir-1.0

View File

@ -1,17 +1,14 @@
NULL =
# Base and default-included sources and headers
HB_BASE_sources = \
hb-atomic-private.hh \
hb-blob.cc \
hb-buffer-deserialize-json.hh \
hb-buffer-deserialize-text.hh \
hb-buffer-private.hh \
hb-buffer-serialize.cc \
hb-buffer.cc \
hb-cache-private.hh \
hb-common.cc \
hb-debug.hh \
hb-dsalgs.hh \
hb-face-private.hh \
hb-face.cc \
hb-font-private.hh \
@ -20,17 +17,23 @@ HB_BASE_sources = \
hb-object-private.hh \
hb-open-file-private.hh \
hb-open-type-private.hh \
hb-ot-cbdt-table.hh \
hb-ot-cmap-table.hh \
hb-ot-glyf-table.hh \
hb-ot-hdmx-table.hh \
hb-ot-head-table.hh \
hb-ot-hhea-table.hh \
hb-ot-hmtx-table.hh \
hb-ot-kern-table.hh \
hb-ot-maxp-table.hh \
hb-ot-name-table.hh \
hb-ot-os2-table.hh \
hb-ot-os2-unicode-ranges.hh \
hb-ot-post-macroman.hh \
hb-ot-post-table.hh \
hb-ot-tag.cc \
hb-private.hh \
hb-set-digest-private.hh \
hb-set-private.hh \
hb-set.cc \
hb-shape.cc \
@ -40,12 +43,22 @@ HB_BASE_sources = \
hb-shaper-impl-private.hh \
hb-shaper-private.hh \
hb-shaper.cc \
hb-string-array.hh \
hb-unicode-private.hh \
hb-unicode.cc \
hb-utf-private.hh \
hb-warning.cc \
$(NULL)
HB_BASE_RAGEL_GENERATED_sources = \
hb-buffer-deserialize-json.hh \
hb-buffer-deserialize-text.hh \
$(NULL)
HB_BASE_RAGEL_sources = \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text.rl \
$(NULL)
HB_BASE_headers = \
hb.h \
hb-blob.h \
@ -58,19 +71,24 @@ HB_BASE_headers = \
hb-shape.h \
hb-shape-plan.h \
hb-unicode.h \
$(NULL)
HB_NODIST_headers = \
hb-version.h \
$(NULL)
HB_FALLBACK_sources = hb-fallback-shape.cc
HB_FALLBACK_sources = \
hb-fallback-shape.cc \
$(NULL)
HB_OT_sources = \
hb-ot-color.cc \
hb-ot-cpal-table.hh \
hb-aat-layout.cc \
hb-aat-layout-common-private.hh \
hb-aat-layout-ankr-table.hh \
hb-aat-layout-kerx-table.hh \
hb-aat-layout-morx-table.hh \
hb-aat-layout-trak-table.hh \
hb-aat-layout-private.hh \
hb-ot-font.cc \
hb-ot-layout.cc \
hb-ot-layout-base-table.hh \
hb-ot-layout-common-private.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
@ -78,8 +96,12 @@ HB_OT_sources = \
hb-ot-layout-gsub-table.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout-private.hh \
hb-ot-color.cc \
hb-ot-cpal-table.hh \
hb-ot-map.cc \
hb-ot-map-private.hh \
hb-ot-math.cc \
hb-ot-math-table.hh \
hb-ot-shape.cc \
hb-ot-shape-complex-arabic.cc \
hb-ot-shape-complex-arabic-fallback.hh \
@ -90,15 +112,15 @@ HB_OT_sources = \
hb-ot-shape-complex-hangul.cc \
hb-ot-shape-complex-hebrew.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-indic-private.hh \
hb-ot-shape-complex-indic-table.cc \
hb-ot-shape-complex-khmer-private.hh \
hb-ot-shape-complex-khmer.cc \
hb-ot-shape-complex-myanmar-private.hh \
hb-ot-shape-complex-myanmar.cc \
hb-ot-shape-complex-myanmar-machine.hh \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-complex-tibetan.cc \
hb-ot-shape-complex-use.cc \
hb-ot-shape-complex-use-machine.hh \
hb-ot-shape-complex-use-private.hh \
hb-ot-shape-complex-use-table.cc \
hb-ot-shape-complex-private.hh \
@ -107,6 +129,24 @@ HB_OT_sources = \
hb-ot-shape-fallback-private.hh \
hb-ot-shape-fallback.cc \
hb-ot-shape-private.hh \
hb-ot-var.cc \
hb-ot-var-avar-table.hh \
hb-ot-var-fvar-table.hh \
hb-ot-var-hvar-table.hh \
hb-ot-var-mvar-table.hh \
$(NULL)
HB_OT_RAGEL_GENERATED_sources = \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-khmer-machine.hh \
hb-ot-shape-complex-myanmar-machine.hh \
hb-ot-shape-complex-use-machine.hh \
$(NULL)
HB_OT_RAGEL_sources = \
hb-ot-shape-complex-indic-machine.rl \
hb-ot-shape-complex-khmer-machine.rl \
hb-ot-shape-complex-myanmar-machine.rl \
hb-ot-shape-complex-use-machine.rl \
$(NULL)
HB_OT_headers = \
@ -114,8 +154,11 @@ HB_OT_headers = \
hb-ot-color.h \
hb-ot-font.h \
hb-ot-layout.h \
hb-ot-math.h \
hb-ot-base.h \
hb-ot-shape.h \
hb-ot-tag.h \
hb-ot-var.h \
$(NULL)
# Optional Sources and Headers with external deps
@ -147,8 +190,26 @@ HB_UCDN_sources = hb-ucdn.cc
HB_ICU_sources = hb-icu.cc
HB_ICU_headers = hb-icu.h
HB_GOBJECT_sources = hb-gobject-structs.cc
HB_GOBJECT_STRUCTS_headers = hb-gobject-structs.h
HB_GOBJECT_headers = hb-gobject.h $(HB_GOBJECT_STRUCTS_headers)
# Sources for libharfbuzz-subset
HB_SUBSET_sources = \
hb-subset.cc \
hb-subset-glyf.cc \
hb-subset-input.cc \
hb-subset-plan.cc \
$(NULL)
HB_SUBSET_headers = \
hb-subset.h \
hb-subset-glyf.hh \
hb-subset-plan.hh \
hb-subset-private.hh \
$(NULL)
HB_GOBJECT_DIST_sources = hb-gobject-structs.cc
HB_GOBJECT_DIST_headers = hb-gobject.h hb-gobject-structs.h
HB_GOBJECT_ENUM_sources = hb-gobject-enums.cc
HB_GOBJECT_ENUM_headers = hb-gobject-enums.h
HB_GOBJECT_NODIST_sources = $(HB_GOBJECT_ENUM_sources)
HB_GOBJECT_NODIST_headers = $(HB_GOBJECT_ENUM_headers)
HB_GOBJECT_sources = $(HB_GOBJECT_DIST_sources) $(HB_GOBJECT_NODIST_sources)
HB_GOBJECT_headers = $(HB_GOBJECT_DIST_headers) $(HB_GOBJECT_NODIST_headers)

View File

@ -7,18 +7,17 @@ test -z "$srcdir" && srcdir=.
stat=0
test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.cc'`
for x in $HBHEADERS; do
test -f $srcdir/$x && x=$srcdir/$x
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
if ! grep -q HB_BEGIN_DECLS "$x" || ! grep -q HB_END_DECLS "$x"; then
echo "Ouch, file $x does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should"
stat=1
fi
done
for x in $HBSOURCES; do
test -f $srcdir/$x && x=$srcdir/$x
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
if grep -q HB_BEGIN_DECLS "$x" || grep -q HB_END_DECLS "$x"; then
echo "Ouch, file $x has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn't"
stat=1

View File

@ -1,44 +0,0 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
test -z "$MAKE" && MAKE=make
stat=0
if which nm 2>/dev/null >/dev/null; then
:
else
echo "check-defs.sh: 'nm' not found; skipping test"
exit 77
fi
defs="harfbuzz.def"
$MAKE $defs > /dev/null
tested=false
for def in $defs; do
lib=`echo "$def" | sed 's/[.]def$//;s@.*/@@'`
so=.libs/lib${lib}.so
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
if test -f "$so"; then
echo "Checking that $so has the same symbol list as $def"
{
echo EXPORTS
echo "$EXPORTED_SYMBOLS"
# cheat: copy the last line from the def file!
tail -n1 "$def"
} | diff "$def" - >&2 || stat=1
tested=true
fi
done
if ! $tested; then
echo "check-defs.sh: libharfbuzz shared library not found; skipping test"
exit 77
fi
exit $stat

22
src/check-externs.sh Executable file
View File

@ -0,0 +1,22 @@
#!/bin/sh
LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
test "x$EGREP" = x && EGREP='grep -E'
echo 'Checking that all public symbols are exported with HB_EXTERN'
for x in $HBHEADERS; do
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
$EGREP -B1 -n '^hb_' /dev/null "$x" |
$EGREP -v '(^--|:hb_|-HB_EXTERN )' -A1
done |
grep . >&2 && stat=1
exit $stat

View File

@ -6,11 +6,11 @@ export LC_ALL
test -z "$srcdir" && srcdir=.
stat=0
test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h'`
test "x$HBHEADERS" = x && HBHEADERS=`cd "$srcdir"; find . -maxdepth 1 -name 'hb*.h' ! -name 'hb-gobject-structs.h'`
test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-*.cc' -or -name 'hb-*.hh'`
for x in $HBHEADERS $HBSOURCES; do
test -f "$srcdir/$x" && x="$srcdir/$x"
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
echo "$x" | grep -q '[^h]$' && continue;
xx=`echo "$x" | sed 's@.*/@@'`
tag=`echo "$xx" | tr 'a-z.-' 'A-Z_'`

View File

@ -13,7 +13,7 @@ test "x$HBSOURCES" = x && HBSOURCES=`cd "$srcdir"; find . -maxdepth 1 -name 'hb-
echo 'Checking that public header files #include "hb-common.h" or "hb.h" first (or none)'
for x in $HBHEADERS; do
test -f "$srcdir/$x" && x="$srcdir/$x"
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
grep '#.*\<include\>' "$x" /dev/null | head -n 1
done |
grep -v '"hb-common[.]h"' |
@ -26,7 +26,7 @@ grep . >&2 && stat=1
echo 'Checking that source files #include "hb-*private.hh" first (or none)'
for x in $HBSOURCES; do
test -f "$srcdir/$x" && x="$srcdir/$x"
test -f "$srcdir/$x" -a ! -f "$x" && x="$srcdir/$x"
grep '#.*\<include\>' "$x" /dev/null | grep -v 'include _' | head -n 1
done |
grep -v '"hb-.*private[.]hh"' |
@ -34,7 +34,7 @@ grep -v 'hb-private[.]hh:' |
grep . >&2 && stat=1
echo 'Checking that there is no #include <hb.*.h>'
echo 'Checking that there is no #include <hb-*.h>'
for x in $HBHEADERS $HBSOURCES; do
test -f "$srcdir/$x" && x="$srcdir/$x"
grep '#.*\<include\>.*<.*hb' "$x" /dev/null >&2 && stat=1

View File

@ -4,27 +4,37 @@ LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
test -z "$libs" && libs=.libs
stat=0
if which ldd 2>/dev/null >/dev/null; then
:
LDD=ldd
else
echo "check-libstdc++.sh: 'ldd' not found; skipping test"
exit 77
# macOS specific tool
if which otool 2>/dev/null >/dev/null; then
LDD="otool -L"
else
echo "check-libstdc++.sh: 'ldd' not found; skipping test"
exit 77
fi
fi
tested=false
for suffix in so dylib; do
so=.libs/libharfbuzz.$suffix
if ! test -f "$so"; then continue; fi
# harfbuzz-icu links to libstdc++ because icu does.
# harfbuzz-subset uses libstdc++.
for soname in harfbuzz harfbuzz-gobject; do
for suffix in so dylib; do
so=$libs/lib$soname.$suffix
if ! test -f "$so"; then continue; fi
echo "Checking that we are not linking to libstdc++ or libc++"
if ldd $so | grep 'libstdc[+][+]\|libc[+][+]'; then
echo "Ouch, linked to libstdc++ or libc++"
stat=1
fi
tested=true
echo "Checking that we are not linking to libstdc++ or libc++ in $so"
if $LDD $so | grep 'libstdc[+][+]\|libc[+][+]'; then
echo "Ouch, linked to libstdc++ or libc++"
stat=1
fi
tested=true
done
done
if ! $tested; then
echo "check-libstdc++.sh: libharfbuzz shared library not found; skipping test"

View File

@ -4,6 +4,7 @@ LC_ALL=C
export LC_ALL
test -z "$srcdir" && srcdir=.
test -z "$libs" && libs=.libs
stat=0
@ -14,7 +15,7 @@ else
exit 77
fi
OBJS=.libs/*.o
OBJS=$libs/*.o
if test "x`echo $OBJS`" = "x$OBJS" 2>/dev/null >/dev/null; then
echo "check-static-inits.sh: object files not found; skipping test"
exit 77

View File

@ -4,8 +4,10 @@ LC_ALL=C
export LC_ALL
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_.*'
if which nm 2>/dev/null >/dev/null; then
:
@ -14,29 +16,46 @@ else
exit 77
fi
echo "Checking that we are not exposing internal symbols"
tested=false
for suffix in so dylib; do
so=.libs/libharfbuzz.$suffix
if ! test -f "$so"; then continue; fi
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] ' | grep -v ' _fini\>\| _init\>\| _fdata\>\| _ftext\>\| _fbss\>\| __bss_start\>\| __bss_start__\>\| __bss_end__\>\| _edata\>\| _end\>\| _bss_end__\>\| __end__\>\| __gcov_flush\>\| llvm_' | cut -d' ' -f3`"
for soname in harfbuzz harfbuzz-subset harfbuzz-icu harfbuzz-gobject; do
for suffix in so dylib; do
so=$libs/lib$soname.$suffix
if ! test -f "$so"; then continue; fi
prefix=`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
# On macOS, C symbols are prefixed with _
symprefix=
if test $suffix = dylib; then symprefix=_; fi
# On mac, C symbols are prefixed with _
if test $suffix = dylib; then prefix="_$prefix"; fi
EXPORTED_SYMBOLS="`nm "$so" | grep ' [BCDGINRSTVW] .' | grep -v " $symprefix\\($IGNORED_SYMBOLS\\>\\)" | cut -d' ' -f3 | c++filt`"
echo "Processing $so"
if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}_"; then
echo "Ouch, internal symbols exposed"
stat=1
fi
prefix=$symprefix`basename "$so" | sed 's/libharfbuzz/hb/; s/-/_/g; s/[.].*//'`
tested=true
echo
echo "Checking that $so does not expose internal symbols"
if echo "$EXPORTED_SYMBOLS" | grep -v "^${prefix}\(_\|$\)"; then
echo "Ouch, internal symbols exposed"
stat=1
fi
def=$soname.def
if ! test -f "$def"; then
echo "'$def' not found; skipping"
else
echo
echo "Checking that $so has the same symbol list as $def"
{
echo EXPORTS
echo "$EXPORTED_SYMBOLS" | sed -e "s/^${symprefix}hb/hb/g"
# cheat: copy the last line from the def file!
tail -n1 "$def"
} | c++filt | diff "$def" - >&2 || stat=1
fi
tested=true
done
done
if ! $tested; then
echo "check-symbols.sh: no shared library found; skipping test"
echo "check-symbols.sh: no shared libraries found; skipping test"
exit 77
fi

84
src/dev-run.sh Executable file
View File

@ -0,0 +1,84 @@
#!/bin/bash
# Suggested setup to use the script:
# (on the root of the project)
# $ NOCONFIGURE=1 ./autogen.sh --with-freetype --with-glib --with-gobject --with-cairo
# $ mkdir build && cd build && ../configure && 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 are using iTerm2, issue 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 = "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=$(mktemp)
[ -f 'build/build.ninja' ] && CMAKENINJA=TRUE
# or "fswatch -0 . -e build/ -e .git"
find src/ | entr printf '\0' | while read -d ""; do
clear
echo '===================================================='
if [[ $CMAKENINJA ]]; then
ninja -Cbuild hb-shape hb-view && {
build/hb-shape $@
if [ $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 [ $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

43
src/dump-indic-data.cc Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-indic-private.hh"
int
main (void)
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{
hb_glyph_info_t info;
info.codepoint = u;
set_indic_properties (info);
if (info.indic_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
info.indic_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
printf("U+%04X %u %u\n", u,
info.indic_category(),
info.indic_position());
}
}

43
src/dump-khmer-data.cc Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-khmer-private.hh"
int
main (void)
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{
hb_glyph_info_t info;
info.codepoint = u;
set_khmer_properties (info);
if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
info.khmer_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
printf("U+%04X %u %u\n", u,
info.khmer_category(),
info.khmer_position());
}
}

43
src/dump-myanmar-data.cc Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-myanmar-private.hh"
int
main (void)
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{
hb_glyph_info_t info;
info.codepoint = u;
set_myanmar_properties (info);
if (info.myanmar_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
info.myanmar_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
printf("U+%04X %u %u\n", u,
info.myanmar_category(),
info.myanmar_position());
}
}

38
src/dump-use-data.cc Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-use-private.hh"
int
main (void)
{
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
{
unsigned int category = hb_use_get_category (u);
if (category != USE_O)
printf("U+%04X %u\n", u, category);
}
}

View File

@ -134,7 +134,7 @@ def print_joining_table(f):
for (start,end) in ranges:
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "joining_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
print " if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset)
print " break;"
print ""
print " default:"

19
src/gen-def.py Executable file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
from __future__ import print_function
import io, os, re, sys
headers_content = []
for h in os.environ["headers"].split (' '):
if h.endswith (".h"):
with io.open(h, encoding='utf8') as f: headers_content.append (f.read ())
result = """EXPORTS
%s
LIBRARY lib%s-0.dll""" % (
"\n".join (sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))),
sys.argv[1].replace ('.def', '')
)
with open (sys.argv[1], "w") as f: f.write (result)

View File

@ -229,13 +229,13 @@ print " {"
pages = set([u>>page_bits for u in starts+ends+singles.keys()])
for p in sorted(pages):
print " case 0x%0Xu:" % p
for (start,end) in zip (starts, ends):
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "indic_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
for u,d in singles.items ():
if p != u>>page_bits: continue
print " if (unlikely (u == 0x%04Xu)) return _(%s,%s);" % (u, short[0][d[0]], short[1][d[1]])
for (start,end) in zip (starts, ends):
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "indic_offset_0x%04xu" % start
print " if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return indic_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
print " break;"
print ""
print " default:"

52
src/gen-unicode-ranges.py Normal file
View File

@ -0,0 +1,52 @@
# -*- 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).
import io
import re
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print (u"""static Range os2UnicodeRangesSorted[] =
{""")
args = sys.argv[1:]
input_file = args[0]
with io.open(input_file, mode="r", encoding="utf-8") as f:
all_ranges = [];
current_bit = 0
while True:
line = f.readline().strip()
if not line:
break
fields = re.split(r'\t+', line)
if len(fields) == 3:
current_bit = fields[0]
fields = fields[1:]
elif len(fields) > 3:
raise Error("bad input :(.")
name = fields[0]
ranges = re.split("-", fields[1])
if len(ranges) != 2:
raise Error("bad input :(.")
v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name))
all_ranges.append(v)
all_ranges = sorted(all_ranges, key=lambda t: t[0])
for ranges in all_ranges:
start = ("0x%X" % ranges[0]).rjust(8)
end = ("0x%X" % ranges[1]).rjust(8)
bit = ("%s" % ranges[2]).rjust(3)
print " {%s, %s, %s}, // %s" % (start, end, bit, ranges[3])
print (u"""};""");

View File

@ -44,6 +44,7 @@ defaults = ('Other', 'Not_Applicable', 'Cn', 'No_Block')
# TODO Characters that are not in Unicode Indic files, but used in USE
data[0][0x034F] = defaults[0]
data[0][0x2060] = defaults[0]
data[0][0x20F0] = defaults[0]
for u in range (0xFE00, 0xFE0F + 1):
data[0][u] = defaults[0]
@ -117,6 +118,7 @@ property_names = [
'Top_And_Right',
'Top_And_Left',
'Top_And_Left_And_Right',
'Bottom_And_Left',
'Bottom_And_Right',
'Top_And_Bottom_And_Right',
'Overstruck',
@ -153,7 +155,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 [0x104E, 0x2022]) or
(UGC == Po and not U in [0x104E, 0x2022, 0x11A3F, 0x11A45]) or
False # SPEC-DRAFT-OUTDATED! U == 0x002D
)
def is_BASE_NUM(U, UISC, UGC):
@ -177,6 +179,8 @@ def is_CONS_MOD(U, UISC, UGC):
def is_CONS_SUB(U, UISC, UGC):
#SPEC-DRAFT return UISC == Consonant_Subjoined
return UISC == Consonant_Subjoined and UGC != Lo
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]
def is_HALANT_NUM(U, UISC, UGC):
@ -198,9 +202,7 @@ def is_OTHER(U, UISC, UGC):
def is_Reserved(U, UISC, UGC):
return UGC == 'Cn'
def is_REPHA(U, UISC, UGC):
#return UISC == Consonant_Preceding_Repha
#SPEC-OUTDATED hack to categorize Consonant_With_Stacker and Consonant_Prefixed
return UISC in [Consonant_Preceding_Repha, Consonant_With_Stacker, Consonant_Prefixed]
return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
def is_SYM(U, UISC, UGC):
if U == 0x25CC: return False #SPEC-DRAFT
#SPEC-DRAFT return UGC in [So, Sc] or UISC == Symbol_Letter
@ -210,11 +212,13 @@ def is_SYM_MOD(U, UISC, UGC):
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
return (UISC == Pure_Killer or
(UGC != Lo and UISC in [Vowel, Vowel_Dependent]))
(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
return (UISC in [Tone_Mark, Cantillation_Mark, Register_Shifter, Visarga] or
(UGC != Lo and UISC == Bindu))
(UGC != Lo and (UISC == Bindu or U in [0xAA29])))
use_mapping = {
'B': is_BASE,
@ -227,6 +231,7 @@ use_mapping = {
'M': is_CONS_MED,
'CM': is_CONS_MOD,
'SUB': is_CONS_SUB,
'CS': is_CONS_WITH_STACKER,
'H': is_HALANT,
'HN': is_HALANT_NUM,
'ZWNJ': is_ZWNJ,
@ -250,7 +255,7 @@ use_positions = {
},
'M': {
'Abv': [Top],
'Blw': [Bottom],
'Blw': [Bottom, Bottom_And_Left],
'Pst': [Right],
'Pre': [Left],
},
@ -292,12 +297,23 @@ def map_to_use(data):
if U == 0x17DD: UISC = Vowel_Dependent
if 0x1CE2 <= U <= 0x1CE8: UISC = Cantillation_Mark
# TODO: https://github.com/harfbuzz/harfbuzz/pull/627
if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
# TODO: U+1CED should only be allowed after some of
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
if U == 0x1CED: UISC = Tone_Mark
evals = [(k, v(U,UISC,UGC)) for k,v in items]
values = [k for k,v in evals if v]
# 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
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]
@ -336,12 +352,6 @@ def map_to_use(data):
defaults = ('O', 'No_Block')
data = map_to_use(data)
# Remove the outliers
singles = {}
for u in [0x034F, 0x25CC, 0x1107F]:
singles[u] = data[u]
del data[u]
print "/* == Start of generated table == */"
print "/*"
print " * The following table is generated by running:"
@ -439,20 +449,17 @@ page_bits = 12
print "}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy)
print
print "USE_TABLE_ELEMENT_TYPE"
print "hb_use_get_categories (hb_codepoint_t u)"
print "hb_use_get_category (hb_codepoint_t u)"
print "{"
print " switch (u >> %d)" % page_bits
print " {"
pages = set([u>>page_bits for u in starts+ends+singles.keys()])
pages = set([u>>page_bits for u in starts+ends])
for p in sorted(pages):
print " case 0x%0Xu:" % p
for (start,end) in zip (starts, ends):
if p not in [start>>page_bits, end>>page_bits]: continue
offset = "use_offset_0x%04xu" % start
print " if (hb_in_range (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
for u,d in singles.items ():
if p != u>>page_bits: continue
print " if (unlikely (u == 0x%04Xu)) return %s;" % (u, d[0])
print " if (hb_in_range<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return use_table[u - 0x%04Xu + %s];" % (start, end-1, start, offset)
print " break;"
print ""
print " default:"

View File

@ -0,0 +1,82 @@
# Set these variables so that the `${prefix}/lib` expands to something we can
# remove.
set(_harfbuzz_remove_string "REMOVE_ME")
set(exec_prefix "${_harfbuzz_remove_string}")
set(prefix "${_harfbuzz_remove_string}")
# Compute the installation prefix by stripping components from our current
# location.
get_filename_component(_harfbuzz_prefix "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
set(_harfbuzz_libdir "@libdir@")
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}")
set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}")
while (_harfbuzz_libdir_iter)
get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY)
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
endwhile ()
unset(_harfbuzz_libdir_iter)
# Get the include subdir.
set(_harfbuzz_includedir "@includedir@")
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_includedir "${_harfbuzz_includedir}")
# Extract version information from libtool.
set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
string(REPLACE ":" ";" _harfbuzz_version_info "${_harfbuzz_version_info}")
list(GET _harfbuzz_version_info 0
_harfbuzz_current)
list(GET _harfbuzz_version_info 1
_harfbuzz_revision)
list(GET _harfbuzz_version_info 2
_harfbuzz_age)
unset(_harfbuzz_version_info)
if (APPLE)
set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}")
elseif (UNIX)
set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}")
else ()
# Unsupported.
set(harfbuzz_FOUND 0)
endif ()
# Add the libraries.
add_library(harfbuzz::harfbuzz SHARED IMPORTED)
set_target_properties(harfbuzz::harfbuzz PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
add_library(harfbuzz::icu SHARED IMPORTED)
set_target_properties(harfbuzz::icu PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
add_library(harfbuzz::subset SHARED IMPORTED)
set_target_properties(harfbuzz::subset PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
# Only add the gobject library if it was built.
set(_harfbuzz_have_gobject "@have_gobject@")
if (_harfbuzz_have_gobject)
add_library(harfbuzz::gobject SHARED IMPORTED)
set_target_properties(harfbuzz::gobject PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
endif ()
# Clean out variables we used in our scope.
unset(_harfbuzz_lib_suffix)
unset(_harfbuzz_current)
unset(_harfbuzz_revision)
unset(_harfbuzz_age)
unset(_harfbuzz_includedir)
unset(_harfbuzz_libdir)
unset(_harfbuzz_prefix)
unset(exec_prefix)
unset(prefix)
unset(_harfbuzz_remove_string)

12
src/harfbuzz-subset.pc.in Normal file
View File

@ -0,0 +1,12 @@
prefix=%prefix%
exec_prefix=%exec_prefix%
libdir=%libdir%
includedir=%includedir%
Name: harfbuzz
Description: HarfBuzz font subsetter
Version: %VERSION%
Requires: harfbuzz
Libs: -L${libdir} -lharfbuzz-subset
Cflags: -I${includedir}/harfbuzz

View File

@ -8,6 +8,6 @@ Description: HarfBuzz text shaping library
Version: %VERSION%
Libs: -L${libdir} -lharfbuzz
Libs.private: %libs_private%
Libs.private: -lm %libs_private%
Requires.private: %requires_private%
Cflags: -I${includedir}/harfbuzz

View File

@ -0,0 +1,80 @@
/*
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
#define HB_AAT_LAYOUT_ANKR_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#define HB_AAT_TAG_ankr HB_TAG('a','n','k','r')
namespace AAT {
/*
* ankr -- Anchor point
*/
struct Anchor
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
FWORD xCoordinate;
FWORD yCoordinate;
public:
DEFINE_SIZE_STATIC (4);
};
struct ankr
{
static const hb_tag_t tableTag = HB_AAT_TAG_ankr;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && version == 0 &&
lookupTable.sanitize (c, this) &&
anchors.sanitize (c, this));
}
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
LOffsetTo<Lookup<HBUINT16> > lookupTable; /* Offset to the table's lookup table */
LOffsetTo<ArrayOf<Anchor, HBUINT32> >
anchors; /* Offset to the glyph data table */
public:
DEFINE_SIZE_STATIC (12);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_ANKR_TABLE_HH */

View File

@ -0,0 +1,728 @@
/*
* 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_AAT_LAYOUT_COMMON_PRIVATE_HH
#define HB_AAT_LAYOUT_COMMON_PRIVATE_HH
#include "hb-aat-layout-private.hh"
namespace AAT {
using namespace OT;
/*
* Binary Searching Tables
*/
struct BinSearchHeader
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT16 unitSize; /* Size of a lookup unit for this search in bytes. */
HBUINT16 nUnits; /* Number of units of the preceding size to be searched. */
HBUINT16 searchRange; /* The value of unitSize times the largest power of 2
* that is less than or equal to the value of nUnits. */
HBUINT16 entrySelector; /* The log base 2 of the largest power of 2 less than
* or equal to the value of nUnits. */
HBUINT16 rangeShift; /* The value of unitSize times the difference of the
* value of nUnits minus the largest power of 2 less
* than or equal to the value of nUnits. */
public:
DEFINE_SIZE_STATIC (10);
};
template <typename Type>
struct BinSearchArrayOf
{
inline const Type& operator [] (unsigned int i) const
{
if (unlikely (i >= header.nUnits)) return Null(Type);
return StructAtOffset<Type> (bytes, i * header.unitSize);
}
inline Type& operator [] (unsigned int i)
{
return StructAtOffset<Type> (bytes, i * header.unitSize);
}
inline unsigned int get_size (void) const
{ return header.static_size + header.nUnits * header.unitSize; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
/* Note: for structs that do not reference other structs,
* we do not need to call their sanitize() as we already did
* a bound check on the aggregate array size. We just include
* a small unreachable expression to make sure the structs
* pointed to do have a simple sanitize(), ie. they do not
* reference other structs via offsets.
*/
(void) (false && StructAtOffset<Type> (bytes, 0).sanitize (c));
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
unsigned int count = header.nUnits;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(*this)[i].sanitize (c, base)))
return_trace (false);
return_trace (true);
}
template <typename T>
inline const Type *bsearch (const T &key) const
{
unsigned int size = header.unitSize;
int min = 0, max = (int) header.nUnits - 1;
while (min <= max)
{
int mid = (min + max) / 2;
const Type *p = (const Type *) (((const char *) bytes) + (mid * size));
int c = p->cmp (key);
if (c < 0)
max = mid - 1;
else if (c > 0)
min = mid + 1;
else
return p;
}
return nullptr;
}
private:
inline bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (header.sanitize (c) &&
Type::static_size >= header.unitSize &&
c->check_array (bytes, header.unitSize, header.nUnits));
}
protected:
BinSearchHeader header;
HBUINT8 bytes[VAR];
public:
DEFINE_SIZE_ARRAY (10, bytes);
};
/* TODO Move this to hb-open-type-private.hh and use it in ArrayOf, HeadlessArrayOf,
* and other places around the code base?? */
template <typename Type>
struct UnsizedArrayOf
{
inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; }
inline Type& operator [] (unsigned int i) { return arrayZ[i]; }
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
/* Note: for structs that do not reference other structs,
* we do not need to call their sanitize() as we already did
* a bound check on the aggregate array size. We just include
* a small unreachable expression to make sure the structs
* pointed to do have a simple sanitize(), ie. they do not
* reference other structs via offsets.
*/
(void) (false && arrayZ[0].sanitize (c));
return_trace (true);
}
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
for (unsigned int i = 0; i < count; i++)
if (unlikely (!arrayZ[i].sanitize (c, base)))
return_trace (false);
return_trace (true);
}
template <typename T>
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
for (unsigned int i = 0; i < count; i++)
if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
return_trace (false);
return_trace (true);
}
private:
inline bool sanitize_shallow (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count));
}
public:
Type arrayZ[VAR];
public:
DEFINE_SIZE_ARRAY (0, arrayZ);
};
/* Unsized array of offset's */
template <typename Type, typename OffsetType>
struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType> > {};
/* Unsized array of offsets relative to the beginning of the array itself. */
template <typename Type, typename OffsetType>
struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
{
inline const Type& operator [] (unsigned int i) const
{
return this+this->arrayZ[i];
}
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this)));
}
template <typename T>
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
{
TRACE_SANITIZE (this);
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType>::sanitize (c, count, this, user_data)));
}
};
/*
* Lookup Table
*/
template <typename T> struct Lookup;
template <typename T>
struct LookupFormat0
{
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
if (unlikely (glyph_id >= num_glyphs)) return nullptr;
return &arrayZ[glyph_id];
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (arrayZ.sanitize (c, c->num_glyphs));
}
protected:
HBUINT16 format; /* Format identifier--format = 0 */
UnsizedArrayOf<T>
arrayZ; /* Array of lookup values, indexed by glyph index. */
public:
DEFINE_SIZE_ARRAY (2, arrayZ);
};
template <typename T>
struct LookupSegmentSingle
{
inline int cmp (hb_codepoint_t g) const {
return g < first ? -1 : g <= last ? 0 : +1 ;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c));
}
GlyphID last; /* Last GlyphID in this segment */
GlyphID first; /* First GlyphID in this segment */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
};
template <typename T>
struct LookupFormat2
{
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
return v ? &v->value : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
BinSearchArrayOf<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). */
public:
DEFINE_SIZE_ARRAY (8, segments);
};
template <typename T>
struct LookupSegmentArray
{
inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
{
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
}
inline int cmp (hb_codepoint_t g) const {
return g < first ? -1 : g <= last ? 0 : +1 ;
}
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1));
}
GlyphID last; /* Last GlyphID in this segment */
GlyphID first; /* First GlyphID in this segment */
OffsetTo<UnsizedArrayOf<T> >
valuesZ; /* A 16-bit offset from the start of
* the table to the data. */
public:
DEFINE_SIZE_STATIC (6);
};
template <typename T>
struct LookupFormat4
{
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
return v ? v->get_value (glyph_id, this) : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (segments.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
BinSearchArrayOf<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). */
public:
DEFINE_SIZE_ARRAY (8, segments);
};
template <typename T>
struct LookupSingle
{
inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && value.sanitize (c));
}
GlyphID glyph; /* Last GlyphID */
T value; /* The lookup value (only one) */
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
};
template <typename T>
struct LookupFormat6
{
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
{
const LookupSingle<T> *v = entries.bsearch (glyph_id);
return v ? &v->value : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (entries.sanitize (c));
}
protected:
HBUINT16 format; /* Format identifier--format = 6 */
BinSearchArrayOf<LookupSingle<T> >
entries; /* The actual entries, sorted by glyph index. */
public:
DEFINE_SIZE_ARRAY (8, entries);
};
template <typename T>
struct LookupFormat8
{
friend struct Lookup<T>;
private:
inline const T* get_value (hb_codepoint_t glyph_id) const
{
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
}
protected:
HBUINT16 format; /* Format identifier--format = 6 */
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
* glyph minus the value of firstGlyph plus 1). */
UnsizedArrayOf<T>
valueArrayZ; /* The lookup values (indexed by the glyph index
* minus the value of firstGlyph). */
public:
DEFINE_SIZE_ARRAY (6, valueArrayZ);
};
template <typename T>
struct Lookup
{
inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
switch (u.format) {
case 0: return u.format0.get_value (glyph_id, num_glyphs);
case 2: return u.format2.get_value (glyph_id);
case 4: return u.format4.get_value (glyph_id);
case 6: return u.format6.get_value (glyph_id);
case 8: return u.format8.get_value (glyph_id);
default:return nullptr;
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
case 6: return_trace (u.format6.sanitize (c));
case 8: return_trace (u.format8.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
LookupFormat0<T> format0;
LookupFormat2<T> format2;
LookupFormat4<T> format4;
LookupFormat6<T> format6;
LookupFormat8<T> format8;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/*
* Extended State Table
*/
template <typename T>
struct Entry
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
/* Note, we don't recurse-sanitize data because we don't access it.
* That said, in our DEFINE_SIZE_STATIC we access T::static_size,
* which ensures that data has a simple sanitize(). To be determined
* if I need to remove that as well. */
return_trace (c->check_struct (this));
}
public:
HBUINT16 newState; /* Byte offset from beginning of state table
* to the new state. Really?!?! Or just state
* number? The latter in morx for sure. */
HBUINT16 flags; /* Table specific. */
T data; /* Optional offsets to per-glyph tables. */
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
};
template <>
struct Entry<void>
{
inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */
HBUINT16 flags; /* Table specific. */
public:
DEFINE_SIZE_STATIC (4);
};
template <typename Extra>
struct StateTable
{
inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
{
const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
return v ? *v : 1;
}
inline const Entry<Extra> *get_entries () const
{
return (this+entryTable).arrayZ;
}
inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
{
if (unlikely (klass >= nClasses)) return nullptr;
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int entry = states[state * nClasses + klass];
return &entries[entry];
}
inline bool sanitize (hb_sanitize_context_t *c,
unsigned int *num_entries_out = nullptr) const
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) &&
classTable.sanitize (c, this)))) return_trace (false);
const HBUINT16 *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int num_states = 1;
unsigned int num_entries = 0;
unsigned int state = 0;
unsigned int entry = 0;
while (state < num_states)
{
if (unlikely (!c->check_array (states,
states[0].static_size * nClasses,
num_states)))
return_trace (false);
{ /* Sweep new states. */
const HBUINT16 *stop = &states[num_states * nClasses];
for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
num_entries = MAX<unsigned int> (num_entries, *p + 1);
state = num_states;
}
if (unlikely (!c->check_array (entries,
entries[0].static_size,
num_entries)))
return_trace (false);
{ /* Sweep new entries. */
const Entry<Extra> *stop = &entries[num_entries];
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
num_states = MAX<unsigned int> (num_states, p->newState + 1);
entry = num_entries;
}
}
if (num_entries_out)
*num_entries_out = num_entries;
return_trace (true);
}
protected:
HBUINT32 nClasses; /* Number of classes, which is the number of indices
* in a single line in the state array. */
OffsetTo<Lookup<HBUINT16>, HBUINT32>
classTable; /* Offset to the class table. */
OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
stateArrayTable;/* Offset to the state array. */
OffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT32>
entryTable; /* Offset to the entry array. */
public:
DEFINE_SIZE_STATIC (16);
};
template <typename EntryData>
struct StateTableDriver
{
inline StateTableDriver (const StateTable<EntryData> &machine_,
hb_buffer_t *buffer_,
hb_face_t *face_) :
machine (machine_),
buffer (buffer_),
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t>
inline void drive (context_t *c)
{
hb_glyph_info_t *info = buffer->info;
if (!c->in_place)
buffer->clear_output ();
unsigned int state = 0;
bool last_was_dont_advance = false;
for (buffer->idx = 0;;)
{
unsigned int klass = buffer->idx < buffer->len ?
machine.get_class (info[buffer->idx].codepoint, num_glyphs) :
0 /* End of text */;
const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
if (unlikely (!entry))
break;
/* Unsafe-to-break before this if not in state 0, as things might
* go differently if we start from state 0 here. */
if (state && buffer->idx)
{
/* 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 == 0 && entry->flags == context_t::DontAdvance))
buffer->unsafe_to_break (buffer->idx - 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);
if (c->is_actionable (this, end_entry))
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
}
if (unlikely (!c->transition (this, entry)))
break;
last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
state = entry->newState;
if (buffer->idx == buffer->len)
break;
if (!last_was_dont_advance)
buffer->next_glyph ();
}
if (!c->in_place)
{
for (; buffer->idx < buffer->len;)
buffer->next_glyph ();
buffer->swap_buffers ();
}
}
public:
const StateTable<EntryData> &machine;
hb_buffer_t *buffer;
unsigned int num_glyphs;
};
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
inline const char *get_name (void) { return "APPLY"; }
template <typename T>
inline return_t dispatch (const T &obj) { return obj.apply (this); }
static return_t default_return_value (void) { return false; }
bool stop_sublookup_iteration (return_t r) const { return r; }
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
/* Unused. For debug tracing only. */
unsigned int lookup_index;
unsigned int debug_depth;
inline hb_aat_apply_context_t (hb_font_t *font_,
hb_buffer_t *buffer_,
hb_blob_t *table) :
font (font_), face (font->face), buffer (buffer_),
sanitizer (), lookup_index (0), debug_depth (0)
{
sanitizer.init (table);
sanitizer.num_glyphs = face->get_num_glyphs ();
sanitizer.start_processing ();
}
inline void set_lookup_index (unsigned int i) { lookup_index = i; }
inline ~hb_aat_apply_context_t (void)
{
sanitizer.end_processing ();
}
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_COMMON_PRIVATE_HH */

View File

@ -0,0 +1,384 @@
/*
* Copyright © 2018 Google, Inc.
* Copyright © 2018 Ebrahim Byagowi
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_KERX_TABLE_HH
#define HB_AAT_LAYOUT_KERX_TABLE_HH
#include "hb-aat-layout-common-private.hh"
namespace AAT {
/*
* kerx -- Kerning
*/
#define HB_AAT_TAG_kerx HB_TAG('k','e','r','x')
struct hb_glyph_pair_t
{
hb_codepoint_t left;
hb_codepoint_t right;
};
struct KerxPair
{
inline int get_kerning (void) const
{ return value; }
inline int cmp (const hb_glyph_pair_t &o) const
{
int ret = left.cmp (o.left);
if (ret) return ret;
return right.cmp (o.right);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
GlyphID left;
GlyphID right;
FWORD value;
HBUINT16 pad;
public:
DEFINE_SIZE_STATIC (8);
};
struct KerxSubTableFormat0
{
inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
//hb_glyph_pair_t pair = {left, right};
//int i = pairs.bsearch (pair);
//if (i == -1)
return 0;
//return pairs[i].get_kerning ();
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (pairs.sanitize (c));
}
protected:
BinSearchArrayOf<KerxPair> pairs; /* Array of kerning pairs. */
//FIXME: BinSearchArrayOf and its BinSearchHeader should be
//modified in a way to accept uint32s
public:
//DEFINE_SIZE_ARRAY (16, pairs);
};
struct KerxAction
{
HBUINT16 index;
};
struct KerxSubTableFormat1
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
//TRACE_SANITIZE (this);
//return_trace (stateHeader.sanitize (c));
return false;
}
protected:
StateTable<KerxAction> stateHeader;
OffsetTo<ArrayOf<HBUINT16>, HBUINT32> valueTable;
public:
//DEFINE_SIZE_MIN (4);
};
//FIXME: Maybe this can be replaced with Lookup<HBUINT16>?
struct KerxClassTable
{
inline unsigned int get_class (hb_codepoint_t g) const { return classes[g - firstGlyph]; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (firstGlyph.sanitize (c) && classes.sanitize (c));
}
protected:
HBUINT16 firstGlyph; /* First glyph in class range. */
ArrayOf<HBUINT16> classes; /* Glyph classes. */
public:
DEFINE_SIZE_ARRAY (4, classes);
};
struct KerxSubTableFormat2
{
inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
{
unsigned int l = (this+leftClassTable).get_class (left);
unsigned int r = (this+leftClassTable).get_class (left);
unsigned int offset = l * rowWidth + r * sizeof (FWORD);
const FWORD *arr = &(this+array);
if (unlikely ((const void *) arr < (const void *) this || (const void *) arr >= (const void *) end))
return 0;
const FWORD *v = &StructAtOffset<FWORD> (arr, offset);
if (unlikely ((const void *) v < (const void *) arr || (const void *) (v + 1) > (const void *) end))
return 0;
return *v;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (rowWidth.sanitize (c) &&
leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) &&
array.sanitize (c, this));
}
protected:
HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */
LOffsetTo<KerxClassTable>
leftClassTable; /* Offset from beginning of this subtable to
* left-hand class table. */
LOffsetTo<KerxClassTable>
rightClassTable;/* Offset from beginning of this subtable to
* right-hand class table. */
LOffsetTo<FWORD>
array; /* Offset from beginning of this subtable to
* the start of the kerning array. */
public:
DEFINE_SIZE_MIN (16);
};
struct KerxSubTableFormat4
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (rowWidth.sanitize (c) &&
leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) &&
array.sanitize (c, this));
}
protected:
HBUINT32 rowWidth; /* The width, in bytes, of a row in the table. */
LOffsetTo<KerxClassTable>
leftClassTable; /* Offset from beginning of this subtable to
* left-hand class table. */
LOffsetTo<KerxClassTable>
rightClassTable;/* Offset from beginning of this subtable to
* right-hand class table. */
LOffsetTo<FWORD>
array; /* Offset from beginning of this subtable to
* the start of the kerning array. */
public:
DEFINE_SIZE_MIN (16);
};
struct KerxSubTableFormat6
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
//TRACE_SANITIZE (this);
//return_trace ;
return false;
}
protected:
HBUINT32 flags;
HBUINT16 rowCount;
HBUINT16 columnCount;
HBUINT32 rowIndexTableOffset;
HBUINT32 columnIndexTableOffset;
HBUINT32 kerningArrayOffset;
HBUINT32 kerningVectorOffset;
public:
DEFINE_SIZE_MIN (24);
};
struct KerxSubTable
{
inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end, unsigned int format) const
{
switch (format) {
case 0: return u.format0.get_kerning (left, right);
case 2: return u.format2.get_kerning (left, right, end);
default:return 0;
}
}
inline bool sanitize (hb_sanitize_context_t *c, unsigned int format) const
{
TRACE_SANITIZE (this);
switch (format) {
case 0: return_trace (u.format0.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
KerxSubTableFormat0 format0;
KerxSubTableFormat2 format2;
KerxSubTableFormat4 format4;
KerxSubTableFormat6 format6;
} u;
public:
DEFINE_SIZE_MIN (0);
};
struct kerx
{
static const hb_tag_t tableTag = HB_AAT_TAG_kerx;
inline bool apply (hb_aat_apply_context_t *c, const AAT::ankr *ankr) const
{
TRACE_APPLY (this);
/* TODO */
return_trace (false);
}
struct SubTableWrapper
{
enum coverage_flags_t {
COVERAGE_VERTICAL_FLAG = 0x8000u,
COVERAGE_CROSSSTREAM_FLAG = 0x4000u,
COVERAGE_VARIATION_FLAG = 0x2000u,
COVERAGE_OVERRIDE_FLAG = 0x0000u, /* Not supported. */
COVERAGE_CHECK_FLAGS = 0x0700u, //FIXME: Where these two come from?
COVERAGE_CHECK_HORIZONTAL = 0x0100u
};
protected:
HBUINT32 length; /* Length of the subtable (including this header). */
HBUINT16 coverage; /* Coverage bits. */
HBUINT16 format; /* Subtable format. */
HBUINT32 tupleIndex; /* The tuple index (used for variations fonts).
* This value specifies which tuple this subtable covers. */
KerxSubTable subtable; /* Subtable data. */
public:
inline bool is_horizontal (void) const
{ return (coverage & COVERAGE_CHECK_FLAGS) == COVERAGE_CHECK_HORIZONTAL; }
inline bool is_override (void) const
{ return bool (coverage & COVERAGE_OVERRIDE_FLAG); }
inline int get_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
{ return subtable.get_kerning (left, right, end, format); }
inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, const char *end) const
{ return is_horizontal () ? get_kerning (left, right, end) : 0; }
inline unsigned int get_size (void) const { return length; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
length >= min_size &&
c->check_array (this, 1, length) &&
subtable.sanitize (c, format));
}
DEFINE_SIZE_MIN (12);
};
inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right, unsigned int table_length) const
{
int v = 0;
const SubTableWrapper *st = (SubTableWrapper *) data;
unsigned int count = nTables;
for (unsigned int i = 0; i < count; i++)
{
if (st->is_override ())
v = 0;
v += st->get_h_kerning (left, right, table_length + (const char *) this);
st = (SubTableWrapper *) st;
}
return v;
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
const SubTableWrapper *st = (SubTableWrapper *) data;
unsigned int count = nTables;
for (unsigned int i = 0; i < count; i++)
{
if (unlikely (!st->sanitize (c)))
return_trace (false);
st = (SubTableWrapper *) st;
}
return_trace (true);
}
struct accelerator_t
{
inline void init (hb_face_t *face)
{
blob = Sanitizer<kerx>().sanitize (face->reference_table (HB_AAT_TAG_kerx));
table = Sanitizer<kerx>::lock_instance (blob);
table_length = hb_blob_get_length (blob);
}
inline void fini (void)
{
hb_blob_destroy (blob);
}
inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{ return table->get_h_kerning (left, right, table_length); }
private:
hb_blob_t *blob;
const kerx *table;
unsigned int table_length;
};
protected:
HBUINT16 version;
HBUINT16 padding;
HBUINT32 nTables; /* Number of subtables in the kerning table. */
HBUINT8 data[VAR];
//ArrayOf<GlyphCoverageArray> subtableGlyphCoverageArray;
public:
DEFINE_SIZE_ARRAY (8, data);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_KERX_TABLE_HH */

View File

@ -0,0 +1,728 @@
/*
* 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_AAT_LAYOUT_MORX_TABLE_HH
#define HB_AAT_LAYOUT_MORX_TABLE_HH
#include "hb-open-type-private.hh"
#include "hb-aat-layout-common-private.hh"
#define HB_AAT_TAG_MORX HB_TAG('m','o','r','x')
namespace AAT {
using namespace OT;
struct RearrangementSubtable
{
typedef void EntryData;
struct driver_context_t
{
static const bool in_place = true;
enum Flags {
MarkFirst = 0x8000, /* If set, make the current glyph the first
* glyph to be rearranged. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. This means
* that the glyph index doesn't change, even
* if the glyph at that index has changed. */
MarkLast = 0x2000, /* If set, make the current glyph the last
* glyph to be rearranged. */
Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */
Verb = 0x000F, /* The type of rearrangement specified. */
};
inline driver_context_t (const RearrangementSubtable *table) :
ret (false),
start (0), end (0) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
{
return (entry->flags & Verb) && start < end;
}
inline bool transition (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry->flags;
if (flags & MarkFirst)
start = buffer->idx;
if (flags & MarkLast)
end = MIN (buffer->idx + 1, buffer->len);
if ((flags & Verb) && start < end)
{
/* The following map has two nibbles, for start-side
* and end-side. Values of 0,1,2 mean move that many
* to the other side. Value of 3 means move 2 and
* flip them. */
const unsigned char map[16] =
{
0x00, /* 0 no change */
0x10, /* 1 Ax => xA */
0x01, /* 2 xD => Dx */
0x11, /* 3 AxD => DxA */
0x20, /* 4 ABx => xAB */
0x30, /* 5 ABx => xBA */
0x02, /* 6 xCD => CDx */
0x03, /* 7 xCD => DCx */
0x12, /* 8 AxCD => CDxA */
0x13, /* 9 AxCD => DCxA */
0x21, /* 10 ABxD => DxAB */
0x31, /* 11 ABxD => DxBA */
0x22, /* 12 ABxCD => CDxAB */
0x32, /* 13 ABxCD => CDxBA */
0x23, /* 14 ABxCD => DCxAB */
0x33, /* 15 ABxCD => DCxBA */
};
unsigned int m = map[flags & Verb];
unsigned int l = MIN<unsigned int> (2, m >> 4);
unsigned int r = MIN<unsigned int> (2, 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, end);
hb_glyph_info_t *info = buffer->info;
hb_glyph_info_t buf[4];
memcpy (buf, info + start, l * sizeof (buf[0]));
memcpy (buf + 2, info + end - r, r * sizeof (buf[0]));
if (l != r)
memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0]));
memcpy (info + start, buf + 2, r * sizeof (buf[0]));
memcpy (info + end - l, buf, l * sizeof (buf[0]));
if (reverse_l)
{
buf[0] = info[end - 1];
info[end - 1] = info[end - 2];
info[end - 2] = buf[0];
}
if (reverse_r)
{
buf[0] = info[start];
info[start] = info[start + 1];
info[start + 1] = buf[0];
}
}
}
return true;
}
public:
bool ret;
private:
unsigned int start;
unsigned int end;
};
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
driver_context_t dc (this);
StateTableDriver<void> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (machine.sanitize (c));
}
protected:
StateTable<EntryData> machine;
public:
DEFINE_SIZE_STATIC (16);
};
struct ContextualSubtable
{
struct EntryData
{
HBUINT16 markIndex; /* Index of the substitution table for the
* marked glyph (use 0xFFFF for none). */
HBUINT16 currentIndex; /* Index of the substitution table for the
* current glyph (use 0xFFFF for none). */
public:
DEFINE_SIZE_STATIC (4);
};
struct driver_context_t
{
static const bool in_place = true;
enum Flags {
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
};
inline driver_context_t (const ContextualSubtable *table) :
ret (false),
mark_set (false),
mark (0),
subs (table+table->substitutionTables) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver,
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;
}
inline bool transition (StateTableDriver<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;
if (entry->data.markIndex != 0xFFFF)
{
const Lookup<GlyphID> &lookup = subs[entry->data.markIndex];
hb_glyph_info_t *info = buffer->info;
const GlyphID *replacement = lookup.get_value (info[mark].codepoint, driver->num_glyphs);
if (replacement)
{
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
info[mark].codepoint = *replacement;
ret = true;
}
}
if (entry->data.currentIndex != 0xFFFF)
{
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
const Lookup<GlyphID> &lookup = subs[entry->data.currentIndex];
hb_glyph_info_t *info = buffer->info;
const GlyphID *replacement = lookup.get_value (info[idx].codepoint, driver->num_glyphs);
if (replacement)
{
info[idx].codepoint = *replacement;
ret = true;
}
}
if (entry->flags & SetMark)
{
mark_set = true;
mark = buffer->idx;
}
return true;
}
public:
bool ret;
private:
bool mark_set;
unsigned int mark;
const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32> &subs;
};
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
driver_context_t dc (this);
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
unsigned int num_entries = 0;
if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
unsigned int num_lookups = 0;
const Entry<EntryData> *entries = machine.get_entries ();
for (unsigned int i = 0; i < num_entries; i++)
{
const EntryData &data = entries[i].data;
if (data.markIndex != 0xFFFF)
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
if (data.currentIndex != 0xFFFF)
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
}
return_trace (substitutionTables.sanitize (c, this, num_lookups));
}
protected:
StateTable<EntryData> machine;
OffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT32>, HBUINT32>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
};
struct LigatureSubtable
{
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
* for processing this group, if indicated
* by the flags. */
public:
DEFINE_SIZE_STATIC (2);
};
struct driver_context_t
{
static const bool in_place = false;
enum Flags {
SetComponent = 0x8000, /* Push this glyph onto the component stack for
* eventual processing. */
DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the
next iteration. */
PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature
* group. */
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
};
enum LigActionFlags {
LigActionLast = 0x80000000, /* This is the last action in the list. This also
* implies storage. */
LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index
* in the ligature table in place of the marked
* (i.e. currently-popped) glyph. */
LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits
* and added to the glyph ID, resulting in an index
* into the component table. */
};
inline driver_context_t (const LigatureSubtable *table,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
ligAction (table+table->ligAction),
component (table+table->component),
ligature (table+table->ligature),
match_length (0) {}
inline bool is_actionable (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
{
return !!(entry->flags & PerformAction);
}
inline bool transition (StateTableDriver<EntryData> *driver,
const Entry<EntryData> *entry)
{
hb_buffer_t *buffer = driver->buffer;
unsigned int flags = entry->flags;
if (flags & 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)
match_length--;
match_positions[match_length++] = buffer->out_len;
}
if (flags & PerformAction)
{
unsigned int end = buffer->out_len;
unsigned int action_idx = entry->data.ligActionIndex;
unsigned int action;
unsigned int ligature_idx = 0;
do
{
if (unlikely (!match_length))
return false;
buffer->move_to (match_positions[--match_length]);
const HBUINT32 &actionData = ligAction[action_idx];
if (unlikely (!actionData.sanitize (&c->sanitizer))) return false;
action = actionData;
uint32_t uoffset = action & LigActionOffset;
if (uoffset & 0x20000000)
uoffset += 0xC0000000;
int32_t offset = (int32_t) uoffset;
unsigned int component_idx = buffer->cur().codepoint + offset;
const HBUINT16 &componentData = component[component_idx];
if (unlikely (!componentData.sanitize (&c->sanitizer))) return false;
ligature_idx += componentData;
if (action & (LigActionStore | LigActionLast))
{
const GlyphID &ligatureData = ligature[ligature_idx];
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) return false;
hb_codepoint_t lig = ligatureData;
match_positions[match_length++] = buffer->out_len;
buffer->replace_glyph (lig);
//ligature_idx = 0; // XXX Yes or no?
}
else
{
buffer->skip_glyph ();
end--;
}
/* TODO merge_clusters / unsafe_to_break */
action_idx++;
}
while (!(action & LigActionLast));
buffer->move_to (end);
}
return true;
}
public:
bool ret;
private:
hb_aat_apply_context_t *c;
const UnsizedArrayOf<HBUINT32> &ligAction;
const UnsizedArrayOf<HBUINT16> &component;
const UnsizedArrayOf<GlyphID> &ligature;
unsigned int match_length;
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
};
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
driver_context_t dc (this, c);
StateTableDriver<EntryData> driver (machine, c->buffer, c->face);
driver.drive (&dc);
return_trace (dc.ret);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */
return_trace (c->check_struct (this) && machine.sanitize (c) &&
ligAction && component && ligature);
}
protected:
StateTable<EntryData> machine;
OffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT32>
ligAction; /* Offset to the ligature action table. */
OffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT32>
component; /* Offset to the component table. */
OffsetTo<UnsizedArrayOf<GlyphID>, HBUINT32>
ligature; /* Offset to the actual ligature lists. */
public:
DEFINE_SIZE_STATIC (28);
};
struct NoncontextualSubtable
{
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
bool ret = false;
unsigned int num_glyphs = c->face->get_num_glyphs ();
hb_glyph_info_t *info = c->buffer->info;
unsigned int count = c->buffer->len;
for (unsigned int i = 0; i < count; i++)
{
const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
if (replacement)
{
info[i].codepoint = *replacement;
ret = true;
}
}
return_trace (ret);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (substitute.sanitize (c));
}
protected:
Lookup<GlyphID> substitute;
public:
DEFINE_SIZE_MIN (2);
};
struct InsertionSubtable
{
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
/* TODO */
return_trace (false);
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
/* TODO */
return_trace (true);
}
};
struct Feature
{
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
public:
HBUINT16 featureType; /* The type of feature. */
HBUINT16 featureSetting; /* The feature's setting (aka selector). */
HBUINT32 enableFlags; /* Flags for the settings that this feature
* and setting enables. */
HBUINT32 disableFlags; /* Complement of flags for the settings that this
* feature and setting disable. */
public:
DEFINE_SIZE_STATIC (12);
};
struct ChainSubtable
{
friend struct Chain;
inline unsigned int get_size (void) const { return length; }
inline unsigned int get_type (void) const { return coverage & 0xFF; }
enum Type {
Rearrangement = 0,
Contextual = 1,
Ligature = 2,
Noncontextual = 4,
Insertion = 5
};
inline void apply (hb_aat_apply_context_t *c) const
{
dispatch (c);
}
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) 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));
default: return_trace (c->default_return_value ());
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!length.sanitize (c) ||
length < min_size ||
!c->check_range (this, length))
return_trace (false);
return_trace (dispatch (c));
}
protected:
HBUINT32 length; /* Total subtable length, including this header. */
HBUINT32 coverage; /* Coverage flags and subtable type. */
HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */
union {
RearrangementSubtable rearrangement;
ContextualSubtable contextual;
LigatureSubtable ligature;
NoncontextualSubtable noncontextual;
InsertionSubtable insertion;
} u;
public:
DEFINE_SIZE_MIN (12);
};
struct Chain
{
inline void apply (hb_aat_apply_context_t *c) const
{
const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
{
c->set_lookup_index (c->lookup_index + 1);
continue;
}
subtable->apply (c);
subtable = &StructAfter<ChainSubtable> (*subtable);
(void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
c->set_lookup_index (c->lookup_index + 1);
}
}
inline unsigned int get_size (void) const { return length; }
inline bool sanitize (hb_sanitize_context_t *c, unsigned int major) const
{
TRACE_SANITIZE (this);
if (!length.sanitize (c) ||
length < min_size ||
!c->check_range (this, length))
return_trace (false);
if (!c->check_array (featureZ, featureZ[0].static_size, featureCount))
return_trace (false);
const ChainSubtable *subtable = &StructAtOffset<ChainSubtable> (featureZ, featureZ[0].static_size * featureCount);
unsigned int count = subtableCount;
for (unsigned int i = 0; i < count; i++)
{
if (!subtable->sanitize (c))
return_trace (false);
subtable = &StructAfter<ChainSubtable> (*subtable);
}
return_trace (true);
}
protected:
HBUINT32 defaultFlags; /* The default specification for subtables. */
HBUINT32 length; /* Total byte count, including this header. */
HBUINT32 featureCount; /* Number of feature subtable entries. */
HBUINT32 subtableCount; /* The number of subtables in the chain. */
Feature featureZ[VAR]; /* Features. */
ChainSubtable subtableX[VAR]; /* Subtables. */
// subtableGlyphCoverageArray if major == 3
public:
DEFINE_SIZE_MIN (16);
};
/*
* The 'mort'/'morx' Tables
*/
struct morx
{
static const hb_tag_t tableTag = HB_AAT_TAG_MORX;
inline void apply (hb_aat_apply_context_t *c) const
{
c->set_lookup_index (0);
const Chain *chain = chains;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
chain->apply (c);
chain = &StructAfter<Chain> (*chain);
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!version.sanitize (c) ||
(version.major >> (sizeof (HBUINT32) == 4 ? 1 : 0)) != 1 ||
!chainCount.sanitize (c))
return_trace (false);
const Chain *chain = chains;
unsigned int count = chainCount;
for (unsigned int i = 0; i < count; i++)
{
if (!chain->sanitize (c, version.major))
return_trace (false);
chain = &StructAfter<Chain> (*chain);
}
return_trace (true);
}
protected:
FixedVersion<>version; /* Version number of the glyph metamorphosis table.
* 1 for mort, 2 or 3 for morx. */
HBUINT32 chainCount; /* Number of metamorphosis chains contained in this
* table. */
Chain chains[VAR]; /* Chains. */
public:
DEFINE_SIZE_MIN (8);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */

View File

@ -0,0 +1,43 @@
/*
* 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_AAT_LAYOUT_PRIVATE_HH
#define HB_AAT_LAYOUT_PRIVATE_HH
#include "hb-private.hh"
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
#include "hb-open-type-private.hh"
HB_INTERNAL void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer);
#endif /* HB_AAT_LAYOUT_PRIVATE_HH */

View File

@ -0,0 +1,201 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2018 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
#define HB_AAT_LAYOUT_TRAK_TABLE_HH
#include "hb-aat-layout-common-private.hh"
#include "hb-open-type-private.hh"
#define HB_AAT_TAG_trak HB_TAG('t','r','a','k')
namespace AAT {
struct TrackTableEntry
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base, unsigned int size) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && (values.sanitize (c, base, size)));
}
inline float get_track_value () const
{
return track.to_float ();
}
inline int get_value (const void *base, unsigned int index) const
{
return (base+values)[index];
}
protected:
Fixed track; /* Track value for this record. */
HBUINT16 trackNameID; /* The 'name' table index for this track */
OffsetTo<UnsizedArrayOf<FWORD> >
values; /* Offset from start of tracking table to
* per-size tracking values for this track. */
public:
DEFINE_SIZE_STATIC (8);
};
struct TrackData
{
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
sizeTable.sanitize (c, base, nSizes) &&
trackTable.sanitize (c, nTracks, base, nSizes));
}
inline float get_tracking (const void *base, float ptem) const
{
/* CoreText points are CSS pixels (96 per inch),
* NOT typographic points (72 per inch).
*
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
*/
float csspx = ptem * 96.f / 72.f;
Fixed fixed_size;
fixed_size.set_float (csspx);
/* XXX Clean this up. Make it work with nSizes==1 and 0. */
unsigned int sizes = nSizes;
const TrackTableEntry *trackTableEntry = nullptr;
for (unsigned int i = 0; i < sizes; ++i)
// For now we only seek for track entries with zero tracking value
if (trackTable[i].get_track_value () == 0.)
trackTableEntry = &trackTable[0];
// We couldn't match any, exit
if (!trackTableEntry) return 0.;
/* TODO bfind() */
unsigned int size_index;
UnsizedArrayOf<Fixed> size_table = base+sizeTable;
for (size_index = 0; size_index < sizes; ++size_index)
if (size_table[size_index] >= fixed_size)
break;
// TODO(ebraminio): We don't attempt to extrapolate to larger or
// smaller values for now but we should do, per spec
if (size_index == sizes)
return trackTableEntry->get_value (base, sizes - 1);
if (size_index == 0 || size_table[size_index] == fixed_size)
return trackTableEntry->get_value (base, size_index);
float s0 = size_table[size_index - 1].to_float ();
float s1 = size_table[size_index].to_float ();
float t = (csspx - s0) / (s1 - s0);
return t * trackTableEntry->get_value (base, size_index) +
(1.0 - t) * trackTableEntry->get_value (base, size_index - 1);
}
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
LOffsetTo<UnsizedArrayOf<Fixed> > /* Offset to array[nSizes] of size values. */
sizeTable;
UnsizedArrayOf<TrackTableEntry>
trackTable; /* Array[nTracks] of TrackTableEntry records. */
public:
DEFINE_SIZE_ARRAY (8, trackTable);
};
struct trak
{
static const hb_tag_t tableTag = HB_AAT_TAG_trak;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this));
}
inline bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
const float ptem = c->font->ptem;
if (ptem <= 0.f)
return_trace (false);
hb_buffer_t *buffer = c->buffer;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
const TrackData &trackData = this+horizData;
float tracking = trackData.get_tracking (this, ptem);
hb_position_t advance_to_add = c->font->em_scalef_x (tracking / 2);
foreach_grapheme (buffer, start, end)
{
/* TODO This is wrong. */
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[end].x_advance += advance_to_add;
}
}
else
{
const TrackData &trackData = this+vertData;
float tracking = trackData.get_tracking (this, ptem);
hb_position_t advance_to_add = c->font->em_scalef_y (tracking / 2);
foreach_grapheme (buffer, start, end)
{
/* TODO This is wrong. */
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[end].y_advance += advance_to_add;
}
}
return_trace (true);
}
protected:
FixedVersion<> version; /* Version of the tracking table--currently
* 0x00010000u for version 1.0. */
HBUINT16 format; /* Format of the tracking table */
OffsetTo<TrackData> horizData; /* TrackData for horizontal text */
OffsetTo<TrackData> vertData; /* TrackData for vertical text */
HBUINT16 reserved; /* Reserved. Set to 0. */
public:
DEFINE_SIZE_MIN (12);
};
} /* namespace AAT */
#endif /* HB_AAT_LAYOUT_TRAK_TABLE_HH */

143
src/hb-aat-layout.cc Normal file
View File

@ -0,0 +1,143 @@
/*
* 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
*/
#include "hb-open-type-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-ot-layout-gsubgpos-private.hh"
#include "hb-aat-layout-private.hh"
#include "hb-aat-layout-ankr-table.hh"
#include "hb-aat-layout-kerx-table.hh"
#include "hb-aat-layout-morx-table.hh"
#include "hb-aat-layout-trak-table.hh"
/*
* morx/kerx/trak
*/
static inline const AAT::ankr&
_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
{
if (blob)
*blob = hb_blob_get_empty ();
return OT::Null(AAT::ankr);
}
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
const AAT::ankr& ankr = *(layout->ankr.get ());
if (blob)
*blob = layout->ankr.blob;
return ankr;
}
static inline const AAT::kerx&
_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
{
if (blob)
*blob = hb_blob_get_empty ();
return OT::Null(AAT::kerx);
}
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
/* XXX this doesn't call set_num_glyphs on sanitizer. */
const AAT::kerx& kerx = *(layout->kerx.get ());
if (blob)
*blob = layout->kerx.blob;
return kerx;
}
static inline const AAT::morx&
_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
{
if (blob)
*blob = hb_blob_get_empty ();
return OT::Null(AAT::morx);
}
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
/* XXX this doesn't call set_num_glyphs on sanitizer. */
const AAT::morx& morx = *(layout->morx.get ());
if (blob)
*blob = layout->morx.blob;
return morx;
}
static inline const AAT::trak&
_get_trak (hb_face_t *face, hb_blob_t **blob = nullptr)
{
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
{
if (blob)
*blob = hb_blob_get_empty ();
return OT::Null(AAT::trak);
}
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
const AAT::trak& trak = *(layout->trak.get ());
if (blob)
*blob = layout->trak.blob;
return trak;
}
// static inline void
// _hb_aat_layout_create (hb_face_t *face)
// {
// OT::Sanitizer<AAT::morx> sanitizer;
// sanitizer.set_num_glyphs (face->get_num_glyphs ());
// hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX));
// OT::Sanitizer<AAT::morx>::lock_instance (morx_blob);
// if (0)
// {
// OT::Sanitizer<AAT::Lookup<OT::GlyphID> >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ());
// }
// }
void
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
{
hb_blob_t *blob;
const AAT::morx& morx = _get_morx (font->face, &blob);
AAT::hb_aat_apply_context_t c (font, buffer, blob);
morx.apply (&c);
}
void
hb_aat_layout_position (hb_font_t *font, hb_buffer_t *buffer)
{
hb_blob_t *blob;
const AAT::ankr& ankr = _get_ankr (font->face, &blob);
const AAT::kerx& kerx = _get_kerx (font->face, &blob);
const AAT::trak& trak = _get_trak (font->face, &blob);
AAT::hb_aat_apply_context_t c (font, buffer, blob);
kerx.apply (&c, &ankr);
trak.apply (&c);
}

View File

@ -70,32 +70,6 @@ typedef LONG hb_atomic_int_impl_t;
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
#elif !defined(HB_NO_MT) && defined(__APPLE__)
#include <libkern/OSAtomic.h>
#ifdef __MAC_OS_X_MIN_REQUIRED
#include <AvailabilityMacros.h>
#elif defined(__IPHONE_OS_MIN_REQUIRED)
#include <Availability.h>
#endif
typedef int32_t hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P))
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
#else
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
#endif
#endif
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
typedef int hb_atomic_int_impl_t;
@ -119,18 +93,44 @@ typedef unsigned int hb_atomic_int_impl_t;
#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
#elif !defined(HB_NO_MT) && defined(__APPLE__)
#include <libkern/OSAtomic.h>
#ifdef __MAC_OS_X_MIN_REQUIRED
#include <AvailabilityMacros.h>
#elif defined(__IPHONE_OS_MIN_REQUIRED)
#include <Availability.h>
#endif
typedef int32_t hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P))
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
#else
#if __ppc64__ || __x86_64__ || __aarch64__
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
#else
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P))
#endif
#endif
#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
#include <builtins.h>
static inline int hb_fetch_and_add(volatile int* AI, unsigned int V) {
static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) {
__lwsync();
int result = __fetch_and_add(AI, V);
__isync();
return result;
}
static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) {
__sync();
int result = __compare_and_swaplp (P, &O, N);
__sync();
@ -139,10 +139,10 @@ static inline int hb_compare_and_swaplp(volatile long* P, long O, long N) {
typedef int hb_atomic_int_impl_t;
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
#define hb_atomic_int_impl_add(AI, V) hb_fetch_and_add (&(AI), (V))
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add (&(AI), (V))
#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
#elif !defined(HB_NO_MT)

View File

@ -26,10 +26,11 @@
/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#define _POSIX_C_SOURCE 200809L
#endif
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-object-private.hh"
@ -44,12 +45,6 @@
#include <errno.h>
#ifndef HB_DEBUG_BLOB
#define HB_DEBUG_BLOB (HB_DEBUG+0)
#endif
struct hb_blob_t {
hb_object_header_t header;
ASSERT_POD ();
@ -72,8 +67,8 @@ _hb_blob_destroy_user_data (hb_blob_t *blob)
{
if (blob->destroy) {
blob->destroy (blob->user_data);
blob->user_data = NULL;
blob->destroy = NULL;
blob->user_data = nullptr;
blob->destroy = nullptr;
}
}
@ -128,6 +123,12 @@ hb_blob_create (const char *data,
return blob;
}
static void
_hb_blob_destroy (void *data)
{
hb_blob_destroy ((hb_blob_t *) data);
}
/**
* hb_blob_create_sub_blob:
* @parent: Parent blob.
@ -164,7 +165,32 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
MIN (length, parent->length - offset),
HB_MEMORY_MODE_READONLY,
hb_blob_reference (parent),
(hb_destroy_func_t) hb_blob_destroy);
_hb_blob_destroy);
return blob;
}
/**
* hb_blob_copy_writable_or_fail:
* @blob: A blob.
*
* Makes a writable copy of @blob.
*
* Return value: New blob, or nullptr if allocation failed.
*
* Since: 1.8.0
**/
hb_blob_t *
hb_blob_copy_writable_or_fail (hb_blob_t *blob)
{
blob = hb_blob_create (blob->data,
blob->length,
HB_MEMORY_MODE_DUPLICATE,
nullptr,
nullptr);
if (unlikely (blob == hb_blob_get_empty ()))
blob = nullptr;
return blob;
}
@ -188,12 +214,12 @@ hb_blob_get_empty (void)
true, /* immutable */
NULL, /* data */
nullptr, /* data */
0, /* length */
HB_MEMORY_MODE_READONLY, /* mode */
NULL, /* user_data */
NULL /* destroy */
nullptr, /* user_data */
nullptr /* destroy */
};
return const_cast<hb_blob_t *> (&_hb_blob_nil);
@ -221,7 +247,7 @@ hb_blob_reference (hb_blob_t *blob)
* hb_blob_destroy: (skip)
* @blob: a blob.
*
* Descreases the reference count on @blob, and if it reaches zero, destroys
* Decreases the reference count on @blob, and if it reaches zero, destroys
* @blob, freeing all memory, possibly calling the destroy-callback the blob
* was created for if it has not been called already.
*
@ -373,7 +399,7 @@ hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
if (length)
*length = 0;
return NULL;
return nullptr;
}
if (length)

View File

@ -44,7 +44,7 @@ HB_BEGIN_DECLS
* any such possibility, MODE_DUPLICATE should be used
* such that HarfBuzz makes a copy immediately,
*
* - Use MODE_READONLY otherse, unless you really really
* - Use MODE_READONLY otherwise, unless you really really
* really know what you are doing,
*
* - MODE_WRITABLE is appropriate if you really made a
@ -82,6 +82,9 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
unsigned int offset,
unsigned int length);
HB_EXTERN hb_blob_t *
hb_blob_copy_writable_or_fail (hb_blob_t *blob);
HB_EXTERN hb_blob_t *
hb_blob_get_empty (void);

View File

@ -0,0 +1,643 @@
#line 1 "hb-buffer-deserialize-json.rl"
/*
* Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
#define HB_BUFFER_DESERIALIZE_JSON_HH
#include "hb-private.hh"
#line 36 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 103u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u,
9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u,
120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u,
9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
65u, 122u, 34u, 122u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0
};
static const char _deserialize_json_key_spans[] = {
0, 115, 26, 7, 2, 1, 50, 49,
10, 117, 117, 117, 1, 50, 49, 10,
117, 117, 1, 1, 50, 49, 117, 117,
2, 1, 50, 49, 10, 117, 117, 1,
50, 49, 10, 117, 117, 1, 50, 49,
58, 89, 117, 117, 85, 115, 0
};
static const short _deserialize_json_index_offsets[] = {
0, 0, 116, 143, 151, 154, 156, 207,
257, 268, 386, 504, 622, 624, 675, 725,
736, 854, 972, 974, 976, 1027, 1077, 1195,
1313, 1316, 1318, 1369, 1419, 1430, 1548, 1666,
1668, 1719, 1769, 1780, 1898, 2016, 2018, 2069,
2119, 2178, 2268, 2386, 2504, 2590, 2706
};
static const char _deserialize_json_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 3, 3, 3,
3, 3, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 3, 1, 4, 1,
5, 1, 6, 7, 1, 1, 8, 1,
9, 10, 1, 11, 1, 11, 11, 11,
11, 11, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 11, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 12, 1,
12, 12, 12, 12, 12, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 12,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 13, 1, 1, 14,
15, 15, 15, 15, 15, 15, 15, 15,
15, 1, 16, 17, 17, 17, 17, 17,
17, 17, 17, 17, 1, 18, 18, 18,
18, 18, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 18, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
19, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 20, 1, 21, 21, 21, 21, 21,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 21, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 3, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 22,
1, 18, 18, 18, 18, 18, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
18, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 19, 1, 1, 1,
17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 20, 1, 23,
1, 23, 23, 23, 23, 23, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
23, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 24, 1, 24, 24, 24, 24,
24, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 24, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
25, 1, 1, 26, 27, 27, 27, 27,
27, 27, 27, 27, 27, 1, 28, 29,
29, 29, 29, 29, 29, 29, 29, 29,
1, 30, 30, 30, 30, 30, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
30, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 31, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 32, 1, 30,
30, 30, 30, 30, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 30, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 31, 1, 1, 1, 29, 29,
29, 29, 29, 29, 29, 29, 29, 29,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 32, 1, 33, 1, 34,
1, 34, 34, 34, 34, 34, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
34, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 35, 1, 35, 35, 35, 35,
35, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 35, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 36, 37, 37, 37, 37,
37, 37, 37, 37, 37, 1, 38, 38,
38, 38, 38, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 38, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 39, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 40, 1, 38, 38, 38, 38,
38, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 38, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 39,
1, 1, 1, 41, 41, 41, 41, 41,
41, 41, 41, 41, 41, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
40, 1, 42, 43, 1, 44, 1, 44,
44, 44, 44, 44, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 44, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
45, 1, 45, 45, 45, 45, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 45, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 46, 1,
1, 47, 48, 48, 48, 48, 48, 48,
48, 48, 48, 1, 49, 50, 50, 50,
50, 50, 50, 50, 50, 50, 1, 51,
51, 51, 51, 51, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 51, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 52, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 53, 1, 51, 51, 51,
51, 51, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 51, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
52, 1, 1, 1, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 53, 1, 54, 1, 54, 54, 54,
54, 54, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 54, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 55, 1,
55, 55, 55, 55, 55, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 55,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 56, 1, 1, 57,
58, 58, 58, 58, 58, 58, 58, 58,
58, 1, 59, 60, 60, 60, 60, 60,
60, 60, 60, 60, 1, 61, 61, 61,
61, 61, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 61, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
62, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 63, 1, 61, 61, 61, 61, 61,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 61, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 62, 1,
1, 1, 60, 60, 60, 60, 60, 60,
60, 60, 60, 60, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 63,
1, 64, 1, 64, 64, 64, 64, 64,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 64, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 65, 1, 65, 65,
65, 65, 65, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 65, 1, 66,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 67, 68, 68,
68, 68, 68, 68, 68, 68, 68, 1,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 1, 1, 1, 1, 1, 1,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
69, 69, 1, 70, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 71, 71,
1, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 1, 1, 1, 1, 1,
1, 1, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 1, 1, 1, 1,
71, 1, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 71, 71, 71, 71,
71, 71, 71, 71, 1, 72, 72, 72,
72, 72, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 72, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
73, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 74, 1, 72, 72, 72, 72, 72,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 72, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 73, 1,
1, 1, 75, 75, 75, 75, 75, 75,
75, 75, 75, 75, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 74,
1, 76, 76, 76, 76, 76, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
76, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 77, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 78, 1, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 1, 1, 0
};
static const char _deserialize_json_trans_targs[] = {
1, 0, 2, 2, 3, 4, 18, 24,
37, 5, 12, 6, 7, 8, 9, 11,
9, 11, 10, 2, 44, 10, 44, 13,
14, 15, 16, 17, 16, 17, 10, 2,
44, 19, 20, 21, 22, 23, 10, 2,
44, 23, 25, 31, 26, 27, 28, 29,
30, 29, 30, 10, 2, 44, 32, 33,
34, 35, 36, 35, 36, 10, 2, 44,
38, 39, 40, 42, 43, 41, 10, 41,
10, 2, 44, 43, 44, 45, 46
};
static const char _deserialize_json_trans_actions[] = {
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 2, 2, 2,
0, 0, 3, 3, 4, 0, 5, 0,
0, 2, 2, 2, 0, 0, 6, 6,
7, 0, 0, 0, 2, 2, 8, 8,
9, 0, 0, 0, 0, 0, 2, 2,
2, 0, 0, 10, 10, 11, 0, 0,
2, 2, 2, 0, 0, 12, 12, 13,
0, 0, 0, 2, 2, 2, 14, 0,
15, 15, 16, 0, 0, 0, 0
};
static const int deserialize_json_start = 1;
static const int deserialize_json_first_final = 44;
static const int deserialize_json_error = 0;
static const int deserialize_json_en_main = 1;
#line 97 "hb-buffer-deserialize-json.rl"
static hb_bool_t
_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? ',' : '['))
{
*end_ptr = ++p;
}
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
#line 466 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
#line 471 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_json_trans_keys + (cs<<1);
_inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs];
_slen = _deserialize_json_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_json_trans_targs[_trans];
if ( _deserialize_json_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_json_trans_actions[_trans] ) {
case 1:
#line 38 "hb-buffer-deserialize-json.rl"
{
memset (&info, 0, sizeof (info));
memset (&pos , 0, sizeof (pos ));
}
break;
case 5:
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 2:
#line 51 "hb-buffer-deserialize-json.rl"
{
tok = p;
}
break;
case 14:
#line 55 "hb-buffer-deserialize-json.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 15:
#line 62 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
break;
case 8:
#line 63 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 10:
#line 64 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 12:
#line 65 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 3:
#line 66 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 6:
#line 67 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
break;
case 16:
#line 62 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 63 "hb-buffer-deserialize-json.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 64 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 13:
#line 65 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 4:
#line 66 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 7:
#line 67 "hb-buffer-deserialize-json.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-json.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 624 "hb-buffer-deserialize-json.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
_out: {}
}
#line 125 "hb-buffer-deserialize-json.rl"
*end_ptr = p;
return p == pe && *(p-1) != ']';
}
#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */

View File

@ -106,7 +106,7 @@ _hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
const char *p = buf, *pe = buf + buf_len;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, NULL);
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
@ -115,7 +115,7 @@ _hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
*end_ptr = ++p;
}
const char *tok = NULL;
const char *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};

View File

@ -0,0 +1,571 @@
#line 1 "hb-buffer-deserialize-text.rl"
/*
* Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
#define HB_BUFFER_DESERIALIZE_TEXT_HH
#include "hb-private.hh"
#line 36 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u,
9u, 122u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 9u, 124u, 9u, 124u, 0
};
static const char _deserialize_text_key_spans[] = {
0, 114, 13, 10, 13, 10, 10, 13,
10, 1, 13, 10, 14, 116, 116, 0,
114, 116, 116, 116, 116, 116, 116, 116,
116, 116, 116
};
static const short _deserialize_text_index_offsets[] = {
0, 0, 115, 129, 140, 154, 165, 176,
190, 201, 203, 217, 228, 243, 360, 477,
478, 593, 710, 827, 944, 1061, 1178, 1295,
1412, 1529, 1646
};
static const char _deserialize_text_indicies[] = {
0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 1, 1, 1, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 1, 1, 1, 1, 1,
1, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 1, 5, 1, 1, 6,
7, 7, 7, 7, 7, 7, 7, 7,
7, 1, 8, 9, 9, 9, 9, 9,
9, 9, 9, 9, 1, 10, 1, 1,
11, 12, 12, 12, 12, 12, 12, 12,
12, 12, 1, 13, 14, 14, 14, 14,
14, 14, 14, 14, 14, 1, 15, 16,
16, 16, 16, 16, 16, 16, 16, 16,
1, 17, 1, 1, 18, 19, 19, 19,
19, 19, 19, 19, 19, 19, 1, 20,
21, 21, 21, 21, 21, 21, 21, 21,
21, 1, 22, 1, 23, 1, 1, 24,
25, 25, 25, 25, 25, 25, 25, 25,
25, 1, 26, 27, 27, 27, 27, 27,
27, 27, 27, 27, 1, 22, 1, 1,
1, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 1, 28, 28, 28, 28,
28, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 28, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 29, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
30, 1, 1, 31, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
32, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 33,
1, 34, 34, 34, 34, 34, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
34, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 35, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 36, 1, 1, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 2, 3,
3, 3, 3, 3, 3, 3, 3, 3,
1, 1, 1, 1, 1, 1, 1, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 1, 1, 1, 1, 1, 1, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4,
4, 1, 28, 28, 28, 28, 28, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 28, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 29, 1, 1, 1,
1, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 1, 1, 1, 30, 1,
1, 31, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 32, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 33, 1, 38,
38, 38, 38, 38, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 38, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 39, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 40, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 41, 1, 42, 42, 42, 42,
42, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 42, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
43, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 44,
1, 42, 42, 42, 42, 42, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
42, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 43, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 44, 1, 38, 38,
38, 38, 38, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 38, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 39, 1, 1, 1, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 40, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 41, 1, 45, 45, 45, 45, 45,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 45, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 46, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 47, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 48,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 49, 1,
50, 50, 50, 50, 50, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 50,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 51, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 52, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 53, 1, 50, 50, 50,
50, 50, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 50, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 51,
1, 1, 1, 1, 27, 27, 27, 27,
27, 27, 27, 27, 27, 27, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 52, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
53, 1, 45, 45, 45, 45, 45, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 45, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 46, 1, 1, 1,
1, 54, 54, 54, 54, 54, 54, 54,
54, 54, 54, 1, 1, 1, 1, 1,
1, 47, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 48, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 49, 1, 28,
28, 28, 28, 28, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 28, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 29, 1, 55, 55, 1, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
1, 1, 1, 30, 1, 1, 31, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 1, 1, 32, 1, 55, 1, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 55, 55, 55, 55, 55, 55, 55,
55, 1, 33, 1, 0
};
static const char _deserialize_text_trans_targs[] = {
1, 0, 13, 17, 26, 3, 18, 21,
18, 21, 5, 19, 20, 19, 20, 22,
25, 8, 9, 12, 9, 12, 10, 11,
23, 24, 23, 24, 14, 2, 6, 7,
15, 16, 14, 15, 16, 17, 14, 4,
15, 16, 14, 15, 16, 14, 2, 7,
15, 16, 14, 2, 15, 16, 25, 26
};
static const char _deserialize_text_trans_actions[] = {
0, 0, 1, 1, 1, 2, 2, 2,
0, 0, 2, 2, 2, 0, 0, 2,
2, 2, 2, 2, 0, 0, 3, 2,
2, 2, 0, 0, 4, 5, 5, 5,
4, 4, 0, 0, 0, 0, 6, 7,
6, 6, 8, 8, 8, 9, 10, 10,
9, 9, 11, 12, 11, 11, 0, 0
};
static const char _deserialize_text_eof_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 4, 0, 0,
0, 4, 6, 8, 8, 6, 9, 11,
11, 9, 4
};
static const int deserialize_text_start = 1;
static const int deserialize_text_first_final = 13;
static const int deserialize_text_error = 0;
static const int deserialize_text_en_main = 1;
#line 91 "hb-buffer-deserialize-text.rl"
static hb_bool_t
_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
const char *buf,
unsigned int buf_len,
const char **end_ptr,
hb_font_t *font)
{
const char *p = buf, *pe = buf + buf_len;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
if (p < pe && *p == (buffer->len ? '|' : '['))
{
*end_ptr = ++p;
}
const char *eof = pe, *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
#line 343 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
#line 348 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
if ( cs == 0 )
goto _out;
_resume:
_keys = _deserialize_text_trans_keys + (cs<<1);
_inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs];
_slen = _deserialize_text_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
(*p) <= _keys[1] ?
(*p) - _keys[0] : _slen ];
cs = _deserialize_text_trans_targs[_trans];
if ( _deserialize_text_trans_actions[_trans] == 0 )
goto _again;
switch ( _deserialize_text_trans_actions[_trans] ) {
case 2:
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 5:
#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
break;
case 10:
#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 3:
#line 63 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 12:
#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 7:
#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 1:
#line 38 "hb-buffer-deserialize-text.rl"
{
memset (&info, 0, sizeof (info));
memset (&pos , 0, sizeof (pos ));
}
#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 4:
#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 6:
#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 8:
#line 66 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 480 "hb-buffer-deserialize-text.hh"
}
_again:
if ( cs == 0 )
goto _out;
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
switch ( _deserialize_text_eof_actions[cs] ) {
case 4:
#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 9:
#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 11:
#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 6:
#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
case 8:
#line 66 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
return false;
buffer->pos[buffer->len - 1] = pos;
*end_ptr = p;
}
break;
#line 557 "hb-buffer-deserialize-text.hh"
}
}
_out: {}
}
#line 119 "hb-buffer-deserialize-text.rl"
*end_ptr = p;
return p == pe && *(p-1) != ']';
}
#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */

View File

@ -100,7 +100,7 @@ _hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
const char *p = buf, *pe = buf + buf_len;
/* Ensure we have positions. */
(void) hb_buffer_get_glyph_positions (buffer, NULL);
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
while (p < pe && ISSPACE (*p))
p++;
@ -109,7 +109,7 @@ _hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
*end_ptr = ++p;
}
const char *eof = pe, *tok = NULL;
const char *eof = pe, *tok = nullptr;
int cs;
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};

View File

@ -35,8 +35,8 @@
#include "hb-unicode-private.hh"
#ifndef HB_BUFFER_MAX_EXPANSION_FACTOR
#define HB_BUFFER_MAX_EXPANSION_FACTOR 32
#ifndef HB_BUFFER_MAX_LEN_FACTOR
#define HB_BUFFER_MAX_LEN_FACTOR 32
#endif
#ifndef HB_BUFFER_MAX_LEN_MIN
#define HB_BUFFER_MAX_LEN_MIN 8192
@ -45,11 +45,22 @@
#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
#endif
ASSERT_STATIC (sizeof (hb_glyph_info_t) == 20);
ASSERT_STATIC (sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t));
#ifndef HB_BUFFER_MAX_OPS_FACTOR
#define HB_BUFFER_MAX_OPS_FACTOR 64
#endif
#ifndef HB_BUFFER_MAX_OPS_MIN
#define HB_BUFFER_MAX_OPS_MIN 1024
#endif
#ifndef HB_BUFFER_MAX_OPS_DEFAULT
#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
#endif
static_assert ((sizeof (hb_glyph_info_t) == 20), "");
static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
HB_MARK_AS_FLAG_T (hb_buffer_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_serialize_flags_t);
HB_MARK_AS_FLAG_T (hb_buffer_diff_flags_t);
enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_DEFAULT = 0x00000000u,
@ -57,6 +68,9 @@ enum hb_buffer_scratch_flags_t {
HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u,
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u,
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u,
/* Reserved for complex shapers' internal use. */
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
HB_BUFFER_SCRATCH_FLAG_COMPLEX1 = 0x02000000u,
@ -79,8 +93,9 @@ struct hb_buffer_t {
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
hb_buffer_cluster_level_t cluster_level;
hb_codepoint_t replacement; /* U+FFFD or something else. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
/* Buffer contents */
hb_buffer_content_type_t content_type;
@ -99,17 +114,6 @@ struct hb_buffer_t {
hb_glyph_info_t *out_info;
hb_glyph_position_t *pos;
inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
inline bool has_separate_output (void) const { return info != out_info; }
unsigned int serial;
/* Text before / after the main buffer contents.
@ -129,12 +133,16 @@ struct hb_buffer_t {
#ifndef HB_NDEBUG
uint8_t allocated_var_bits;
#endif
/* Methods */
inline void allocate_var (unsigned int start, unsigned int count)
{
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1<<end) - (1<<start);
unsigned int bits = (1u<<end) - (1u<<start);
assert (0 == (allocated_var_bits & bits));
allocated_var_bits |= bits;
#endif
@ -144,7 +152,7 @@ struct hb_buffer_t {
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1<<end) - (1<<start);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
allocated_var_bits &= ~bits;
#endif
@ -154,7 +162,7 @@ struct hb_buffer_t {
#ifndef HB_NDEBUG
unsigned int end = start + count;
assert (end <= 8);
unsigned int bits = (1<<end) - (1<<start);
unsigned int bits = (1u<<end) - (1u<<start);
assert (bits == (allocated_var_bits & bits));
#endif
}
@ -165,8 +173,17 @@ struct hb_buffer_t {
#endif
}
inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
inline bool has_separate_output (void) const { return info != out_info; }
/* Methods */
HB_INTERNAL void reset (void);
HB_INTERNAL void clear (void);
@ -232,25 +249,31 @@ struct hb_buffer_t {
for (unsigned int j = 0; j < len; j++)
info[j].mask |= mask;
}
HB_INTERNAL void set_masks (hb_mask_t value,
hb_mask_t mask,
unsigned int cluster_start,
unsigned int cluster_end);
HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
unsigned int cluster_start, unsigned int cluster_end);
HB_INTERNAL void merge_clusters (unsigned int start,
unsigned int end)
inline void merge_clusters (unsigned int start, unsigned int end)
{
if (end - start < 2)
return;
merge_clusters_impl (start, end);
}
HB_INTERNAL void merge_clusters_impl (unsigned int start,
unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start,
unsigned int end);
HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
/* Merge clusters for deleting current glyph, and skip it. */
HB_INTERNAL void delete_glyph (void);
inline void unsafe_to_break (unsigned int start,
unsigned int end)
{
if (end - start < 2)
return;
unsafe_to_break_impl (start, end);
}
HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end);
HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end);
/* Internal methods */
HB_INTERNAL bool enlarge (unsigned int size);
@ -282,9 +305,78 @@ struct hb_buffer_t {
return ret;
}
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
static inline void
set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
{
if (inf.cluster != cluster)
{
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
else
inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
inf.cluster = cluster;
}
inline int
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
unsigned int start, unsigned int end,
unsigned int cluster) const
{
for (unsigned int i = start; i < end; i++)
cluster = MIN<unsigned int> (cluster, infos[i].cluster);
return cluster;
}
inline void
_unsafe_to_break_set_mask (hb_glyph_info_t *infos,
unsigned int start, unsigned int end,
unsigned int cluster)
{
for (unsigned int i = start; i < end; i++)
if (cluster != infos[i].cluster)
{
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
}
inline void
unsafe_to_break_all (void)
{
unsafe_to_break_impl (0, len);
}
inline void
safe_to_break_all (void)
{
for (unsigned int i = 0; i < len; i++)
info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
}
};
/* Loop over clusters. Duplicated in foreach_syllable(). */
#define foreach_cluster(buffer, start, end) \
for (unsigned int \
_count = buffer->len, \
start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \
start < _count; \
start = end, end = _next_cluster (buffer, start))
static inline unsigned int
_next_cluster (hb_buffer_t *buffer, unsigned int start)
{
hb_glyph_info_t *info = buffer->info;
unsigned int count = buffer->len;
unsigned int cluster = info[start].cluster;
while (++start < count && cluster == info[start].cluster)
;
return start;
}
#define HB_BUFFER_XALLOCATE_VAR(b, func, var) \
b->func (offsetof (hb_glyph_info_t, var) - offsetof(hb_glyph_info_t, var1), \
sizeof (b->info[0].var))

View File

@ -30,7 +30,7 @@
static const char *serialize_formats[] = {
"text",
"json",
NULL
nullptr
};
/**
@ -90,7 +90,7 @@ hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
default:
case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return NULL;
case HB_BUFFER_SERIALIZE_FORMAT_INVALID: return nullptr;
}
}
@ -104,11 +104,12 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
NULL : hb_buffer_get_glyph_positions (buffer, NULL);
nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
*buf_consumed = 0;
hb_position_t x = 0, y = 0;
for (unsigned int i = start; i < end; i++)
{
char b[1024];
@ -145,10 +146,17 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
pos[i].x_offset, pos[i].y_offset);
p += snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
pos[i].x_advance, pos[i].y_advance);
p += 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",
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));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
@ -156,9 +164,9 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
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",
extents.x_bearing, extents.y_bearing));
extents.x_bearing, extents.y_bearing));
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
extents.width, extents.height));
extents.width, extents.height));
}
*p++ = '}';
@ -173,6 +181,12 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
*buf = '\0';
} else
return i - start;
if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
{
x += pos[i].x_advance;
y += pos[i].y_advance;
}
}
return end - start;
@ -188,11 +202,12 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
hb_font_t *font,
hb_buffer_serialize_flags_t flags)
{
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, NULL);
hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, nullptr);
hb_glyph_position_t *pos = (flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS) ?
NULL : hb_buffer_get_glyph_positions (buffer, NULL);
nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
*buf_consumed = 0;
hb_position_t x = 0, y = 0;
for (unsigned int i = start; i < end; i++)
{
char b[1024];
@ -217,13 +232,22 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
{
if (pos[i].x_offset || pos[i].y_offset)
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
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++ = '+';
p += 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));
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
{
*p++ = '+';
p += 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));
}
}
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));
}
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
@ -243,6 +267,12 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
*buf = '\0';
} else
return i - start;
if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
{
x += pos[i].x_advance;
y += pos[i].y_advance;
}
}
return end - start;
@ -311,6 +341,8 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
if (!buf_consumed)
buf_consumed = &sconsumed;
*buf_consumed = 0;
if (buf_size)
*buf = '\0';
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
@ -408,8 +440,8 @@ hb_bool_t
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
const char *buf,
int buf_len, /* -1 means nul-terminated */
const char **end_ptr, /* May be NULL */
hb_font_t *font, /* May be NULL */
const char **end_ptr, /* May be nullptr */
hb_font_t *font, /* May be nullptr */
hb_buffer_serialize_format_t format)
{
const char *end;

View File

@ -31,10 +31,6 @@
#include "hb-utf-private.hh"
#ifndef HB_DEBUG_BUFFER
#define HB_DEBUG_BUFFER (HB_DEBUG+0)
#endif
/**
* SECTION: hb-buffer
* @title: Buffers
@ -52,7 +48,7 @@
*
* Checks the equality of two #hb_segment_properties_t's.
*
* Return value: (transfer full):
* Return value:
* %true if all properties of @a equal those of @b, false otherwise.
*
* Since: 0.9.7
@ -124,8 +120,8 @@ hb_buffer_t::enlarge (unsigned int size)
}
unsigned int new_allocated = allocated;
hb_glyph_position_t *new_pos = NULL;
hb_glyph_info_t *new_info = NULL;
hb_glyph_position_t *new_pos = nullptr;
hb_glyph_info_t *new_info = nullptr;
bool separate_out = out_info != info;
if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
@ -134,7 +130,7 @@ hb_buffer_t::enlarge (unsigned int size)
while (size >= new_allocated)
new_allocated += (new_allocated >> 1) + 32;
ASSERT_STATIC (sizeof (info[0]) == sizeof (pos[0]));
static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
goto done;
@ -183,6 +179,12 @@ hb_buffer_t::shift_forward (unsigned int count)
if (unlikely (!ensure (len + count))) return false;
memmove (info + idx + count, info + idx, (len - idx) * sizeof (info[0]));
if (idx + count > len)
{
/* Under memory failure we might expose this area. At least
* clean it up. Oh well... */
memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
}
len += count;
idx += count;
@ -261,7 +263,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint,
memset (glyph, 0, sizeof (*glyph));
glyph->codepoint = codepoint;
glyph->mask = 1;
glyph->mask = 0;
glyph->cluster = cluster;
len++;
@ -426,6 +428,8 @@ hb_buffer_t::move_to (unsigned int i)
/* Tricky part: rewinding... */
unsigned int count = out_len - i;
/* This will blow in our face if memory allocation fails later
* in this same lookup... */
if (unlikely (idx < count && !shift_forward (count + 32))) return false;
assert (idx >= count);
@ -542,12 +546,15 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
unsigned int end)
{
if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
{
unsafe_to_break (start, end);
return;
}
unsigned int cluster = info[start].cluster;
for (unsigned int i = start + 1; i < end; i++)
cluster = MIN (cluster, info[i].cluster);
cluster = MIN<unsigned int> (cluster, info[i].cluster);
/* Extend end */
while (end < len && info[end - 1].cluster == info[end].cluster)
@ -560,10 +567,10 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
/* If we hit the start of buffer, continue in out-buffer. */
if (idx == start)
for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
out_info[i - 1].cluster = cluster;
set_cluster (out_info[i - 1], cluster);
for (unsigned int i = start; i < end; i++)
info[i].cluster = cluster;
set_cluster (info[i], cluster);
}
void
hb_buffer_t::merge_out_clusters (unsigned int start,
@ -578,7 +585,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 (cluster, out_info[i].cluster);
cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
/* Extend start */
while (start && out_info[start - 1].cluster == out_info[start].cluster)
@ -591,14 +598,16 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
/* If we hit the end of out-buffer, continue in buffer. */
if (end == out_len)
for (unsigned int i = idx; i < len && info[i].cluster == out_info[end - 1].cluster; i++)
info[i].cluster = cluster;
set_cluster (info[i], cluster);
for (unsigned int i = start; i < end; i++)
out_info[i].cluster = cluster;
set_cluster (out_info[i], cluster);
}
void
hb_buffer_t::delete_glyph ()
{
/* The logic here is duplicated in hb_ot_hide_default_ignorables(). */
unsigned int cluster = info[idx].cluster;
if (idx + 1 < len && cluster == info[idx + 1].cluster)
{
@ -611,9 +620,10 @@ hb_buffer_t::delete_glyph ()
/* Merge cluster backward. */
if (cluster < out_info[out_len - 1].cluster)
{
unsigned int mask = info[idx].mask;
unsigned int old_cluster = out_info[out_len - 1].cluster;
for (unsigned i = out_len; i && out_info[i - 1].cluster == old_cluster; i--)
out_info[i - 1].cluster = cluster;
set_cluster (out_info[i - 1], cluster, mask);
}
goto done;
}
@ -629,6 +639,32 @@ done:
skip_glyph ();
}
void
hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
{
unsigned int cluster = (unsigned int) -1;
cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
_unsafe_to_break_set_mask (info, start, end, cluster);
}
void
hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end)
{
if (!have_output)
{
unsafe_to_break_impl (start, end);
return;
}
assert (start <= out_len);
assert (idx <= end);
unsigned int cluster = (unsigned int) -1;
cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
_unsafe_to_break_set_mask (out_info, start, out_len, cluster);
_unsafe_to_break_set_mask (info, idx, end, cluster);
}
void
hb_buffer_t::guess_segment_properties (void)
{
@ -686,6 +722,7 @@ hb_buffer_create (void)
return hb_buffer_get_empty ();
buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT;
buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT;
buffer->reset ();
@ -713,6 +750,7 @@ hb_buffer_get_empty (void)
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
HB_BUFFER_MAX_LEN_DEFAULT,
HB_BUFFER_MAX_OPS_DEFAULT,
HB_BUFFER_CONTENT_TYPE_INVALID,
HB_SEGMENT_PROPERTIES_DEFAULT,
@ -1371,6 +1409,23 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
return (hb_glyph_position_t *) buffer->pos;
}
/**
* hb_glyph_info_get_glyph_flags:
* @info: a #hb_glyph_info_t.
*
* Returns glyph flags encoded within a #hb_glyph_info_t.
*
* Return value:
* The #hb_glyph_flags_t encoded within @info.
*
* Since: 1.5.0
**/
hb_glyph_flags_t
(hb_glyph_info_get_glyph_flags) (const hb_glyph_info_t *info)
{
return hb_glyph_info_get_glyph_flags (info);
}
/**
* hb_buffer_reverse:
* @buffer: an #hb_buffer_t.
@ -1658,6 +1713,58 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
}
/**
* hb_buffer_append:
* @buffer: an #hb_buffer_t.
* @source: source #hb_buffer_t.
* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.
* @end: end index into source buffer to copy. Use (unsigned int) -1 to copy to end of buffer.
*
* Append (part of) contents of another buffer to this buffer.
*
* Since: 1.5.0
**/
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
hb_buffer_t *source,
unsigned int start,
unsigned int end)
{
assert (!buffer->have_output && !source->have_output);
assert (buffer->have_positions == source->have_positions ||
!buffer->len || !source->len);
assert (buffer->content_type == source->content_type ||
!buffer->len || !source->len);
if (end > source->len)
end = source->len;
if (start > end)
start = end;
if (start == end)
return;
if (!buffer->len)
buffer->content_type = source->content_type;
if (!buffer->have_positions && source->have_positions)
buffer->clear_positions ();
if (buffer->len + (end - start) < buffer->len) /* Overflows. */
{
buffer->in_error = true;
return;
}
unsigned int orig_len = buffer->len;
hb_buffer_set_length (buffer, buffer->len + (end - start));
if (buffer->in_error)
return;
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
}
static int
compare_info_codepoint (const hb_glyph_info_t *pa,
const hb_glyph_info_t *pb)
@ -1728,7 +1835,8 @@ void
hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
{
assert (buffer->have_positions);
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
@ -1767,6 +1875,98 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
}
}
/*
* Comparing buffers.
*/
/**
* hb_buffer_diff:
*
* If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
* and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
* callers if just comparing two buffers is needed.
*
* Since: 1.5.0
**/
hb_buffer_diff_flags_t
hb_buffer_diff (hb_buffer_t *buffer,
hb_buffer_t *reference,
hb_codepoint_t dottedcircle_glyph,
unsigned int position_fuzz)
{
if (buffer->content_type != reference->content_type && buffer->len && reference->len)
return HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH;
hb_buffer_diff_flags_t result = HB_BUFFER_DIFF_FLAG_EQUAL;
bool contains = dottedcircle_glyph != (hb_codepoint_t) -1;
unsigned int count = reference->len;
if (buffer->len != count)
{
/*
* we can't compare glyph-by-glyph, but we do want to know if there
* are .notdef or dottedcircle glyphs present in the reference buffer
*/
const hb_glyph_info_t *info = reference->info;
unsigned int i;
for (i = 0; i < count; i++)
{
if (contains && info[i].codepoint == dottedcircle_glyph)
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
if (contains && info[i].codepoint == 0)
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
}
result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
return hb_buffer_diff_flags_t (result);
}
if (!count)
return hb_buffer_diff_flags_t (result);
const hb_glyph_info_t *buf_info = buffer->info;
const hb_glyph_info_t *ref_info = reference->info;
for (unsigned int i = 0; i < count; i++)
{
if (buf_info->codepoint != ref_info->codepoint)
result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
if (buf_info->cluster != ref_info->cluster)
result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))
result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
if (contains && ref_info->codepoint == dottedcircle_glyph)
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
if (contains && ref_info->codepoint == 0)
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
buf_info++;
ref_info++;
}
if (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)
{
assert (buffer->have_positions);
const hb_glyph_position_t *buf_pos = buffer->pos;
const hb_glyph_position_t *ref_pos = reference->pos;
for (unsigned int i = 0; i < count; i++)
{
if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
{
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
break;
}
buf_pos++;
ref_pos++;
}
}
return result;
}
/*
* Debugging.
*/
@ -1795,9 +1995,9 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
buffer->message_data = user_data;
buffer->message_destroy = destroy;
} else {
buffer->message_func = NULL;
buffer->message_data = NULL;
buffer->message_destroy = NULL;
buffer->message_func = nullptr;
buffer->message_data = nullptr;
buffer->message_destroy = nullptr;
}
}

View File

@ -63,7 +63,7 @@ HB_BEGIN_DECLS
*/
typedef struct hb_glyph_info_t {
hb_codepoint_t codepoint;
hb_mask_t mask;
hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */
uint32_t cluster;
/*< private >*/
@ -71,6 +71,37 @@ typedef struct hb_glyph_info_t {
hb_var_int_t var2;
} hb_glyph_info_t;
/**
* hb_glyph_flags_t:
* @HB_GLYPH_FLAG_UNSAFE_TO_BREAK: Indicates that if input text is broken at the
* beginning of the cluster this glyph is part of,
* then both sides need to be re-shaped, as the
* result might be different. On the flip side,
* it means that when this flag is not present,
* then it's safe to break the glyph-run at the
* beginning of this cluster, and the two sides
* represent the exact same result one would get
* if breaking input text at the beginning of
* this cluster and shaping the two sides
* separately. This can be used to optimize
* paragraph layout, by avoiding re-shaping
* of each line after line-breaking, or limiting
* the reshaping to a small piece around the
* breaking point only.
*/
typedef enum { /*< flags >*/
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t
hb_glyph_info_get_glyph_flags (const hb_glyph_info_t *info);
#define hb_glyph_info_get_glyph_flags(info) \
((hb_glyph_flags_t) ((unsigned int) (info)->mask & HB_GLYPH_FLAG_DEFINED))
/**
* hb_glyph_position_t:
* @x_advance: how much the line advances after drawing this glyph when setting
@ -119,8 +150,8 @@ typedef struct hb_segment_properties_t {
#define HB_SEGMENT_PROPERTIES_DEFAULT {HB_DIRECTION_INVALID, \
HB_SCRIPT_INVALID, \
HB_LANGUAGE_INVALID, \
NULL, \
NULL}
(void *) 0, \
(void *) 0}
HB_EXTERN hb_bool_t
hb_segment_properties_equal (const hb_segment_properties_t *a,
@ -163,6 +194,7 @@ HB_EXTERN void *
hb_buffer_get_user_data (hb_buffer_t *buffer,
hb_user_data_key_t *key);
/**
* hb_buffer_content_type_t:
* @HB_BUFFER_CONTENT_TYPE_INVALID: Initial value for new buffer.
@ -233,13 +265,21 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* of the text without the full context.
* @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
* paragraph can be applied to this buffer, similar to
* @HB_BUFFER_FLAG_EOT.
* @HB_BUFFER_FLAG_BOT.
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
* flag indication that character with Default_Ignorable
* Unicode property should use the corresponding glyph
* from the font, instead of hiding them (currently done
* by replacing them with the space glyph and zeroing the
* advance width.)
* from the font, instead of hiding them (done by
* replacing them with the space glyph and zeroing the
* advance width.) This flag takes precedence over
* @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES.
* @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES:
* flag indication that character with Default_Ignorable
* Unicode property should be removed from glyph string
* instead of hiding them (done by replacing them with the
* space glyph and zeroing the advance width.)
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
* precedence over this flag. Since: 1.8.0
*
* Since: 0.9.20
*/
@ -247,7 +287,8 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_DEFAULT = 0x00000000u,
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_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u
} hb_buffer_flags_t;
HB_EXTERN void
@ -359,6 +400,11 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
unsigned int item_offset,
int item_length);
HB_EXTERN void
hb_buffer_append (hb_buffer_t *buffer,
hb_buffer_t *source,
unsigned int start,
unsigned int end);
HB_EXTERN hb_bool_t
hb_buffer_set_length (hb_buffer_t *buffer,
@ -393,6 +439,9 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
* @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
* @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0
* @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances,
* glyph offsets will reflect absolute glyph positions. Since: 1.8.0
*
* Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
*
@ -403,7 +452,9 @@ typedef enum { /*< flags >*/
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u,
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u,
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u,
HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u
} hb_buffer_serialize_flags_t;
/**
@ -452,6 +503,45 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
hb_buffer_serialize_format_t format);
/*
* Compare buffers
*/
typedef enum { /*< flags >*/
HB_BUFFER_DIFF_FLAG_EQUAL = 0x0000,
/* Buffers with different content_type cannot be meaningfully compared
* in any further detail. */
HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH = 0x0001,
/* For buffers with differing length, the per-glyph comparison is not
* attempted, though we do still scan reference for dottedcircle / .notdef
* glyphs. */
HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH = 0x0002,
/* We want to know if dottedcircle / .notdef glyphs are present in the
* reference, as we may not care so much about other differences in this
* case. */
HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT = 0x0004,
HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT = 0x0008,
/* If the buffers have the same length, we compare them glyph-by-glyph
* and report which aspect(s) of the glyph info/position are different. */
HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH = 0x0010,
HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH = 0x0020,
HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH = 0x0040,
HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH = 0x0080
} hb_buffer_diff_flags_t;
/* Compare the contents of two buffers, report types of differences. */
HB_EXTERN hb_buffer_diff_flags_t
hb_buffer_diff (hb_buffer_t *buffer,
hb_buffer_t *reference,
hb_codepoint_t dottedcircle_glyph,
unsigned int position_fuzz);
/*
* Debugging.
*/

View File

@ -1,74 +0,0 @@
/*
* Copyright © 2012 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_CACHE_PRIVATE_HH
#define HB_CACHE_PRIVATE_HH
#include "hb-private.hh"
/* Implements a lock-free cache for int->int functions. */
template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
struct hb_cache_t
{
ASSERT_STATIC (key_bits >= cache_bits);
ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int));
inline void clear (void)
{
memset (values, 255, sizeof (values));
}
inline bool get (unsigned int key, unsigned int *value)
{
unsigned int k = key & ((1<<cache_bits)-1);
unsigned int v = values[k];
if ((v >> value_bits) != (key >> cache_bits))
return false;
*value = v & ((1<<value_bits)-1);
return true;
}
inline bool set (unsigned int key, unsigned int value)
{
if (unlikely ((key >> key_bits) || (value >> value_bits)))
return false; /* Overflows */
unsigned int k = key & ((1<<cache_bits)-1);
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
values[k] = v;
return true;
}
private:
unsigned int values[1<<cache_bits];
};
typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
#endif /* HB_CACHE_PRIVATE_HH */

View File

@ -32,6 +32,9 @@
#include "hb-object-private.hh"
#include <locale.h>
#ifdef HAVE_XLOCALE_H
#include <xlocale.h>
#endif
/* hb_options_t */
@ -82,13 +85,13 @@ hb_tag_from_string (const char *str, int len)
for (; i < 4; i++)
tag[i] = ' ';
return HB_TAG_CHAR4 (tag);
return HB_TAG (tag[0], tag[1], tag[2], tag[3]);
}
/**
* hb_tag_to_string:
* @tag:
* @buf: (array fixed-size=4):
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
*
*
*
@ -186,8 +189,10 @@ lang_equal (hb_language_t v1,
const unsigned char *p1 = (const unsigned char *) v1;
const unsigned char *p2 = (const unsigned char *) v2;
while (*p1 && *p1 == canon_map[*p2])
p1++, p2++;
while (*p1 && *p1 == canon_map[*p2]) {
p1++;
p2++;
}
return *p1 == canon_map[*p2];
}
@ -219,9 +224,18 @@ struct hb_language_item_t {
}
inline hb_language_item_t & operator = (const char *s) {
lang = (hb_language_t) strdup (s);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
/* If a custom allocated is used calling strdup() pairs
badly with a call to the custom free() in finish() below.
Therefore don't call strdup(), implement its behavior.
*/
size_t len = strlen(s) + 1;
lang = (hb_language_t) malloc(len);
if (likely (lang))
{
memcpy((unsigned char *) lang, s, len);
for (unsigned char *p = (unsigned char *) lang; *p; p++)
*p = canon_map[*p];
}
return *this;
}
@ -235,8 +249,8 @@ struct hb_language_item_t {
static hb_language_item_t *langs;
#ifdef HB_USE_ATEXIT
static
void free_langs (void)
static void
free_langs (void)
{
while (langs) {
hb_language_item_t *next = langs->next;
@ -260,9 +274,14 @@ retry:
/* Not found; allocate one. */
hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
if (unlikely (!lang))
return NULL;
return nullptr;
lang->next = first_lang;
*lang = key;
if (unlikely (!lang->lang))
{
free (lang);
return nullptr;
}
if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
lang->finish ();
@ -299,7 +318,7 @@ hb_language_from_string (const char *str, int len)
if (!str || !len || !*str)
return HB_LANGUAGE_INVALID;
hb_language_item_t *item = NULL;
hb_language_item_t *item = nullptr;
if (len >= 0)
{
/* NUL-terminate it. */
@ -330,7 +349,7 @@ hb_language_from_string (const char *str, int len)
const char *
hb_language_to_string (hb_language_t language)
{
/* This is actually NULL-safe! */
/* This is actually nullptr-safe! */
return language->s;
}
@ -350,7 +369,7 @@ hb_language_get_default (void)
hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
if (unlikely (language == HB_LANGUAGE_INVALID)) {
language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
(void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
}
@ -505,6 +524,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_PSALTER_PAHLAVI:
/* Unicode-8.0 additions */
case HB_SCRIPT_HATRAN:
case HB_SCRIPT_OLD_HUNGARIAN:
/* Unicode-9.0 additions */
@ -543,9 +563,9 @@ hb_user_data_array_t::set (hb_user_data_key_t *key,
void *
hb_user_data_array_t::get (hb_user_data_key_t *key)
{
hb_user_data_item_t item = {NULL, NULL, NULL};
hb_user_data_item_t item = {nullptr, nullptr, nullptr};
return items.find (key, &item, lock) ? item.data : NULL;
return items.find (key, &item, lock) ? item.data : nullptr;
}
@ -605,3 +625,426 @@ hb_version_atleast (unsigned int major,
{
return HB_VERSION_ATLEAST (major, minor, micro);
}
/* hb_feature_t and hb_variation_t */
static bool
parse_space (const char **pp, const char *end)
{
while (*pp < end && ISSPACE (**pp))
(*pp)++;
return true;
}
static bool
parse_char (const char **pp, const char *end, char c)
{
parse_space (pp, end);
if (*pp == end || **pp != c)
return false;
(*pp)++;
return true;
}
static bool
parse_uint (const char **pp, const char *end, unsigned int *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
unsigned int v;
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static bool
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
unsigned int v;
/* Intentionally use strtol instead of strtoul, such that
* -1 turns into "big number"... */
errno = 0;
v = strtol (p, &pend, 0);
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
#define USE_XLOCALE 1
#define HB_LOCALE_T locale_t
#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
#define HB_FREE_LOCALE(loc) freelocale (loc)
#elif defined(_MSC_VER)
#define USE_XLOCALE 1
#define HB_LOCALE_T _locale_t
#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
#define HB_FREE_LOCALE(loc) _free_locale (loc)
#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
#endif
#ifdef USE_XLOCALE
static HB_LOCALE_T C_locale;
#ifdef HB_USE_ATEXIT
static void
free_C_locale (void)
{
if (C_locale)
HB_FREE_LOCALE (C_locale);
}
#endif
static HB_LOCALE_T
get_C_locale (void)
{
retry:
HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
if (unlikely (!C))
{
C = HB_CREATE_LOCALE ("C");
if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C))
{
HB_FREE_LOCALE (C_locale);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_C_locale); /* First person registers atexit() callback. */
#endif
}
return C;
}
#endif
static bool
parse_float (const char **pp, const char *end, float *pv)
{
char buf[32];
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
strncpy (buf, *pp, len);
buf[len] = '\0';
char *p = buf;
char *pend = p;
float v;
errno = 0;
#ifdef USE_XLOCALE
v = strtod_l (p, &pend, get_C_locale ());
#else
v = strtod (p, &pend);
#endif
if (errno || p == pend)
return false;
*pv = v;
*pp += pend - p;
return true;
}
static bool
parse_bool (const char **pp, const char *end, uint32_t *pv)
{
parse_space (pp, end);
const char *p = *pp;
while (*pp < end && ISALPHA(**pp))
(*pp)++;
/* CSS allows on/off as aliases 1/0. */
if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
*pv = 1;
else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
*pv = 0;
else
return false;
return true;
}
/* hb_feature_t */
static bool
parse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
{
if (parse_char (pp, end, '-'))
feature->value = 0;
else {
parse_char (pp, end, '+');
feature->value = 1;
}
return true;
}
static bool
parse_tag (const char **pp, const char *end, hb_tag_t *tag)
{
parse_space (pp, end);
char quote = 0;
if (*pp < end && (**pp == '\'' || **pp == '"'))
{
quote = **pp;
(*pp)++;
}
const char *p = *pp;
while (*pp < end && ISALNUM(**pp))
(*pp)++;
if (p == *pp || *pp - p > 4)
return false;
*tag = hb_tag_from_string (p, *pp - p);
if (quote)
{
/* CSS expects exactly four bytes. And we only allow quotations for
* CSS compatibility. So, enforce the length. */
if (*pp - p != 4)
return false;
if (*pp == end || **pp != quote)
return false;
(*pp)++;
}
return true;
}
static bool
parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
{
parse_space (pp, end);
bool has_start;
feature->start = 0;
feature->end = (unsigned int) -1;
if (!parse_char (pp, end, '['))
return true;
has_start = parse_uint (pp, end, &feature->start);
if (parse_char (pp, end, ':')) {
parse_uint (pp, end, &feature->end);
} else {
if (has_start)
feature->end = feature->start + 1;
}
return parse_char (pp, end, ']');
}
static bool
parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
{
bool had_equal = parse_char (pp, end, '=');
bool had_value = parse_uint32 (pp, end, &feature->value) ||
parse_bool (pp, end, &feature->value);
/* CSS doesn't use equal-sign between tag and value.
* If there was an equal-sign, then there *must* be a value.
* A value without an equal-sign is ok, but not required. */
return !had_equal || had_value;
}
static bool
parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
{
return parse_feature_value_prefix (pp, end, feature) &&
parse_tag (pp, end, &feature->tag) &&
parse_feature_indices (pp, end, feature) &&
parse_feature_value_postfix (pp, end, feature) &&
parse_space (pp, end) &&
*pp == end;
}
/**
* hb_feature_from_string:
* @str: (array length=len) (element-type uint8_t): a string to parse
* @len: length of @str, or -1 if string is %NULL terminated
* @feature: (out): the #hb_feature_t to initialize with the parsed values
*
* Parses a string into a #hb_feature_t.
*
* TODO: document the syntax here.
*
* Return value:
* %true if @str is successfully parsed, %false otherwise.
*
* Since: 0.9.5
**/
hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature)
{
hb_feature_t feat;
if (len < 0)
len = strlen (str);
if (likely (parse_one_feature (&str, str + len, &feat)))
{
if (feature)
*feature = feat;
return true;
}
if (feature)
memset (feature, 0, sizeof (*feature));
return false;
}
/**
* hb_feature_to_string:
* @feature: an #hb_feature_t to convert
* @buf: (array length=size) (out): output string
* @size: the allocated size of @buf
*
* Converts a #hb_feature_t into a %NULL-terminated string in the format
* understood by hb_feature_from_string(). The client in responsible for
* allocating big enough size for @buf, 128 bytes is more than enough.
*
* Since: 0.9.5
**/
void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size)
{
if (unlikely (!size)) return;
char s[128];
unsigned int len = 0;
if (feature->value == 0)
s[len++] = '-';
hb_tag_to_string (feature->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
if (feature->start != 0 || feature->end != (unsigned int) -1)
{
s[len++] = '[';
if (feature->start)
len += 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));
}
s[len++] = ']';
}
if (feature->value > 1)
{
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
memcpy (buf, s, len);
buf[len] = '\0';
}
/* hb_variation_t */
static bool
parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
{
parse_char (pp, end, '='); /* Optional. */
return parse_float (pp, end, &variation->value);
}
static bool
parse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
{
return parse_tag (pp, end, &variation->tag) &&
parse_variation_value (pp, end, variation) &&
parse_space (pp, end) &&
*pp == end;
}
/**
* hb_variation_from_string:
*
* Since: 1.4.2
*/
hb_bool_t
hb_variation_from_string (const char *str, int len,
hb_variation_t *variation)
{
hb_variation_t var;
if (len < 0)
len = strlen (str);
if (likely (parse_one_variation (&str, str + len, &var)))
{
if (variation)
*variation = var;
return true;
}
if (variation)
memset (variation, 0, sizeof (*variation));
return false;
}
/**
* hb_variation_to_string:
*
* Since: 1.4.2
*/
void
hb_variation_to_string (hb_variation_t *variation,
char *buf, unsigned int size)
{
if (unlikely (!size)) return;
char s[128];
unsigned int len = 0;
hb_tag_to_string (variation->tag, s + len);
len += 4;
while (len && s[len - 1] == ' ')
len--;
s[len++] = '=';
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
assert (len < ARRAY_LENGTH (s));
len = MIN (len, size - 1);
memcpy (buf, s, len);
buf[len] = '\0';
}

View File

@ -43,30 +43,16 @@
# endif /* !__cplusplus */
#endif
#if !defined (HB_DONT_DEFINE_STDINT)
#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
defined (_sgi) || defined (__sun) || defined (sun) || \
defined (__digital__) || defined (__HP_cc)
# include <inttypes.h>
#elif defined (_AIX)
# include <sys/inttypes.h>
/* VS 2010 (_MSC_VER 1600) has stdint.h */
#elif defined (_MSC_VER) && _MSC_VER < 1600
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#endif
#endif
HB_BEGIN_DECLS
@ -148,7 +134,7 @@ hb_language_from_string (const char *str, int len);
HB_EXTERN const char *
hb_language_to_string (hb_language_t language);
#define HB_LANGUAGE_INVALID ((hb_language_t) NULL)
#define HB_LANGUAGE_INVALID ((hb_language_t) 0)
HB_EXTERN hb_language_t
hb_language_get_default (void);
@ -321,6 +307,14 @@ typedef enum
/*9.0*/ HB_SCRIPT_TANGUT = HB_TAG ('T','a','n','g'),
/*9.0*/ HB_SCRIPT_NEWA = HB_TAG ('N','e','w','a'),
/*
* Since 1.6.0
*/
/*10.0*/HB_SCRIPT_MASARAM_GONDI = HB_TAG ('G','o','n','m'),
/*10.0*/HB_SCRIPT_NUSHU = HB_TAG ('N','s','h','u'),
/*10.0*/HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'),
/*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'),
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,
@ -362,6 +356,42 @@ typedef struct hb_user_data_key_t {
typedef void (*hb_destroy_func_t) (void *user_data);
/* Font features and variations. */
typedef struct hb_feature_t {
hb_tag_t tag;
uint32_t value;
unsigned int start;
unsigned int end;
} hb_feature_t;
HB_EXTERN hb_bool_t
hb_feature_from_string (const char *str, int len,
hb_feature_t *feature);
HB_EXTERN void
hb_feature_to_string (hb_feature_t *feature,
char *buf, unsigned int size);
/**
* hb_variation_t:
*
* Since: 1.4.2
*/
typedef struct hb_variation_t {
hb_tag_t tag;
float value;
} hb_variation_t;
HB_EXTERN hb_bool_t
hb_variation_from_string (const char *str, int len,
hb_variation_t *variation);
HB_EXTERN void
hb_variation_to_string (hb_variation_t *variation,
char *buf, unsigned int size);
HB_END_DECLS
#endif /* HB_COMMON_H */

View File

@ -27,15 +27,34 @@
*/
#define HB_SHAPER coretext
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-shaper-impl-private.hh"
#include "hb-coretext.h"
#include <math.h>
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
#ifndef HB_DEBUG_CORETEXT
#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
#endif
static CGFloat
coretext_font_size_from_ptem (float ptem)
{
/* CoreText points are CSS pixels (96 per inch),
* NOT typographic points (72 per inch).
*
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
*/
ptem *= 96.f / 72.f;
return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem;
}
static float
coretext_font_size_to_ptem (CGFloat size)
{
size *= 72.f / 96.f;
return size <= 0.f ? 0 : size;
}
static void
release_table_data (void *user_data)
@ -50,32 +69,32 @@ 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);
if (unlikely (!cf_data))
return NULL;
return nullptr;
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
const size_t length = CFDataGetLength (cf_data);
if (!data || !length)
return NULL;
{
CFRelease (cf_data);
return nullptr;
}
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
release_table_data);
}
hb_face_t *
hb_coretext_face_create (CGFontRef cg_font)
static void
_hb_cg_font_release (void *data)
{
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), (hb_destroy_func_t) CGFontRelease);
CGFontRelease ((CGFontRef) data);
}
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, face)
HB_SHAPER_DATA_ENSURE_DECLARE(coretext, font)
/*
* shaper face data
*/
HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) <= .5
)
static CTFontDescriptorRef
get_last_resort_font_desc (void)
@ -104,7 +123,7 @@ static void
release_data (void *info, const void *data, size_t size)
{
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
hb_blob_get_data ((hb_blob_t *) info, NULL) == data);
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
hb_blob_destroy ((hb_blob_t *) info);
}
@ -112,8 +131,8 @@ release_data (void *info, const void *data, size_t size)
static CGFontRef
create_cg_font (hb_face_t *face)
{
CGFontRef cg_font = NULL;
if (face->destroy == (hb_destroy_func_t) CGFontRelease)
CGFontRef cg_font = nullptr;
if (face->destroy == _hb_cg_font_release)
{
cg_font = CGFontRetain ((CGFontRef) face->user_data);
}
@ -140,75 +159,118 @@ create_cg_font (hb_face_t *face)
static CTFontRef
create_ct_font (CGFontRef cg_font, CGFloat font_size)
{
CTFontRef ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, NULL, NULL);
CTFontRef ct_font = nullptr;
/* CoreText does not enable trak table usage / tracking when creating a CTFont
* using CTFontCreateWithGraphicsFont. The only way of enabling tracking seems
* to be through the CTFontCreateUIFontForLanguage call. */
CFStringRef cg_postscript_name = CGFontCopyPostScriptName (cg_font);
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
{
CTFontUIFontType font_type = kCTFontUIFontSystem;
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
font_type = kCTFontUIFontEmphasizedSystem;
ct_font = CTFontCreateUIFontForLanguage (font_type, font_size, nullptr);
CFStringRef ct_result_name = CTFontCopyPostScriptName(ct_font);
if (CFStringCompare (ct_result_name, cg_postscript_name, 0) != kCFCompareEqualTo)
{
CFRelease(ct_font);
ct_font = nullptr;
}
CFRelease (ct_result_name);
}
CFRelease (cg_postscript_name);
if (!ct_font)
ct_font = CTFontCreateWithGraphicsFont (cg_font, font_size, nullptr, nullptr);
if (unlikely (!ct_font)) {
DEBUG_MSG (CORETEXT, cg_font, "Font CTFontCreateWithGraphicsFont() failed");
return NULL;
return nullptr;
}
/* crbug.com/576941 and crbug.com/625902 and the investigation in the latter
* bug indicate that the cascade list reconfiguration occasionally causes
* crashes in CoreText on OS X 10.9, thus let's skip this step on older
* operating system versions. Except for the emoji font, where _not_
* reconfiguring the cascade list causes CoreText crashes. For details, see
* crbug.com/549610 */
// 0x00070000 stands for "kCTVersionNumber10_10", see CoreText.h
if (&CTGetCoreTextVersion != nullptr && CTGetCoreTextVersion() < 0x00070000) {
CFStringRef fontName = CTFontCopyPostScriptName (ct_font);
bool isEmojiFont = CFStringCompare (fontName, CFSTR("AppleColorEmoji"), 0) == kCFCompareEqualTo;
CFRelease (fontName);
if (!isEmojiFont)
return ct_font;
}
CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
* font fallback which we don't need anyway. */
{
CTFontDescriptorRef last_resort_font_desc = get_last_resort_font_desc ();
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, NULL, last_resort_font_desc);
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, last_resort_font_desc);
CFRelease (last_resort_font_desc);
if (new_ct_font)
{
CFRelease (ct_font);
ct_font = new_ct_font;
/* The CTFontCreateCopyWithAttributes call fails to stay on the same font
* when reconfiguring the cascade list and may switch to a different font
* when there are fonts that go by the same name, since the descriptor is
* just name and size.
*
* Avoid reconfiguring the cascade lists if the new font is outside the
* system locations that we cannot access from the sandboxed renderer
* process in Blink. This can be detected by the new file URL location
* that the newly found font points to. */
CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
CFRelease (ct_font);
ct_font = new_ct_font;
} else {
CFRelease (new_ct_font);
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
}
if (new_url)
CFRelease (new_url);
}
else
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
}
return ct_font;
if (original_url)
CFRelease (original_url);
return ct_font;
}
struct hb_coretext_shaper_face_data_t {
CGFontRef cg_font;
CTFontRef ct_font;
};
hb_coretext_shaper_face_data_t *
_hb_coretext_shaper_face_data_create (hb_face_t *face)
{
hb_coretext_shaper_face_data_t *data = (hb_coretext_shaper_face_data_t *) calloc (1, sizeof (hb_coretext_shaper_face_data_t));
if (unlikely (!data))
return NULL;
CGFontRef cg_font = create_cg_font (face);
data->cg_font = create_cg_font (face);
if (unlikely (!data->cg_font))
if (unlikely (!cg_font))
{
DEBUG_MSG (CORETEXT, face, "CGFont creation failed..");
free (data);
return NULL;
return nullptr;
}
/* We use 36pt size instead of UPEM, because CoreText implements the 'trak' table,
* which can make the font too tight at large sizes. 36pt should be a good semi-neutral
* size.
*
* Since we always create CTFont at a fixed size, our CTFont lives in face_data
* instead of font_data. Which is good, because when people change scale on
* hb_font_t, we won't need to update our CTFont. */
data->ct_font = create_ct_font (data->cg_font, 36.);
if (unlikely (!data->ct_font))
{
DEBUG_MSG (CORETEXT, face, "CTFont creation failed.");
CFRelease (data->cg_font);
free (data);
return NULL;
}
return data;
return (hb_coretext_shaper_face_data_t *) cg_font;
}
void
_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
{
CFRelease (data->ct_font);
CFRelease (data->cg_font);
free (data);
CFRelease ((CGFontRef) 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);
}
/*
@ -217,29 +279,66 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face)
{
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
return face_data->cg_font;
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
return (CGFontRef) HB_SHAPER_DATA_GET (face);
}
/*
* shaper font data
*/
struct hb_coretext_shaper_font_data_t {};
hb_coretext_shaper_font_data_t *
_hb_coretext_shaper_font_data_create (hb_font_t *font HB_UNUSED)
_hb_coretext_shaper_font_data_create (hb_font_t *font)
{
return (hb_coretext_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
hb_face_t *face = font->face;
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
if (unlikely (!ct_font))
{
DEBUG_MSG (CORETEXT, font, "CGFont creation failed..");
return nullptr;
}
return (hb_coretext_shaper_font_data_t *) ct_font;
}
void
_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
{
CFRelease ((CTFontRef) data);
}
/*
* Since: 1.7.2
*/
hb_font_t *
hb_coretext_font_create (CTFontRef ct_font)
{
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
hb_face_t *face = hb_coretext_face_create (cg_font);
CFRelease (cg_font);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
if (unlikely (hb_object_is_inert (font)))
return font;
hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
/* Let there be dragons here... */
HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font);
return font;
}
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
return (CTFontRef) HB_SHAPER_DATA_GET (font);
}
/*
* shaper shape_plan data
@ -250,7 +349,9 @@ struct hb_coretext_shaper_shape_plan_data_t {};
hb_coretext_shaper_shape_plan_data_t *
_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@ -260,15 +361,6 @@ _hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_
{
}
CTFontRef
hb_coretext_font_get_ct_font (hb_font_t *font)
{
hb_face_t *face = font->face;
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL;
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
return face_data->ct_font;
}
/*
* shaper
@ -283,7 +375,9 @@ struct active_feature_t {
feature_record_t rec;
unsigned int order;
static int cmp (const active_feature_t *a, const active_feature_t *b) {
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 :
a->order < b->order ? -1 : a->order > b->order ? 1 :
a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 :
@ -299,7 +393,9 @@ struct feature_event_t {
bool start;
active_feature_t feature;
static int cmp (const feature_event_t *a, const feature_event_t *b) {
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 :
a->start < b->start ? -1 : a->start > b->start ? 1 :
active_feature_t::cmp (&a->feature, &b->feature);
@ -498,9 +594,10 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
unsigned int num_features)
{
hb_face_t *face = font->face;
hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font);
CGFloat ct_font_size = CTFontGetSize (face_data->ct_font);
CGFloat ct_font_size = CTFontGetSize (ct_font);
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
@ -601,22 +698,23 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
/* active_features.qsort (); */
for (unsigned int j = 0; j < active_features.len; j++)
{
CFStringRef keys[2] = {
CFStringRef keys[] = {
kCTFontFeatureTypeIdentifierKey,
kCTFontFeatureSelectorIdentifierKey
};
CFNumberRef values[2] = {
CFNumberRef values[] = {
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
};
static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
(const void **) keys,
(const void **) values,
2,
ARRAY_LENGTH (keys),
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (values[0]);
CFRelease (values[1]);
for (unsigned int i = 0; i < ARRAY_LENGTH (values); i++)
CFRelease (values[i]);
CFArrayAppendValue (features_array, dict);
CFRelease (dict);
@ -634,12 +732,12 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CTFontDescriptorRef font_desc = CTFontDescriptorCreateWithAttributes (attributes);
CFRelease (attributes);
range->font = CTFontCreateCopyWithAttributes (face_data->ct_font, 0.0, NULL, font_desc);
range->font = CTFontCreateCopyWithAttributes (ct_font, 0.0, nullptr, font_desc);
CFRelease (font_desc);
}
else
{
range->font = NULL;
range->font = nullptr;
}
range->index_first = last_index;
@ -659,9 +757,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
active_features.remove (feature - active_features.array);
}
}
if (!range_records.len) /* No active feature found. */
goto fail_features;
}
else
{
@ -695,7 +790,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
pchars[chars_len++] = 0xFFFDu;
else {
pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
}
}
@ -712,14 +807,14 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (CORETEXT, NULL, __VA_ARGS__); \
DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
ret = false; \
goto fail; \
} HB_STMT_END;
bool ret = true;
CFStringRef string_ref = NULL;
CTLineRef line = NULL;
CFStringRef string_ref = nullptr;
CTLineRef line = nullptr;
if (0)
{
@ -731,8 +826,8 @@ resize_and_retry:
assert (line);
CFRelease (string_ref);
CFRelease (line);
string_ref = NULL;
line = NULL;
string_ref = nullptr;
line = nullptr;
/* Get previous start-of-scratch-area, that we use later for readjusting
* our existing scratch arrays. */
@ -753,7 +848,7 @@ resize_and_retry:
scratch_size -= old_scratch_used;
}
{
string_ref = CFStringCreateWithCharactersNoCopy (NULL,
string_ref = CFStringCreateWithCharactersNoCopy (nullptr,
pchars, chars_len,
kCFAllocatorNull);
if (unlikely (!string_ref))
@ -785,15 +880,18 @@ resize_and_retry:
kCFStringEncodingUTF8,
kCFAllocatorNull);
if (unlikely (!lang))
{
CFRelease (attr_string);
FAIL ("CFStringCreateWithCStringNoCopy failed");
}
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
kCTLanguageAttributeName, lang);
CFRelease (lang);
}
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
kCTFontAttributeName, face_data->ct_font);
kCTFontAttributeName, ct_font);
if (num_features)
if (num_features && range_records.len)
{
unsigned int start = 0;
range_record_t *last_range = &range_records[0];
@ -819,6 +917,30 @@ resize_and_retry:
CFAttributedStringSetAttribute (attr_string, CFRangeMake (start, chars_len - start),
kCTFontAttributeName, last_range->font);
}
/* Enable/disable kern if requested.
*
* Note: once kern is disabled, reenabling it doesn't currently seem to work in CoreText.
*/
if (num_features)
{
unsigned int zeroint = 0;
CFNumberRef zero = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &zeroint);
for (unsigned int i = 0; i < num_features; i++)
{
const hb_feature_t &feature = features[i];
if (feature.tag == HB_TAG('k','e','r','n') &&
feature.start < chars_len && feature.start < feature.end)
{
CFRange feature_range = CFRangeMake (feature.start,
MIN (feature.end, chars_len) - feature.start);
if (feature.value)
CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
else
CFAttributedStringSetAttribute (attr_string, feature_range, kCTKernAttributeName, zero);
}
}
CFRelease (zero);
}
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
@ -828,8 +950,12 @@ resize_and_retry:
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease (level_number);
if (unlikely (!options))
{
CFRelease (attr_string);
FAIL ("CFDictionaryCreate failed");
}
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
CFRelease (options);
@ -845,7 +971,7 @@ resize_and_retry:
CFArrayRef glyph_runs = CTLineGetGlyphRuns (line);
unsigned int num_runs = CFArrayGetCount (glyph_runs);
DEBUG_MSG (CORETEXT, NULL, "Num runs: %d", num_runs);
DEBUG_MSG (CORETEXT, nullptr, "Num runs: %d", num_runs);
buffer->len = 0;
uint32_t status_and = ~0, status_or = 0;
@ -871,7 +997,7 @@ resize_and_retry:
status_or |= run_status;
status_and &= run_status;
DEBUG_MSG (CORETEXT, run, "CTRunStatus: %x", run_status);
double run_advance = CTRunGetTypographicBounds (run, range_all, NULL, NULL, NULL);
double run_advance = CTRunGetTypographicBounds (run, range_all, nullptr, nullptr, nullptr);
if (HB_DIRECTION_IS_VERTICAL (buffer->props.direction))
run_advance = -run_advance;
DEBUG_MSG (CORETEXT, run, "Run advance: %g", run_advance);
@ -884,7 +1010,7 @@ resize_and_retry:
*/
CFDictionaryRef attributes = CTRunGetAttributes (run);
CTFontRef run_ct_font = static_cast<CTFontRef>(CFDictionaryGetValue (attributes, kCTFontAttributeName));
if (!CFEqual (run_ct_font, face_data->ct_font))
if (!CFEqual (run_ct_font, ct_font))
{
/* The run doesn't use our main font instance. We have to figure out
* whether font fallback happened, or this is just CoreText giving us
@ -906,7 +1032,7 @@ resize_and_retry:
* However, even that wouldn't work if we were passed in the CGFont to
* construct a hb_face to begin with.
*
* See: http://github.com/behdad/harfbuzz/pull/36
* See: http://github.com/harfbuzz/harfbuzz/pull/36
*
* Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
*/
@ -919,16 +1045,16 @@ resize_and_retry:
}
if (!matched)
{
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, nullptr);
if (run_cg_font)
{
matched = CFEqual (run_cg_font, face_data->cg_font);
matched = CFEqual (run_cg_font, cg_font);
CFRelease (run_cg_font);
}
}
if (!matched)
{
CFStringRef font_ps_name = CTFontCopyName (face_data->ct_font, kCTFontPostScriptNameKey);
CFStringRef font_ps_name = CTFontCopyName (ct_font, kCTFontPostScriptNameKey);
CFStringRef run_ps_name = CTFontCopyName (run_ct_font, kCTFontPostScriptNameKey);
CFComparisonResult result = CFStringCompare (run_ps_name, font_ps_name, 0);
CFRelease (run_ps_name);
@ -997,7 +1123,7 @@ resize_and_retry:
/* Testing used to indicate that CTRunGetGlyphsPtr, etc (almost?) always
* succeed, and so copying data to our own buffer will be rare. Reports
* have it that this changed in OS X 10.10 Yosemite, and NULL is returned
* have it that this changed in OS X 10.10 Yosemite, and nullptr is returned
* frequently. At any rate, we can test that codepath by setting USE_PTR
* to false. */
@ -1013,13 +1139,13 @@ resize_and_retry:
{ /* Setup glyphs */
SCRATCH_SAVE();
const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : NULL;
const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
if (!glyphs) {
ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
CTRunGetGlyphs (run, range_all, glyph_buf);
glyphs = glyph_buf;
}
const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : NULL;
const CFIndex* string_indices = USE_PTR ? CTRunGetStringIndicesPtr (run) : nullptr;
if (!string_indices) {
ALLOCATE_ARRAY (CFIndex, index_buf, num_glyphs, goto resize_and_retry);
CTRunGetStringIndices (run, range_all, index_buf);
@ -1041,7 +1167,7 @@ resize_and_retry:
* advance (in the advance direction only), and for last glyph we set
* whatever is needed to make the whole run's advance add up. */
SCRATCH_SAVE();
const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : NULL;
const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
if (!positions) {
ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
CTRunGetPositions (run, range_all, position_buf);
@ -1092,7 +1218,7 @@ resize_and_retry:
}
/* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
* or if it does, it doesn't resepct it. So we get runs with wrong
* or if it does, it doesn't respect it. So we get runs with wrong
* directions. As such, disable the assert... It wouldn't crash, but
* cursoring will be off...
*
@ -1117,6 +1243,7 @@ resize_and_retry:
pos->x_advance = info->mask;
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
info++, pos++;
}
else
@ -1125,6 +1252,7 @@ resize_and_retry:
pos->y_advance = info->mask;
pos->x_offset = info->var1.i32;
pos->y_offset = info->var2.i32;
info++, pos++;
}
@ -1162,6 +1290,8 @@ resize_and_retry:
}
}
buffer->unsafe_to_break_all ();
#undef FAIL
fail:
@ -1182,6 +1312,9 @@ fail:
* AAT shaper
*/
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
/*
* shaper face data
*/
@ -1191,22 +1324,20 @@ struct hb_coretext_aat_shaper_face_data_t {};
hb_coretext_aat_shaper_face_data_t *
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
{
hb_blob_t *mort_blob = face->reference_table (HB_CORETEXT_TAG_MORT);
/* Umm, we just reference the table to check whether it exists.
* Maybe add better API for this? */
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
mort_blob = face->reference_table (HB_CORETEXT_TAG_MORX);
if (!hb_blob_get_length (mort_blob))
{
hb_blob_destroy (mort_blob);
return NULL;
}
}
hb_blob_destroy (mort_blob);
static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
{
hb_blob_t *blob = face->reference_table (tags[i]);
if (hb_blob_get_length (blob))
{
hb_blob_destroy (blob);
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
}
hb_blob_destroy (blob);
}
return nullptr;
}
void
@ -1224,7 +1355,7 @@ struct hb_coretext_aat_shaper_font_data_t {};
hb_coretext_aat_shaper_font_data_t *
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
{
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : NULL;
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
}
void
@ -1242,7 +1373,9 @@ struct hb_coretext_aat_shaper_shape_plan_data_t {};
hb_coretext_aat_shaper_shape_plan_data_t *
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}

View File

@ -42,11 +42,15 @@ HB_BEGIN_DECLS
#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
#define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x')
HB_EXTERN hb_face_t *
hb_coretext_face_create (CGFontRef cg_font);
HB_EXTERN hb_font_t *
hb_coretext_font_create (CTFontRef ct_font);
HB_EXTERN CGFontRef
hb_coretext_face_get_cg_font (hb_face_t *face);

444
src/hb-debug.hh Normal file
View File

@ -0,0 +1,444 @@
/*
* 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_DEBUG_HH
#define HB_DEBUG_HH
#include "hb-private.hh"
#ifndef HB_DEBUG
#define HB_DEBUG 0
#endif
static inline bool
_hb_debug (unsigned int level,
unsigned int max_level)
{
return level < max_level;
}
#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
static inline void
_hb_print_func (const char *func)
{
if (func)
{
unsigned int func_len = strlen (func);
/* Skip "static" */
if (0 == strncmp (func, "static ", 7))
func += 7;
/* Skip "typename" */
if (0 == strncmp (func, "typename ", 9))
func += 9;
/* Skip return type */
const char *space = strchr (func, ' ');
if (space)
func = space + 1;
/* Skip parameter list */
const char *paren = strchr (func, '(');
if (paren)
func_len = paren - func;
fprintf (stderr, "%.*s", func_len, func);
}
}
template <int max_level> static inline void
_hb_debug_msg_va (const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
va_list ap) HB_PRINTF_FUNC(7, 0);
template <int max_level> static inline void
_hb_debug_msg_va (const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
va_list ap)
{
if (!_hb_debug (level, max_level))
return;
fprintf (stderr, "%-10s", what ? what : "");
if (obj)
fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
else
fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
if (indented) {
#define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */
#define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
#define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
#define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
#define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */
static const char bars[] =
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
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),
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
} else
fprintf (stderr, " " VRBAR LBAR);
_hb_print_func (func);
if (message)
{
fprintf (stderr, ": ");
vfprintf (stderr, message, ap);
}
fprintf (stderr, "\n");
}
template <> inline void
_hb_debug_msg_va<0> (const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
bool indented HB_UNUSED,
unsigned int level HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
va_list ap HB_UNUSED) {}
template <int max_level> static inline void
_hb_debug_msg (const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
...) HB_PRINTF_FUNC(7, 8);
template <int max_level> static inline void
_hb_debug_msg (const char *what,
const void *obj,
const char *func,
bool indented,
unsigned int level,
int level_dir,
const char *message,
...)
{
va_list ap;
va_start (ap, message);
_hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
va_end (ap);
}
template <> inline void
_hb_debug_msg<0> (const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
bool indented HB_UNUSED,
unsigned int level HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
...) HB_PRINTF_FUNC(7, 8);
template <> inline void
_hb_debug_msg<0> (const char *what HB_UNUSED,
const void *obj HB_UNUSED,
const char *func HB_UNUSED,
bool indented HB_UNUSED,
unsigned int level HB_UNUSED,
int level_dir HB_UNUSED,
const char *message HB_UNUSED,
...) {}
#define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
#define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__)
#define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
/*
* Printer
*/
template <typename T>
struct hb_printer_t {
const char *print (const T&) { return "something"; }
};
template <>
struct hb_printer_t<bool> {
const char *print (bool v) { return v ? "true" : "false"; }
};
template <>
struct hb_printer_t<hb_void_t> {
const char *print (hb_void_t) { return ""; }
};
/*
* Trace
*/
template <typename T>
static inline void _hb_warn_no_return (bool returned)
{
if (unlikely (!returned)) {
fprintf (stderr, "OUCH, returned with no call to return_trace(). This is a bug, please report.\n");
}
}
template <>
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
{}
template <int max_level, typename ret_t>
struct hb_auto_trace_t
{
explicit inline hb_auto_trace_t (unsigned int *plevel_,
const char *what_,
const void *obj_,
const char *func,
const char *message,
...) HB_PRINTF_FUNC(6, 7)
: plevel (plevel_), what (what_), obj (obj_), returned (false)
{
if (plevel) ++*plevel;
va_list ap;
va_start (ap, message);
_hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
va_end (ap);
}
inline ~hb_auto_trace_t (void)
{
_hb_warn_no_return<ret_t> (returned);
if (!returned) {
_hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
}
if (plevel) --*plevel;
}
inline ret_t ret (ret_t v, unsigned int line = 0)
{
if (unlikely (returned)) {
fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
return v;
}
_hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
"return %s (line %d)",
hb_printer_t<ret_t>().print (v), line);
if (plevel) --*plevel;
plevel = nullptr;
returned = true;
return v;
}
private:
unsigned int *plevel;
const char *what;
const void *obj;
bool returned;
};
template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */
struct hb_auto_trace_t<0, ret_t>
{
explicit inline hb_auto_trace_t (unsigned int *plevel_,
const char *what_,
const void *obj_,
const char *func,
const char *message,
...) HB_PRINTF_FUNC(6, 7) {}
inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
};
/* For disabled tracing; optimize out everything.
* https://github.com/harfbuzz/harfbuzz/pull/605 */
template <typename ret_t>
struct hb_no_trace_t {
inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
};
#define return_trace(RET) return trace.ret (RET, __LINE__)
/*
* Instances.
*/
#ifndef HB_DEBUG_ARABIC
#define HB_DEBUG_ARABIC (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_BLOB
#define HB_DEBUG_BLOB (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_CORETEXT
#define HB_DEBUG_CORETEXT (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_DIRECTWRITE
#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_FT
#define HB_DEBUG_FT (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_GET_COVERAGE
#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_OBJECT
#define HB_DEBUG_OBJECT (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_SHAPE_PLAN
#define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_UNISCRIBE
#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
#endif
/*
* With tracing.
*/
#ifndef HB_DEBUG_APPLY
#define HB_DEBUG_APPLY (HB_DEBUG+0)
#endif
#if HB_DEBUG_APPLY
#define TRACE_APPLY(this) \
hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
"idx %d gid %u lookup %d", \
c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
#else
#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
#if HB_DEBUG_SANITIZE
#define TRACE_SANITIZE(this) \
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
" ");
#else
#define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_SERIALIZE
#define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
#endif
#if HB_DEBUG_SERIALIZE
#define TRACE_SERIALIZE(this) \
hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
" ");
#else
#define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_SUBSET
#define HB_DEBUG_SUBSET (HB_DEBUG+0)
#endif
#if HB_DEBUG_SUBSET
#define TRACE_SUBSET(this) \
hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
" ");
#else
#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 + \
0)
#endif
#if HB_DEBUG_DISPATCH
#define TRACE_DISPATCH(this, format) \
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
"format %d", (int) format);
#else
#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
#endif
#endif /* HB_DEBUG_HH */

View File

@ -34,6 +34,7 @@
#include "hb-common.h"
#include "hb-unicode.h"
#include "hb-font.h"
#include "hb-set.h"
HB_BEGIN_DECLS
@ -54,6 +55,9 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN void
hb_set_invert (hb_set_t *set);
#endif
HB_END_DECLS

View File

@ -22,199 +22,202 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#define HB_SHAPER directwrite
#include "hb-shaper-impl-private.hh"
#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
#include <DWrite.h>
#else
#include <DWrite_1.h>
#endif
#include <DWrite_1.h>
#include "hb-directwrite.h"
#include "hb-open-file-private.hh"
#include "hb-ot-name-table.hh"
#include "hb-ot-tag.h"
HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, face)
HB_SHAPER_DATA_ENSURE_DEFINE(directwrite, font)
#ifndef HB_DEBUG_DIRECTWRITE
#define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
#endif
/*
* DirectWrite font stream helpers
*/
// This is a font loader which provides only one font (unlike its original design).
// For a better implementation which was also source of this
// and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
class DWriteFontFileLoader : public IDWriteFontFileLoader
{
private:
IDWriteFontFileStream *mFontFileStream;
public:
DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream) {
mFontFileStream = fontFileStream;
}
// IUnknown interface
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_(ULONG, AddRef)() { return 1; }
IFACEMETHOD_(ULONG, Release)() { return 1; }
// IDWriteFontFileLoader methods
virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey,
UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream** fontFileStream)
{
*fontFileStream = mFontFileStream;
return S_OK;
}
};
class DWriteFontFileStream : public IDWriteFontFileStream
{
private:
uint8_t *mData;
uint32_t mSize;
public:
DWriteFontFileStream(uint8_t *aData, uint32_t aSize)
{
mData = aData;
mSize = aSize;
}
// IUnknown interface
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) { return S_OK; }
IFACEMETHOD_(ULONG, AddRef)() { return 1; }
IFACEMETHOD_(ULONG, Release)() { return 1; }
// IDWriteFontFileStream methods
virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart,
UINT64 fileOffset,
UINT64 fragmentSize,
OUT void** fragmentContext)
{
// We are required to do bounds checking.
if (fileOffset + fragmentSize > mSize) {
return E_FAIL;
}
// truncate the 64 bit fileOffset to size_t sized index into mData
size_t index = static_cast<size_t> (fileOffset);
// We should be alive for the duration of this.
*fragmentStart = &mData[index];
*fragmentContext = nullptr;
return S_OK;
}
virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext) { }
virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize)
{
*fileSize = mSize;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime)
{
return E_NOTIMPL;
}
};
HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, face)
HB_SHAPER_DATA_ENSURE_DECLARE(directwrite, font)
/*
* shaper face data
*/
struct hb_directwrite_shaper_face_data_t {
HANDLE fh;
wchar_t face_name[LF_FACESIZE];
IDWriteFactory *dwriteFactory;
IDWriteFontFile *fontFile;
IDWriteFontFileStream *fontFileStream;
IDWriteFontFileLoader *fontFileLoader;
IDWriteFontFace *fontFace;
hb_blob_t *faceBlob;
};
/* face_name should point to a wchar_t[LF_FACESIZE] object. */
static void
_hb_generate_unique_face_name(wchar_t *face_name, unsigned int *plen)
{
/* We'll create a private name for the font from a UUID using a simple,
* somewhat base64-like encoding scheme */
const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
UUID id;
UuidCreate ((UUID*)&id);
ASSERT_STATIC (2 + 3 * (16 / 2) < LF_FACESIZE);
unsigned int name_str_len = 0;
face_name[name_str_len++] = 'F';
face_name[name_str_len++] = '_';
unsigned char *p = (unsigned char *)&id;
for (unsigned int i = 0; i < 16; i += 2)
{
/* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
* using the bits in groups of 5,5,6 to select chars from enc.
* This will generate 24 characters; with the 'F_' prefix we already provided,
* the name will be 26 chars (plus the NUL terminator), so will always fit within
* face_name (LF_FACESIZE = 32). */
face_name[name_str_len++] = enc[p[i] >> 3];
face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
}
face_name[name_str_len] = 0;
if (plen)
*plen = name_str_len;
}
/* Destroys blob. */
static hb_blob_t *
_hb_rename_font(hb_blob_t *blob, wchar_t *new_name)
{
/* Create a copy of the font data, with the 'name' table replaced by a
* table that names the font with our private F_* name created above.
* For simplicity, we just append a new 'name' table and update the
* sfnt directory; the original table is left in place, but unused.
*
* The new table will contain just 5 name IDs: family, style, unique,
* full, PS. All of them point to the same name data with our unique name.
*/
blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
unsigned int length, new_length, name_str_len;
const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
_hb_generate_unique_face_name (new_name, &name_str_len);
static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
unsigned int name_table_length = OT::name::min_size +
ARRAY_LENGTH(name_IDs) * OT::NameRecord::static_size +
name_str_len * 2; /* for name data in UTF16BE form */
unsigned int name_table_offset = (length + 3) & ~3;
new_length = name_table_offset + ((name_table_length + 3) & ~3);
void *new_sfnt_data = calloc(1, new_length);
if (!new_sfnt_data)
{
hb_blob_destroy (blob);
return NULL;
}
memcpy(new_sfnt_data, orig_sfnt_data, length);
OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
name.format.set (0);
name.count.set (ARRAY_LENGTH (name_IDs));
name.stringOffset.set (name.get_size());
for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
{
OT::NameRecord &record = name.nameRecord[i];
record.platformID.set(3);
record.encodingID.set(1);
record.languageID.set(0x0409u); /* English */
record.nameID.set(name_IDs[i]);
record.length.set(name_str_len * 2);
record.offset.set(0);
}
/* Copy string data from new_name, converting wchar_t to UTF16BE. */
unsigned char *p = &OT::StructAfter<unsigned char>(name);
for (unsigned int i = 0; i < name_str_len; i++)
{
*p++ = new_name[i] >> 8;
*p++ = new_name[i] & 0xff;
}
/* Adjust name table entry to point to new name table */
const OT::OpenTypeFontFile &file = *(OT::OpenTypeFontFile *) (new_sfnt_data);
unsigned int face_count = file.get_face_count ();
for (unsigned int face_index = 0; face_index < face_count; face_index++)
{
/* Note: doing multiple edits (ie. TTC) can be unsafe. There may be
* toe-stepping. But we don't really care. */
const OT::OpenTypeFontFace &face = file.get_face (face_index);
unsigned int index;
if (face.find_table_index (HB_OT_TAG_name, &index))
{
OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
record.checkSum.set_for_data (&name, name_table_length);
record.offset.set (name_table_offset);
record.length.set (name_table_length);
}
else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
{
free (new_sfnt_data);
hb_blob_destroy (blob);
return NULL;
}
}
/* The checkSumAdjustment field in the 'head' table is now wrong,
* but that doesn't actually seem to cause any problems so we don't
* bother. */
hb_blob_destroy (blob);
return hb_blob_create ((const char *)new_sfnt_data, new_length,
HB_MEMORY_MODE_WRITABLE, NULL, free);
}
hb_directwrite_shaper_face_data_t *
_hb_directwrite_shaper_face_data_create(hb_face_t *face)
{
hb_directwrite_shaper_face_data_t *data =
(hb_directwrite_shaper_face_data_t *) calloc (1, sizeof (hb_directwrite_shaper_face_data_t));
(hb_directwrite_shaper_face_data_t *) malloc (sizeof (hb_directwrite_shaper_face_data_t));
if (unlikely (!data))
return NULL;
return nullptr;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory
);
HRESULT hr;
hb_blob_t *blob = hb_face_reference_blob (face);
if (unlikely (!hb_blob_get_length (blob)))
DEBUG_MSG(DIRECTWRITE, face, "Face has empty blob");
IDWriteFontFileStream *fontFileStream = new DWriteFontFileStream (
(uint8_t*) hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob));
blob = _hb_rename_font (blob, data->face_name);
if (unlikely (!blob))
{
free(data);
return NULL;
IDWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
IDWriteFontFile *fontFile;
uint64_t fontFileKey = 0;
hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
fontFileLoader, &fontFile);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return false; \
} HB_STMT_END;
if (FAILED (hr)) {
FAIL ("Failed to load font file from data!");
return false;
}
DWORD num_fonts_installed;
data->fh = AddFontMemResourceEx ((void *)hb_blob_get_data(blob, NULL),
hb_blob_get_length (blob),
0, &num_fonts_installed);
if (unlikely (!data->fh))
{
DEBUG_MSG (DIRECTWRITE, face, "Face AddFontMemResourceEx() failed");
free (data);
return NULL;
BOOL isSupported;
DWRITE_FONT_FILE_TYPE fileType;
DWRITE_FONT_FACE_TYPE faceType;
UINT32 numberOfFaces;
hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
if (FAILED (hr) || !isSupported) {
FAIL ("Font file is not supported.");
return false;
}
#undef FAIL
IDWriteFontFace *fontFace;
dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
data->dwriteFactory = dwriteFactory;
data->fontFile = fontFile;
data->fontFileStream = fontFileStream;
data->fontFileLoader = fontFileLoader;
data->fontFace = fontFace;
data->faceBlob = blob;
return data;
}
void
_hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data)
{
RemoveFontMemResourceEx(data->fh);
free(data);
if (data->fontFace)
data->fontFace->Release ();
if (data->fontFile)
data->fontFile->Release ();
if (data->dwriteFactory) {
if (data->fontFileLoader)
data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
data->dwriteFactory->Release ();
}
if (data->fontFileLoader)
delete data->fontFileLoader;
if (data->fontFileStream)
delete data->fontFileStream;
if (data->faceBlob)
hb_blob_destroy (data->faceBlob);
if (data)
free (data);
}
@ -223,60 +226,17 @@ _hb_directwrite_shaper_face_data_destroy(hb_directwrite_shaper_face_data_t *data
*/
struct hb_directwrite_shaper_font_data_t {
HDC hdc;
LOGFONTW log_font;
HFONT hfont;
};
static bool
populate_log_font (LOGFONTW *lf,
hb_font_t *font)
{
memset (lf, 0, sizeof (*lf));
lf->lfHeight = -font->y_scale;
lf->lfCharSet = DEFAULT_CHARSET;
hb_face_t *face = font->face;
hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
return true;
}
hb_directwrite_shaper_font_data_t *
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
{
if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return NULL;
if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
hb_directwrite_shaper_font_data_t *data =
(hb_directwrite_shaper_font_data_t *) calloc (1, sizeof (hb_directwrite_shaper_font_data_t));
(hb_directwrite_shaper_font_data_t *) malloc (sizeof (hb_directwrite_shaper_font_data_t));
if (unlikely (!data))
return NULL;
data->hdc = GetDC (NULL);
if (unlikely (!populate_log_font (&data->log_font, font)))
{
DEBUG_MSG (DIRECTWRITE, font, "Font populate_log_font() failed");
_hb_directwrite_shaper_font_data_destroy (data);
return NULL;
}
data->hfont = CreateFontIndirectW (&data->log_font);
if (unlikely (!data->hfont))
{
DEBUG_MSG (DIRECTWRITE, font, "Font CreateFontIndirectW() failed");
_hb_directwrite_shaper_font_data_destroy (data);
return NULL;
}
if (!SelectObject (data->hdc, data->hfont))
{
DEBUG_MSG (DIRECTWRITE, font, "Font SelectObject() failed");
_hb_directwrite_shaper_font_data_destroy (data);
return NULL;
}
return nullptr;
return data;
}
@ -284,29 +244,9 @@ _hb_directwrite_shaper_font_data_create (hb_font_t *font)
void
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
{
if (data->hdc)
ReleaseDC (NULL, data->hdc);
if (data->hfont)
DeleteObject (data->hfont);
free (data);
}
LOGFONTW *
hb_directwrite_font_get_logfontw (hb_font_t *font)
{
if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
return &font_data->log_font;
}
HFONT
hb_directwrite_font_get_hfont (hb_font_t *font)
{
if (unlikely (!hb_directwrite_shaper_font_data_ensure (font))) return NULL;
hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
return font_data->hfont;
}
/*
* shaper shape_plan data
@ -316,8 +256,10 @@ struct hb_directwrite_shaper_shape_plan_data_t {};
hb_directwrite_shaper_shape_plan_data_t *
_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@ -327,7 +269,7 @@ _hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan
{
}
// Most of here TextAnalysis is originally written by Bas Schouten for Mozilla project
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
// but now is relicensed to MIT for HarfBuzz use
class TextAnalysis
: public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
@ -369,7 +311,7 @@ public:
, mTextLength(textLength)
, mLocaleName(localeName)
, mReadingDirection(readingDirection)
, mCurrentRun(NULL) { };
, mCurrentRun(nullptr) { };
~TextAnalysis() {
// delete runs, except mRunHead which is part of the TextAnalysis object
@ -393,7 +335,7 @@ public:
mRunHead.mTextLength = mTextLength;
mRunHead.mBidiLevel =
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
mRunHead.nextRun = NULL;
mRunHead.nextRun = nullptr;
mCurrentRun = &mRunHead;
// Call each of the analyzers in sequence, recording their results.
@ -412,7 +354,7 @@ public:
{
if (textPosition >= mTextLength) {
// No text at this position, valid query though.
*textString = NULL;
*textString = nullptr;
*textLength = 0;
}
else {
@ -428,8 +370,8 @@ public:
{
if (textPosition == 0 || textPosition > mTextLength) {
// Either there is no text before here (== 0), or this
// is an invalid position. The query is considered valid thouh.
*textString = NULL;
// is an invalid position. The query is considered valid though.
*textString = nullptr;
*textLength = 0;
}
else {
@ -444,7 +386,8 @@ public:
IFACEMETHODIMP GetLocaleName(uint32_t textPosition,
uint32_t* textLength,
wchar_t const** localeName) {
wchar_t const** localeName)
{
return S_OK;
}
@ -454,7 +397,7 @@ public:
OUT IDWriteNumberSubstitution** numberSubstitution)
{
// We do not support number substitution.
*numberSubstitution = NULL;
*numberSubstitution = nullptr;
*textLength = mTextLength - textPosition;
return S_OK;
@ -469,7 +412,8 @@ public:
{
SetCurrentRun(textPosition);
SplitCurrentRun(textPosition);
while (textLength > 0) {
while (textLength > 0)
{
Run *run = FetchNextRun(&textLength);
run->mScript = *scriptAnalysis;
}
@ -502,10 +446,12 @@ protected:
Run *origRun = mCurrentRun;
// Split the tail if needed (the length remaining is less than the
// current run's size).
if (*textLength < mCurrentRun->mTextLength) {
SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
if (*textLength < mCurrentRun->mTextLength)
{
SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
}
else {
else
{
// Just advance the current run.
mCurrentRun = mCurrentRun->nextRun;
}
@ -522,12 +468,14 @@ protected:
// this will usually just return early. If not, find the
// corresponding run for the text position.
if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
{
return;
}
for (Run *run = &mRunHead; run; run = run->nextRun) {
if (run->ContainsTextPosition(textPosition)) {
if (run->ContainsTextPosition (textPosition))
{
mCurrentRun = run;
return;
}
@ -538,13 +486,15 @@ protected:
void SplitCurrentRun(uint32_t splitPosition)
{
if (!mCurrentRun) {
if (!mCurrentRun)
{
//NS_ASSERTION(false, "SplitCurrentRun called without current run.");
// Shouldn't be calling this when no current run is set!
return;
}
// Split the current run.
if (splitPosition <= mCurrentRun->mTextStart) {
if (splitPosition <= mCurrentRun->mTextStart)
{
// No need to split, already the start of a run
// or before it. Usually the first.
return;
@ -590,42 +540,22 @@ static inline uint32_t hb_uint32_swap (const uint32_t v)
* shaper
*/
hb_bool_t
_hb_directwrite_shape(hb_shape_plan_t *shape_plan,
static hb_bool_t
_hb_directwrite_shape_full(hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
unsigned int num_features,
float lineWidth)
{
hb_face_t *face = font->face;
hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
IDWriteFontFace *fontFace = face_data->fontFace;
// factory probably should be cached
#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
IDWriteFactory* dwriteFactory;
#else
IDWriteFactory1* dwriteFactory;
#endif
DWriteCreateFactory (
DWRITE_FACTORY_TYPE_SHARED,
__uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory
);
IDWriteGdiInterop *gdiInterop;
dwriteFactory->GetGdiInterop (&gdiInterop);
IDWriteFontFace* fontFace;
gdiInterop->CreateFontFaceFromHdc (font_data->hdc, &fontFace);
#ifndef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
IDWriteTextAnalyzer* analyzer;
dwriteFactory->CreateTextAnalyzer(&analyzer);
#else
IDWriteTextAnalyzer* analyzer0;
dwriteFactory->CreateTextAnalyzer (&analyzer0);
IDWriteTextAnalyzer1* analyzer = (IDWriteTextAnalyzer1*) analyzer0;
#endif
unsigned int scratch_size;
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
@ -653,7 +583,7 @@ _hb_directwrite_shape(hb_shape_plan_t *shape_plan,
textString[chars_len++] = 0xFFFDu;
else {
textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
}
}
@ -672,7 +602,6 @@ _hb_directwrite_shape(hb_shape_plan_t *shape_plan,
}
}
HRESULT hr;
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
DWRITE_READING_DIRECTION readingDirection = buffer->props.direction ?
@ -686,13 +615,14 @@ _hb_directwrite_shape(hb_shape_plan_t *shape_plan,
*/
uint32_t textLength = buffer->len;
TextAnalysis analysis(textString, textLength, NULL, readingDirection);
TextAnalysis analysis(textString, textLength, nullptr, readingDirection);
TextAnalysis::Run *runHead;
HRESULT hr;
hr = analysis.GenerateResults(analyzer, &runHead);
#define FAIL(...) \
HB_STMT_START { \
DEBUG_MSG (DIRECTWRITE, NULL, __VA_ARGS__); \
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
return false; \
} HB_STMT_END;
@ -707,7 +637,7 @@ _hb_directwrite_shape(hb_shape_plan_t *shape_plan,
bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
const wchar_t localeName[20] = {0};
if (buffer->props.language != NULL)
if (buffer->props.language != nullptr)
{
mbstowcs ((wchar_t*) localeName,
hb_language_to_string (buffer->props.language), 20);
@ -731,24 +661,22 @@ _hb_directwrite_shape(hb_shape_plan_t *shape_plan,
(const DWRITE_TYPOGRAPHIC_FEATURES*) &singleFeatures;
const uint32_t featureRangeLengths[] = { textLength };
retry_getglyphs:
uint16_t* clusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
uint16_t* clusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties = (DWRITE_SHAPING_TEXT_PROPERTIES*)
malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
malloc (textLength * sizeof (DWRITE_SHAPING_TEXT_PROPERTIES));
retry_getglyphs:
uint16_t* glyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties = (DWRITE_SHAPING_GLYPH_PROPERTIES*)
malloc (maxGlyphCount * sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES));
hr = analyzer->GetGlyphs (textString, textLength, fontFace, FALSE,
isRightToLeft, &runHead->mScript, localeName, NULL, &dwFeatures,
hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
isRightToLeft, &runHead->mScript, localeName, nullptr, &dwFeatures,
featureRangeLengths, 1, maxGlyphCount, clusterMap, textProperties, glyphIndices,
glyphProperties, &glyphCount);
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
{
free (clusterMap);
free (glyphIndices);
free (textProperties);
free (glyphProperties);
maxGlyphCount *= 2;
@ -789,7 +717,7 @@ retry_getglyphs:
hr = analyzer->GetGlyphPlacements (textString,
clusterMap, textProperties, textLength, glyphIndices,
glyphProperties, glyphCount, fontFace, fontEmSize,
FALSE, isRightToLeft, &runHead->mScript, localeName,
false, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
@ -799,106 +727,106 @@ retry_getglyphs:
return false;
}
#ifdef HB_DIRECTWRITE_EXPERIMENTAL_JUSTIFICATION
IDWriteTextAnalyzer1* analyzer1;
analyzer->QueryInterface (&analyzer1);
DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
(DWRITE_JUSTIFICATION_OPPORTUNITY*)
malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
hr = analyzer->GetJustificationOpportunities (fontFace, fontEmSize,
runHead->mScript, textLength, glyphCount, textString, clusterMap,
glyphProperties, justificationOpportunities);
if (FAILED (hr))
if (analyzer1 && lineWidth)
{
FAIL ("Analyzer failed to get justification opportunities.");
return false;
}
// TODO: get lineWith from somewhere
float lineWidth = 60000;
DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
(DWRITE_JUSTIFICATION_OPPORTUNITY*)
malloc (maxGlyphCount * sizeof (DWRITE_JUSTIFICATION_OPPORTUNITY));
hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize,
runHead->mScript, textLength, glyphCount, textString, clusterMap,
glyphProperties, justificationOpportunities);
float* justifiedGlyphAdvances =
(float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
hr = analyzer->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
if (FAILED (hr))
{
FAIL ("Analyzer failed to get justification opportunities.");
return false;
}
if (FAILED (hr))
{
FAIL ("Analyzer failed to get justified glyph advances.");
return false;
}
float* justifiedGlyphAdvances =
(float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc (glyphCount * sizeof (DWRITE_GLYPH_OFFSET));
hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
glyphAdvances, glyphOffsets, justifiedGlyphAdvances, justifiedGlyphOffsets);
DWRITE_SCRIPT_PROPERTIES scriptProperties;
hr = analyzer->GetScriptProperties (runHead->mScript, &scriptProperties);
if (FAILED (hr))
{
FAIL ("Analyzer failed to get script properties.");
return false;
}
uint32_t justificationCharacter = scriptProperties.justificationCharacter;
if (FAILED (hr))
{
FAIL("Analyzer failed to get justified glyph advances.");
return false;
}
// if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
if (justificationCharacter != 32)
{
retry_getjustifiedglyphs:
uint16_t* modifiedClusterMap = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
uint32_t actualGlyphsCount;
hr = analyzer->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
DWRITE_SCRIPT_PROPERTIES scriptProperties;
hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
if (FAILED (hr))
{
FAIL("Analyzer failed to get script properties.");
return false;
}
uint32_t justificationCharacter = scriptProperties.justificationCharacter;
// if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
if (justificationCharacter != 32)
{
uint16_t* modifiedClusterMap = (uint16_t*) malloc (textLength * sizeof (uint16_t));
retry_getjustifiedglyphs:
uint16_t* modifiedGlyphIndices = (uint16_t*) malloc (maxGlyphCount * sizeof (uint16_t));
float* modifiedGlyphAdvances = (float*) malloc (maxGlyphCount * sizeof (float));
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = (DWRITE_GLYPH_OFFSET*)
malloc (maxGlyphCount * sizeof (DWRITE_GLYPH_OFFSET));
uint32_t actualGlyphsCount;
hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
textLength, glyphCount, maxGlyphCount, clusterMap, glyphIndices,
glyphAdvances, justifiedGlyphAdvances, justifiedGlyphOffsets,
glyphProperties, &actualGlyphsCount, modifiedClusterMap, modifiedGlyphIndices,
modifiedGlyphAdvances, modifiedGlyphOffsets);
if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
{
maxGlyphCount = actualGlyphsCount;
free (modifiedClusterMap);
free (modifiedGlyphIndices);
free (modifiedGlyphAdvances);
free (modifiedGlyphOffsets);
if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
{
maxGlyphCount = actualGlyphsCount;
free (modifiedGlyphIndices);
free (modifiedGlyphAdvances);
free (modifiedGlyphOffsets);
maxGlyphCount = actualGlyphsCount;
maxGlyphCount = actualGlyphsCount;
goto retry_getjustifiedglyphs;
goto retry_getjustifiedglyphs;
}
if (FAILED (hr))
{
FAIL ("Analyzer failed to get justified glyphs.");
return false;
}
free (clusterMap);
free (glyphIndices);
free (glyphAdvances);
free (glyphOffsets);
glyphCount = actualGlyphsCount;
clusterMap = modifiedClusterMap;
glyphIndices = modifiedGlyphIndices;
glyphAdvances = modifiedGlyphAdvances;
glyphOffsets = modifiedGlyphOffsets;
free (justifiedGlyphAdvances);
free (justifiedGlyphOffsets);
}
if (FAILED (hr))
else
{
FAIL ("Analyzer failed to get justified glyphs.");
return false;
free (glyphAdvances);
free (glyphOffsets);
glyphAdvances = justifiedGlyphAdvances;
glyphOffsets = justifiedGlyphOffsets;
}
free (clusterMap);
free (glyphIndices);
free (glyphAdvances);
free (glyphOffsets);
free (justificationOpportunities);
glyphCount = actualGlyphsCount;
clusterMap = modifiedClusterMap;
glyphIndices = modifiedGlyphIndices;
glyphAdvances = modifiedGlyphAdvances;
glyphOffsets = modifiedGlyphOffsets;
free(justifiedGlyphAdvances);
free(justifiedGlyphOffsets);
}
else
{
free(glyphAdvances);
free(glyphOffsets);
glyphAdvances = justifiedGlyphAdvances;
glyphOffsets = justifiedGlyphOffsets;
}
free(justificationOpportunities);
#endif
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
@ -968,3 +896,36 @@ retry_getjustifiedglyphs:
/* Wow, done! */
return true;
}
hb_bool_t
_hb_directwrite_shape(hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_directwrite_shape_full(shape_plan, font, buffer,
features, num_features, 0);
}
/*
* Public [experimental] API
*/
hb_bool_t
hb_directwrite_shape_experimental_width(hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float width)
{
static char *shapers = "directwrite";
hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face,
&buffer->props, features, num_features, &shapers);
hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
features, num_features, width);
buffer->unsafe_to_break_all ();
return res;
}

View File

@ -29,6 +29,10 @@
HB_BEGIN_DECLS
HB_EXTERN hb_bool_t
hb_directwrite_shape_experimental_width(hb_font_t *font, hb_buffer_t *buffer,
const hb_feature_t *features, unsigned int num_features, float width);
HB_END_DECLS
#endif /* HB_UNISCRIBE_H */
#endif /* HB_DIRECTWRITE_H */

161
src/hb-dsalgs.hh Normal file
View File

@ -0,0 +1,161 @@
/*
* 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-private.hh"
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 = (min + 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 NULL;
}
/* From https://github.com/noporpoise/sort_r */
/* 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, *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) {
for(; pl < pr; pl += w) {
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
pr -= w; /* pivot now at pl */
break;
}
}
for(; pl < 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);
}
#endif /* HB_DSALGS_HH */

View File

@ -50,12 +50,16 @@ struct hb_face_t {
void *user_data;
hb_destroy_func_t destroy;
unsigned int index;
mutable unsigned int upem;
mutable unsigned int num_glyphs;
unsigned int index; /* Face index in a collection, zero-based. */
mutable unsigned int upem; /* Units-per-EM. */
mutable unsigned int num_glyphs; /* Number of glyphs. */
struct hb_shaper_data_t shaper_data;
struct hb_shaper_data_t shaper_data; /* Various shaper data. */
/* Various non-shaping data. */
/* ... */
/* Cache */
struct plan_node_t {
hb_shape_plan_t *shape_plan;
plan_node_t *next;

View File

@ -28,17 +28,11 @@
#include "hb-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-face-private.hh"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
#include "hb-cache-private.hh"
#include <string.h>
/*
* hb_face_t
@ -49,9 +43,9 @@ const hb_face_t _hb_face_nil = {
true, /* immutable */
NULL, /* reference_table_func */
NULL, /* user_data */
NULL, /* destroy */
nullptr, /* reference_table_func */
nullptr, /* user_data */
nullptr, /* destroy */
0, /* index */
1000, /* upem */
@ -63,7 +57,7 @@ const hb_face_t _hb_face_nil = {
#undef HB_SHAPER_IMPLEMENT
},
NULL, /* shape_plans */
nullptr, /* shape_plans */
};
@ -115,7 +109,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
if (unlikely (!closure))
return NULL;
return nullptr;
closure->blob = blob;
closure->index = index;
@ -124,8 +118,10 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
}
static void
_hb_face_for_data_closure_destroy (hb_face_for_data_closure_t *closure)
_hb_face_for_data_closure_destroy (void *data)
{
hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
hb_blob_destroy (closure->blob);
free (closure);
}
@ -168,16 +164,16 @@ hb_face_create (hb_blob_t *blob,
if (unlikely (!blob))
blob = hb_blob_get_empty ();
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (hb_blob_reference (blob)), index);
if (unlikely (!closure))
return hb_face_get_empty ();
face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
closure,
(hb_destroy_func_t) _hb_face_for_data_closure_destroy);
_hb_face_for_data_closure_destroy);
hb_face_set_index (face, index);
face->index = index;
return face;
}
@ -428,7 +424,7 @@ hb_face_get_upem (hb_face_t *face)
void
hb_face_t::load_upem (void) const
{
hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (reference_table (HB_OT_TAG_head));
const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
upem = head_table->get_upem ();
hb_blob_destroy (head_blob);
@ -472,10 +468,39 @@ hb_face_get_glyph_count (hb_face_t *face)
void
hb_face_t::load_num_glyphs (void) const
{
hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (reference_table (HB_OT_TAG_maxp));
const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
num_glyphs = maxp_table->get_num_glyphs ();
hb_blob_destroy (maxp_blob);
}
/**
* hb_face_get_table_tags:
* @face: a face.
*
* Retrieves table tags for a face, if possible.
*
* Return value: total number of tables, or 0 if not possible to list.
*
* Since: 1.6.0
**/
unsigned int
hb_face_get_table_tags (hb_face_t *face,
unsigned int start_offset,
unsigned int *table_count, /* IN/OUT */
hb_tag_t *table_tags /* OUT */)
{
if (face->destroy != _hb_face_for_data_closure_destroy)
{
if (table_count)
*table_count = 0;
return 0;
}
hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
return ot_face.get_table_tags (start_offset, table_count, table_tags);
}

View File

@ -71,7 +71,6 @@ hb_face_set_user_data (hb_face_t *face,
hb_destroy_func_t destroy,
hb_bool_t replace);
HB_EXTERN void *
hb_face_get_user_data (hb_face_t *face,
hb_user_data_key_t *key);
@ -111,6 +110,11 @@ hb_face_set_glyph_count (hb_face_t *face,
HB_EXTERN unsigned int
hb_face_get_glyph_count (hb_face_t *face);
HB_EXTERN unsigned int
hb_face_get_table_tags (hb_face_t *face,
unsigned int start_offset,
unsigned int *table_count, /* IN/OUT */
hb_tag_t *table_tags /* OUT */);
HB_END_DECLS

View File

@ -28,6 +28,10 @@
#include "hb-shaper-impl-private.hh"
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font)
/*
* shaper face data
*/
@ -73,7 +77,9 @@ struct hb_fallback_shaper_shape_plan_data_t {};
hb_fallback_shaper_shape_plan_data_t *
_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
const hb_feature_t *user_features HB_UNUSED,
unsigned int num_user_features HB_UNUSED)
unsigned int num_user_features HB_UNUSED,
const int *coords HB_UNUSED,
unsigned int num_coords HB_UNUSED)
{
return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
@ -123,7 +129,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
pos[i].y_advance = 0;
continue;
}
font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
(void) font->get_nominal_glyph (info[i].codepoint, &info[i].codepoint);
font->get_glyph_advance_for_direction (info[i].codepoint,
direction,
&pos[i].x_advance,
@ -137,5 +143,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
if (HB_DIRECTION_IS_BACKWARD (direction))
hb_buffer_reverse (buffer);
buffer->safe_to_break_all ();
return true;
}

View File

@ -108,6 +108,12 @@ struct hb_font_t {
unsigned int x_ppem;
unsigned int y_ppem;
float ptem;
/* Font variation coordinates. */
unsigned int num_coords;
int *coords;
hb_font_funcs_t *klass;
void *user_data;
hb_destroy_func_t destroy;
@ -116,8 +122,16 @@ struct hb_font_t {
/* Convert from font-space to user-space */
inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, this->x_scale); }
inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, this->y_scale); }
inline int dir_scale (hb_direction_t direction)
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
inline float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
inline float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
{ return em_scale (v, dir_scale (direction)); }
/* Convert from parent-font user-space to our user-space */
inline hb_position_t parent_scale_x_distance (hb_position_t v) {
@ -292,24 +306,32 @@ struct hb_font_t {
/* A bit higher-level, and with fallback */
inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
{
if (!get_font_h_extents (extents))
{
extents->ascender = y_scale * .8;
extents->descender = extents->ascender - y_scale;
extents->line_gap = 0;
}
}
inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
{
if (!get_font_v_extents (extents))
{
extents->ascender = x_scale / 2;
extents->descender = extents->ascender - x_scale;
extents->line_gap = 0;
}
}
inline void get_extents_for_direction (hb_direction_t direction,
hb_font_extents_t *extents)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
if (!get_font_h_extents (extents))
{
extents->ascender = y_scale * .8;
extents->descender = y_scale - extents->ascender;
extents->line_gap = 0;
}
} else {
if (!get_font_v_extents (extents))
{
extents->ascender = x_scale / 2;
extents->descender = x_scale - extents->ascender;
extents->line_gap = 0;
}
}
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
get_h_extents_with_fallback (extents);
else
get_v_extents_with_fallback (extents);
}
inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
@ -325,14 +347,38 @@ struct hb_font_t {
}
}
/* Internal only */
inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
*x = get_glyph_h_advance (glyph) / 2;
/* TODO use font_extents.ascender */
*y = y_scale;
/* TODO cache this somehow?! */
hb_font_extents_t extents;
get_h_extents_with_fallback (&extents);
*y = extents.ascender;
}
inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
if (!get_glyph_h_origin (glyph, x, y) &&
get_glyph_v_origin (glyph, x, y))
{
hb_position_t dx, dy;
guess_v_origin_minus_h_origin (glyph, &dx, &dy);
*x -= dx; *y -= dy;
}
}
inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y)
{
if (!get_glyph_v_origin (glyph, x, y) &&
get_glyph_h_origin (glyph, x, y))
{
hb_position_t dx, dy;
guess_v_origin_minus_h_origin (glyph, &dx, &dy);
*x += dx; *y += dy;
}
}
inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
@ -340,25 +386,9 @@ struct hb_font_t {
hb_position_t *x, hb_position_t *y)
{
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
{
if (!get_glyph_h_origin (glyph, x, y) &&
get_glyph_v_origin (glyph, x, y))
{
hb_position_t dx, dy;
guess_v_origin_minus_h_origin (glyph, &dx, &dy);
*x -= dx; *y -= dy;
}
}
get_glyph_h_origin_with_fallback (glyph, x, y);
else
{
if (!get_glyph_v_origin (glyph, x, y) &&
get_glyph_h_origin (glyph, x, y))
{
hb_position_t dx, dy;
guess_v_origin_minus_h_origin (glyph, &dx, &dy);
*x += dx; *y += dy;
}
}
get_glyph_v_origin_with_fallback (glyph, x, y);
}
inline void add_glyph_h_origin (hb_codepoint_t glyph,
@ -366,7 +396,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin (glyph, &origin_x, &origin_y);
get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
@ -376,7 +406,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin (glyph, &origin_x, &origin_y);
get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
*x += origin_x;
*y += origin_y;
@ -398,7 +428,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
get_glyph_h_origin (glyph, &origin_x, &origin_y);
get_glyph_h_origin_with_fallback (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
@ -408,7 +438,7 @@ struct hb_font_t {
{
hb_position_t origin_x, origin_y;
get_glyph_v_origin (glyph, &origin_x, &origin_y);
get_glyph_v_origin_with_fallback (glyph, &origin_x, &origin_y);
*x -= origin_x;
*y -= origin_y;
@ -504,7 +534,6 @@ struct hb_font_t {
return false;
}
private:
inline hb_position_t em_scale (int16_t v, int scale)
{
int upem = face->get_upem ();
@ -512,6 +541,14 @@ struct hb_font_t {
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
return (hb_position_t) (scaled / upem);
}
inline hb_position_t em_scalef (float v, int scale)
{
return (hb_position_t) round (v * scale / face->get_upem ());
}
inline float em_fscale (int16_t v, int scale)
{
return (float) v * scale / face->get_upem ();
}
};
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS

View File

@ -28,16 +28,7 @@
#include "hb-private.hh"
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"
#include "hb-cache-private.hh"
#include <string.h>
/*
@ -45,7 +36,7 @@
*/
static hb_bool_t
hb_font_get_font_h_extents_nil (hb_font_t *font,
hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
@ -69,7 +60,7 @@ hb_font_get_font_h_extents_parent (hb_font_t *font,
}
static hb_bool_t
hb_font_get_font_v_extents_nil (hb_font_t *font,
hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
void *font_data HB_UNUSED,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
@ -356,12 +347,12 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
@ -379,12 +370,12 @@ static const hb_font_funcs_t _hb_font_funcs_parent = {
true, /* immutable */
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
{
#define HB_FONT_FUNC_IMPLEMENT(name) NULL,
#define HB_FONT_FUNC_IMPLEMENT(name) nullptr,
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
},
@ -572,8 +563,8 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
ffuncs->destroy.name = destroy; \
} else { \
ffuncs->get.f.name = hb_font_get_##name##_parent; \
ffuncs->user_data.name = NULL; \
ffuncs->destroy.name = NULL; \
ffuncs->user_data.name = nullptr; \
ffuncs->destroy.name = nullptr; \
} \
}
@ -1166,6 +1157,20 @@ hb_font_create_sub_font (hb_font_t *parent)
font->y_scale = parent->y_scale;
font->x_ppem = parent->x_ppem;
font->y_ppem = parent->y_ppem;
font->ptem = parent->ptem;
font->num_coords = parent->num_coords;
if (!font->num_coords)
font->coords = nullptr;
else
{
unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
font->coords = (int *) malloc (size);
if (unlikely (!font->coords))
font->num_coords = 0;
else
memcpy (font->coords, parent->coords, size);
}
return font;
}
@ -1187,7 +1192,7 @@ hb_font_get_empty (void)
true, /* immutable */
NULL, /* parent */
nullptr, /* parent */
const_cast<hb_face_t *> (&_hb_face_nil),
1000, /* x_scale */
@ -1195,10 +1200,14 @@ hb_font_get_empty (void)
0, /* x_ppem */
0, /* y_ppem */
0, /* ptem */
0, /* num_coords */
nullptr, /* coords */
const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
NULL, /* user_data */
NULL, /* destroy */
nullptr, /* user_data */
nullptr, /* destroy */
{
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
@ -1250,6 +1259,8 @@ hb_font_destroy (hb_font_t *font)
hb_face_destroy (font->face);
hb_font_funcs_destroy (font->klass);
free (font->coords);
free (font);
}
@ -1373,6 +1384,32 @@ hb_font_get_parent (hb_font_t *font)
return font->parent;
}
/**
* hb_font_set_face:
* @font: a font.
* @face: new face.
*
* Sets font-face of @font.
*
* Since: 1.4.3
**/
void
hb_font_set_face (hb_font_t *font,
hb_face_t *face)
{
if (font->immutable)
return;
if (unlikely (!face))
face = hb_face_get_empty ();
hb_face_t *old = font->face;
font->face = hb_face_reference (face);
hb_face_destroy (old);
}
/**
* hb_font_get_face:
* @font: a font.
@ -1538,6 +1575,148 @@ hb_font_get_ppem (hb_font_t *font,
if (y_ppem) *y_ppem = font->y_ppem;
}
/**
* hb_font_set_ptem:
* @font: a font.
* @ptem:
*
* Sets "point size" of the font.
*
* Since: 1.6.0
**/
void
hb_font_set_ptem (hb_font_t *font, float ptem)
{
if (font->immutable)
return;
font->ptem = ptem;
}
/**
* hb_font_get_ptem:
* @font: a font.
*
* Gets the "point size" of the font. A value of 0 means unset.
*
* Return value: Point size.
*
* Since: 0.9.2
**/
float
hb_font_get_ptem (hb_font_t *font)
{
return font->ptem;
}
/*
* Variations
*/
static void
_hb_font_adopt_var_coords_normalized (hb_font_t *font,
int *coords, /* 2.14 normalized */
unsigned int coords_length)
{
free (font->coords);
font->coords = coords;
font->num_coords = coords_length;
}
/**
* hb_font_set_variations:
*
* Since: 1.4.2
*/
void
hb_font_set_variations (hb_font_t *font,
const hb_variation_t *variations,
unsigned int variations_length)
{
if (font->immutable)
return;
if (!variations_length)
{
hb_font_set_var_coords_normalized (font, nullptr, 0);
return;
}
unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
if (unlikely (coords_length && !normalized))
return;
hb_ot_var_normalize_variations (font->face,
variations, variations_length,
normalized, coords_length);
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
/**
* hb_font_set_var_coords_design:
*
* Since: 1.4.2
*/
void
hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length)
{
if (font->immutable)
return;
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
if (unlikely (coords_length && !normalized))
return;
hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
}
/**
* hb_font_set_var_coords_normalized:
*
* Since: 1.4.2
*/
void
hb_font_set_var_coords_normalized (hb_font_t *font,
const int *coords, /* 2.14 normalized */
unsigned int coords_length)
{
if (font->immutable)
return;
int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
if (unlikely (coords_length && !copy))
return;
if (coords_length)
memcpy (copy, coords, coords_length * sizeof (coords[0]));
_hb_font_adopt_var_coords_normalized (font, copy, coords_length);
}
/**
* hb_font_get_var_coords_normalized:
*
* Return value is valid as long as variation coordinates of the font
* are not modified.
*
* Since: 1.4.2
*/
const int *
hb_font_get_var_coords_normalized (hb_font_t *font,
unsigned int *length)
{
if (length)
*length = font->num_coords;
return font->coords;
}
#ifndef HB_DISABLE_DEPRECATED
@ -1570,7 +1749,7 @@ trampoline_create (FuncType func,
trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
if (unlikely (!trampoline))
return NULL;
return nullptr;
trampoline->closure.user_data = user_data;
trampoline->closure.destroy = destroy;

View File

@ -456,7 +456,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
/* high-level funcs, with fallback */
/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
* otherwise callse hb_font_get_variation_glyph(). */
* otherwise calls hb_font_get_variation_glyph(). */
HB_EXTERN hb_bool_t
hb_font_get_glyph (hb_font_t *font,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@ -563,6 +563,10 @@ hb_font_set_parent (hb_font_t *font,
HB_EXTERN hb_font_t *
hb_font_get_parent (hb_font_t *font);
HB_EXTERN void
hb_font_set_face (hb_font_t *font,
hb_face_t *face);
HB_EXTERN hb_face_t *
hb_font_get_face (hb_font_t *font);
@ -603,6 +607,34 @@ hb_font_get_ppem (hb_font_t *font,
unsigned int *x_ppem,
unsigned int *y_ppem);
/*
* Point size per EM. Used for optical-sizing in CoreText.
* A value of zero means "not set".
*/
HB_EXTERN void
hb_font_set_ptem (hb_font_t *font, float ptem);
HB_EXTERN float
hb_font_get_ptem (hb_font_t *font);
HB_EXTERN void
hb_font_set_variations (hb_font_t *font,
const hb_variation_t *variations,
unsigned int variations_length);
HB_EXTERN void
hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length);
HB_EXTERN void
hb_font_set_var_coords_normalized (hb_font_t *font,
const int *coords, /* 2.14 normalized */
unsigned int coords_length);
HB_EXTERN const int *
hb_font_get_var_coords_normalized (hb_font_t *font,
unsigned int *length);
HB_END_DECLS

View File

@ -28,21 +28,17 @@
*/
#include "hb-private.hh"
#include "hb-debug.hh"
#include "hb-ft.h"
#include "hb-font-private.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H
#ifndef HB_DEBUG_FT
#define HB_DEBUG_FT (HB_DEBUG+0)
#endif
/* TODO:
*
* In general, this file does a fine job of what it's supposed to do.
@ -62,7 +58,7 @@
*
* - In the future, we should add constructors to create fonts in font space?
*
* - FT_Load_Glyph() is exteremely costly. Do something about it?
* - FT_Load_Glyph() is extremely costly. Do something about it?
*/
@ -70,18 +66,20 @@ struct hb_ft_font_t
{
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
};
static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool unref)
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
if (unlikely (!ft_font))
return NULL;
return nullptr;
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
@ -90,10 +88,18 @@ _hb_ft_font_create (FT_Face ft_face, bool unref)
}
static void
_hb_ft_font_destroy (hb_ft_font_t *ft_font)
_hb_ft_face_destroy (void *data)
{
FT_Done_Face ((FT_Face) data);
}
static void
_hb_ft_font_destroy (void *data)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
if (ft_font->unref)
FT_Done_Face (ft_font->ft_face);
_hb_ft_face_destroy (ft_font->ft_face);
free (ft_font);
}
@ -113,7 +119,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
if (font->immutable)
return;
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
if (font->destroy != _hb_ft_font_destroy)
return;
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
@ -133,7 +139,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
int
hb_ft_font_get_load_flags (hb_font_t *font)
{
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
if (font->destroy != _hb_ft_font_destroy)
return 0;
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@ -144,8 +150,8 @@ hb_ft_font_get_load_flags (hb_font_t *font)
FT_Face
hb_ft_font_get_face (hb_font_t *font)
{
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return NULL;
if (font->destroy != _hb_ft_font_destroy)
return nullptr;
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
@ -165,7 +171,21 @@ hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
if (unlikely (!g))
return false;
{
if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
{
/* For symbol-encoded OpenType fonts, we duplicate the
* U+F000..F0FF range at U+0000..U+00FF. That's what
* Windows seems to do, and that's hinted about at:
* http://www.microsoft.com/typography/otspec/recom.htm
* under "Non-Standard (Symbol) Fonts". */
g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
if (!g)
return false;
}
else
return false;
}
*glyph = g;
return true;
@ -397,7 +417,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true;
}
static hb_font_funcs_t *static_ft_funcs = NULL;
static hb_font_funcs_t *static_ft_funcs = nullptr;
#ifdef HB_USE_ATEXIT
static
@ -417,24 +437,24 @@ retry:
{
funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, NULL, NULL);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, NULL, NULL);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, NULL, NULL);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, NULL, NULL);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, NULL, NULL);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, NULL, NULL);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, NULL, NULL);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, NULL, NULL);
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, NULL, NULL);
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, NULL, NULL);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, NULL, NULL);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, NULL, NULL);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, NULL, NULL);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, NULL, NULL);
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
hb_font_funcs_make_immutable (funcs);
if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, NULL, funcs)) {
if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
hb_font_funcs_destroy (funcs);
goto retry;
}
@ -444,10 +464,12 @@ retry:
#endif
};
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
hb_font_set_funcs (font,
funcs,
_hb_ft_font_create (ft_face, unref),
(hb_destroy_func_t) _hb_ft_font_destroy);
_hb_ft_font_create (ft_face, symbol, unref),
_hb_ft_font_destroy);
}
@ -461,17 +483,17 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
/* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
if (error)
return NULL;
return nullptr;
buffer = (FT_Byte *) malloc (length);
if (buffer == NULL)
return NULL;
if (!buffer)
return nullptr;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
if (error)
return NULL;
return nullptr;
return hb_blob_create ((const char *) buffer, length,
HB_MEMORY_MODE_WRITABLE,
@ -494,7 +516,7 @@ hb_ft_face_create (FT_Face ft_face,
{
hb_face_t *face;
if (ft_face->stream->read == NULL) {
if (!ft_face->stream->read) {
hb_blob_t *blob;
blob = hb_blob_create ((const char *) ft_face->stream->base,
@ -526,7 +548,7 @@ hb_face_t *
hb_ft_face_create_referenced (FT_Face ft_face)
{
FT_Reference_Face (ft_face);
return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
}
static void
@ -552,7 +574,7 @@ hb_ft_face_create_cached (FT_Face ft_face)
if (ft_face->generic.finalizer)
ft_face->generic.finalizer (ft_face);
ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
}
@ -581,16 +603,61 @@ hb_ft_font_create (FT_Face ft_face,
font = hb_font_create (face);
hb_face_destroy (face);
_hb_ft_font_set_funcs (font, ft_face, false);
hb_ft_font_changed (font);
return font;
}
void
hb_ft_font_changed (hb_font_t *font)
{
if (font->destroy != _hb_ft_font_destroy)
return;
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
FT_Face ft_face = ft_font->ft_face;
hb_font_set_scale (font,
(int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
(int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
(int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
(int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
#if 0 /* hb-ft works in no-hinting model */
hb_font_set_ppem (font,
ft_face->size->metrics.x_ppem,
ft_face->size->metrics.y_ppem);
#endif
return font;
#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
FT_MM_Var *mm_var = nullptr;
if (!FT_Get_MM_Var (ft_face, &mm_var))
{
FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
if (coords && ft_coords)
{
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
{
bool nonzero = false;
for (unsigned int i = 0; i < mm_var->num_axis; ++i)
{
coords[i] = ft_coords[i] >>= 2;
nonzero = nonzero || coords[i];
}
if (nonzero)
hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
else
hb_font_set_var_coords_normalized (font, nullptr, 0);
}
}
free (coords);
free (ft_coords);
#ifdef HAVE_FT_DONE_MM_VAR
FT_Done_MM_Var (ft_face->glyph->library, mm_var);
#else
free (mm_var);
#endif
}
#endif
}
/**
@ -606,7 +673,7 @@ hb_font_t *
hb_ft_font_create_referenced (FT_Face ft_face)
{
FT_Reference_Face (ft_face);
return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
@ -632,9 +699,9 @@ retry:
{
/* Not found; allocate one. */
if (FT_Init_FreeType (&library))
return NULL;
return nullptr;
if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
FT_Done_FreeType (library);
goto retry;
}
@ -662,7 +729,7 @@ hb_ft_font_set_funcs (hb_font_t *font)
if (unlikely (!blob_length))
DEBUG_MSG (FT, font, "Font face has empty blob");
FT_Face ft_face = NULL;
FT_Face ft_face = nullptr;
FT_Error err = FT_New_Memory_Face (get_ft_library (),
(const FT_Byte *) blob_data,
blob_length,
@ -675,7 +742,8 @@ hb_ft_font_set_funcs (hb_font_t *font)
return;
}
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
FT_Set_Char_Size (ft_face,
abs (font->x_scale), abs (font->y_scale),
@ -688,9 +756,25 @@ hb_ft_font_set_funcs (hb_font_t *font)
{
FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
0, font->y_scale < 0 ? -1 : +1};
FT_Set_Transform (ft_face, &matrix, NULL);
FT_Set_Transform (ft_face, &matrix, nullptr);
}
#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
unsigned int num_coords;
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
if (num_coords)
{
FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
if (ft_coords)
{
for (unsigned int i = 0; i < num_coords; i++)
ft_coords[i] = coords[i] << 2;
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
free (ft_coords);
}
}
#endif
ft_face->generic.data = blob;
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;

View File

@ -116,7 +116,13 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
HB_EXTERN int
hb_ft_font_get_load_flags (hb_font_t *font);
/* Makes an hb_font_t use FreeType internally to implement font functions. */
/* Call when size or variations settings on underlying FT_Face change. */
HB_EXTERN void
hb_ft_font_changed (hb_font_t *font);
/* Makes an hb_font_t use FreeType internally to implement font functions.
* Note: this internally creates an FT_Face. Use it when you create your
* hb_face_t using hb_face_create(). */
HB_EXTERN void
hb_ft_font_set_funcs (hb_font_t *font);

View File

@ -364,22 +364,52 @@ hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED,
return utf8_decomposed_len;
}
static hb_unicode_funcs_t *static_glib_funcs = nullptr;
#ifdef HB_USE_ATEXIT
static
void free_static_glib_funcs (void)
{
hb_unicode_funcs_destroy (static_glib_funcs);
}
#endif
hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void)
{
static const hb_unicode_funcs_t _hb_glib_unicode_funcs = {
HB_OBJECT_HEADER_STATIC,
retry:
hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs);
NULL, /* parent */
true, /* immutable */
{
#define HB_UNICODE_FUNC_IMPLEMENT(name) hb_glib_unicode_##name,
if (unlikely (!funcs))
{
funcs = hb_unicode_funcs_create (nullptr);
#define HB_UNICODE_FUNC_IMPLEMENT(name) \
hb_unicode_funcs_set_##name##_func (funcs, hb_glib_unicode_##name, nullptr, nullptr);
HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_UNICODE_FUNC_IMPLEMENT
hb_unicode_funcs_make_immutable (funcs);
if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, nullptr, funcs)) {
hb_unicode_funcs_destroy (funcs);
goto retry;
}
#ifdef HB_USE_ATEXIT
atexit (free_static_glib_funcs); /* First person registers atexit() callback. */
#endif
};
return const_cast<hb_unicode_funcs_t *> (&_hb_glib_unicode_funcs);
return hb_unicode_funcs_reference (funcs);
}
#if GLIB_CHECK_VERSION(2,31,10)
static void
_hb_g_bytes_unref (void *data)
{
g_bytes_unref ((GBytes *) data);
}
/**
@ -396,5 +426,6 @@ hb_glib_blob_create (GBytes *gbytes)
size,
HB_MEMORY_MODE_READONLY,
g_bytes_ref (gbytes),
(hb_destroy_func_t) g_bytes_unref);
_hb_g_bytes_unref);
}
#endif

View File

@ -46,9 +46,10 @@ hb_glib_script_from_script (hb_script_t script);
HB_EXTERN hb_unicode_funcs_t *
hb_glib_get_unicode_funcs (void);
#if GLIB_CHECK_VERSION(2,31,10)
HB_EXTERN hb_blob_t *
hb_glib_blob_create (GBytes *gbytes);
#endif
HB_END_DECLS

View File

@ -42,7 +42,8 @@ HB_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN value-header ***/
HB_EXTERN GType @enum_name@_get_type (void) G_GNUC_CONST;
HB_EXTERN GType
@enum_name@_get_type (void) G_GNUC_CONST;
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
/*** END value-header ***/

View File

@ -58,7 +58,7 @@ hb_gobject_##name##_get_type (void) \
static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
{ \
hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
if (unlikely (!c)) return NULL; \
if (unlikely (!c)) return nullptr; \
*c = *l; \
return c; \
} \
@ -78,3 +78,6 @@ HB_DEFINE_VALUE_TYPE (glyph_info)
HB_DEFINE_VALUE_TYPE (glyph_position)
HB_DEFINE_VALUE_TYPE (segment_properties)
HB_DEFINE_VALUE_TYPE (user_data_key)
HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)

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