mirror of
https://gitee.com/openharmony/third_party_harfbuzz
synced 2024-11-26 17:00:46 +00:00
Description: harfbuzz升级到2.8.2
IssueNo: https://gitee.com/openharmony/third_party_harfbuzz/issues/I8KEZE Feature or Bugfix: Feature Binary Source:No Signed-off-by: wyk99 <wangyuekai1@huawei.com>
This commit is contained in:
parent
c11ddb09fb
commit
b452025fb8
@ -1,15 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
meson --cross-file=.ci/win32-cross-file.txt win32build --wrap-mode=forcefallback -Dtests=disabled \
|
||||
-Dglib=enabled -Dfreetype=enabled -Dgdi=enabled -Ddirectwrite=enabled -Dcairo=enabled --buildtype=release $@
|
||||
ninja -Cwin32build -j3 # building with all the cores won't work fine with CricleCI for some reason
|
||||
|
||||
rm -rf win32build/harfbuzz-win32
|
||||
mkdir win32build/harfbuzz-win32
|
||||
cp win32build/util/hb-*.exe win32build/harfbuzz-win32
|
||||
find win32build -name '*.dll' -exec cp {} win32build/harfbuzz-win32 \;
|
||||
i686-w64-mingw32-strip win32build/harfbuzz-win32/*.{dll,exe}
|
||||
rm -f harfbuzz-win32.zip
|
||||
(cd win32build && zip -r ../harfbuzz-win32.zip harfbuzz-win32)
|
||||
echo "harfbuzz-win32.zip is ready."
|
@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set -o errexit -o nounset
|
||||
|
||||
TAG="$(git describe --exact-match --match "[0-9]*" HEAD 2>/dev/null || true)"
|
||||
|
||||
DOCSDIR=build-docs
|
||||
REVISION=$(git rev-parse --short HEAD)
|
||||
|
||||
rm -rf $DOCSDIR || exit
|
||||
mkdir $DOCSDIR
|
||||
cd $DOCSDIR
|
||||
|
||||
cp ../build/docs/html/* .
|
||||
#cp ../build/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/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/master
|
||||
|
||||
touch .
|
||||
git add -A .
|
||||
|
||||
if [[ $(git status -s) ]]; then
|
||||
git commit -m "Rebuild docs for https://github.com/harfbuzz/harfbuzz/commit/$REVISION"
|
||||
git push -q upstream HEAD:master
|
||||
fi
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if [[ -z $GITHUB_TOKEN ]]; then
|
||||
echo "No GITHUB_TOKEN secret found, artifact publishing skipped"
|
||||
exit
|
||||
fi
|
||||
|
||||
mkdir -p $HOME/.local/bin
|
||||
export _GHR_VER=v0.13.0
|
||||
export _GHR=ghr_${_GHR_VER}_linux_amd64
|
||||
curl -sfL https://github.com/tcnksm/ghr/releases/download/$_GHR_VER/$_GHR.tar.gz |
|
||||
tar xz -C $HOME/.local/bin --strip-components=1 $_GHR/ghr
|
||||
|
||||
ghr -replace \
|
||||
-u $CIRCLE_PROJECT_USERNAME \
|
||||
-r $CIRCLE_PROJECT_REPONAME \
|
||||
$CIRCLE_TAG \
|
||||
$1
|
@ -1,20 +0,0 @@
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86'
|
||||
cpu = 'i686'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
c_args = []
|
||||
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
|
||||
cpp_args = []
|
||||
cpp_link_args = ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lpthread']
|
||||
|
||||
[binaries]
|
||||
c = 'i686-w64-mingw32-gcc'
|
||||
cpp = 'i686-w64-mingw32-g++'
|
||||
ar = 'i686-w64-mingw32-ar'
|
||||
ld = 'i686-w64-mingw32-ld'
|
||||
objcopy = 'i686-w64-mingw32-objcopy'
|
||||
strip = 'i686-w64-mingw32-strip'
|
||||
windres = 'i686-w64-mingw32-windres'
|
@ -1,20 +0,0 @@
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
c_args = []
|
||||
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
|
||||
cpp_args = []
|
||||
cpp_link_args = ['-static-libgcc', '-static-libstdc++', '-Wl,-Bstatic', '-lpthread']
|
||||
|
||||
[binaries]
|
||||
c = 'x86_64-w64-mingw32-gcc'
|
||||
cpp = 'x86_64-w64-mingw32-g++'
|
||||
ar = 'x86_64-w64-mingw32-ar'
|
||||
ld = 'x86_64-w64-mingw32-ld'
|
||||
objcopy = 'x86_64-w64-mingw32-objcopy'
|
||||
strip = 'x86_64-w64-mingw32-strip'
|
||||
windres = 'x86_64-w64-mingw32-windres'
|
@ -1,176 +0,0 @@
|
||||
version: 2.1
|
||||
|
||||
executors:
|
||||
win32-executor:
|
||||
docker:
|
||||
- image: cimg/base:edge-20.04
|
||||
autotools-executor:
|
||||
docker:
|
||||
- image: cimg/base:edge-20.04
|
||||
|
||||
jobs:
|
||||
|
||||
macos-10_14_4-aat-fonts:
|
||||
macos:
|
||||
xcode: "11.1.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 ninja
|
||||
- run: pip3 install meson --upgrade
|
||||
- run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled
|
||||
- run: meson compile -Cbuild
|
||||
- run: meson test -Cbuild --print-errorlogs
|
||||
- store_artifacts:
|
||||
path: build/meson-logs/
|
||||
|
||||
macos-10_15_3-aat-fonts:
|
||||
macos:
|
||||
xcode: "11.4.0"
|
||||
steps:
|
||||
- checkout
|
||||
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection gtk-doc ninja
|
||||
- run: pip3 install meson --upgrade
|
||||
- run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled
|
||||
- run: meson compile -Cbuild
|
||||
- run: meson test -Cbuild --print-errorlogs
|
||||
- store_artifacts:
|
||||
path: build/meson-logs/
|
||||
|
||||
# will be dropped with autotools removal
|
||||
distcheck:
|
||||
executor: autotools-executor
|
||||
steps:
|
||||
- checkout
|
||||
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y git ninja-build binutils libtool autoconf automake make gcc g++ pkg-config ragel gtk-doc-tools gobject-introspection libfreetype6-dev libglib2.0-dev libgirepository1.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip
|
||||
- run: pip3 install fonttools meson --upgrade
|
||||
- run: ./autogen.sh
|
||||
- run: make -j2 distcheck
|
||||
- run: rm harfbuzz-* && make distdir
|
||||
- run: cd harfbuzz-* && meson build && ninja -j2 -Cbuild test
|
||||
- run: make dist
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: harfbuzz-*.tar.xz
|
||||
|
||||
publish-dist:
|
||||
executor: autotools-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: |
|
||||
.ci/publish_release_artifact.sh harfbuzz-$CIRCLE_TAG.tar.xz
|
||||
|
||||
fedora-valgrind:
|
||||
docker:
|
||||
- image: fedora:33
|
||||
steps:
|
||||
- checkout
|
||||
- run: dnf install -y pkg-config ragel valgrind gcc gcc-c++ meson git glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip || true
|
||||
- run: meson build --buildtype=debugoptimized
|
||||
- run: ninja -Cbuild -j9
|
||||
# TOOD: increase timeouts and remove --no-suite=slow
|
||||
- run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs
|
||||
|
||||
alpine:
|
||||
docker:
|
||||
- image: alpine
|
||||
steps:
|
||||
- checkout
|
||||
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
|
||||
- run: pip3 install meson==0.47.0
|
||||
- run: meson build --buildtype=minsize
|
||||
- run: ninja -Cbuild -j9
|
||||
- run: meson test -Cbuild --print-errorlogs
|
||||
|
||||
archlinux:
|
||||
docker:
|
||||
- image: archlinux/base
|
||||
steps:
|
||||
- checkout
|
||||
- run: pacman --noconfirm -Syu freetype2 meson git clang cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip base-devel gtk-doc
|
||||
- run: pip install flake8 fonttools
|
||||
- run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
|
||||
- run: meson build -Dgraphite=enabled -Dauto_features=enabled -Dexperimental_api=true
|
||||
- run: meson compile -Cbuild -j9
|
||||
- run: meson test -Cbuild --print-errorlogs
|
||||
- run: meson dist -Cbuild
|
||||
- run: clang -c src/harfbuzz.cc -DHB_NO_MT
|
||||
- run: clang -c src/hb-*.cc -DHB_NO_MT -DHB_TINY -DHB_NO_OT_FONT
|
||||
|
||||
sanitizers:
|
||||
docker:
|
||||
- image: ubuntu:20.04
|
||||
steps:
|
||||
- checkout
|
||||
- run: apt update || true
|
||||
- run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils meson pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
|
||||
# asan+ubsan
|
||||
- run: rm -rf build && meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
|
||||
- run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
|
||||
# tsan
|
||||
- run: rm -rf build && meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
|
||||
- run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
|
||||
# msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
|
||||
- run: rm -rf build && meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
|
||||
- run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
|
||||
- run: clang -c src/harfbuzz.cc src/hb-subset*.cc -DHB_NO_MT -Werror -std=c++2a
|
||||
|
||||
crossbuild-win32:
|
||||
executor: win32-executor
|
||||
steps:
|
||||
- checkout
|
||||
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build binutils gcc g++ pkg-config ragel gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-pip git g++-mingw-w64-i686 zip
|
||||
- run: pip3 install meson==0.56.0 --upgrade
|
||||
- run: .ci/build-win32.sh
|
||||
- store_artifacts:
|
||||
path: harfbuzz-win32.zip
|
||||
- persist_to_workspace:
|
||||
root: .
|
||||
paths: harfbuzz-win32.zip
|
||||
|
||||
publish-win32:
|
||||
executor: win32-executor
|
||||
steps:
|
||||
- checkout
|
||||
- attach_workspace:
|
||||
at: .
|
||||
- run: |
|
||||
mv harfbuzz-win32{,-$CIRCLE_TAG}.zip
|
||||
.ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
|
||||
build:
|
||||
jobs:
|
||||
- macos-10_14_4-aat-fonts
|
||||
- macos-10_15_3-aat-fonts
|
||||
- distcheck: # will be dropped with autotools removal
|
||||
filters:
|
||||
tags:
|
||||
only: /^\d+.\d+.\d+$/
|
||||
- publish-dist:
|
||||
requires:
|
||||
- distcheck
|
||||
filters:
|
||||
tags:
|
||||
only: /^\d+\.\d+\.\d+$/
|
||||
branches:
|
||||
ignore: /.*/
|
||||
- fedora-valgrind
|
||||
- alpine
|
||||
#- archlinux
|
||||
- sanitizers
|
||||
- crossbuild-win32:
|
||||
filters:
|
||||
tags:
|
||||
only: /^\d+.\d+.\d+$/
|
||||
- publish-win32:
|
||||
requires:
|
||||
- crossbuild-win32
|
||||
filters:
|
||||
tags:
|
||||
only: /^\d+\.\d+\.\d+$/
|
||||
branches:
|
||||
ignore: /.*/
|
@ -1,38 +0,0 @@
|
||||
# The following tries to match the current code style, is imperfect for now
|
||||
# but good for new codes be added
|
||||
|
||||
IndentWidth: 2
|
||||
TabWidth: 8
|
||||
UseTab: Always
|
||||
SpaceBeforeParens: Always
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterEnum: true
|
||||
AfterStruct: false
|
||||
SplitEmptyFunction: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeElse: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AlignTrailingComments: true
|
||||
AlignEscapedNewlines: Left
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
SpaceAfterCStyleCast: true
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
BinPackParameters: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AccessModifierOffset: 0
|
||||
AlignTrailingComments: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignOperands: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
|
||||
# We like to have this only for function parameters and structs fields, not always
|
||||
# AlignConsecutiveDeclarations: true
|
@ -1,7 +0,0 @@
|
||||
comment: off
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
@ -1,23 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{c,cc,h,hh,rl}]
|
||||
tab_width = 8
|
||||
indent_size = 2
|
||||
indent_style = tab # should be space
|
||||
|
||||
[*.{py,sh}]
|
||||
indent_style = tab
|
||||
|
||||
[{Makefile.am,Makefile.sources,configure.ac}]
|
||||
tab_width = 8
|
||||
|
||||
[{meson.build,meson_options.txt}]
|
||||
tab_width = 8
|
||||
indent_style = space
|
||||
indent_size = 2
|
@ -1,11 +0,0 @@
|
||||
### 该问题是怎么引起的?
|
||||
|
||||
|
||||
|
||||
### 重现步骤
|
||||
|
||||
|
||||
|
||||
### 报错信息
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
### 相关的Issue
|
||||
|
||||
|
||||
### 原因(目的、解决的问题等)
|
||||
|
||||
|
||||
### 描述(做了什么,变更了什么)
|
||||
|
||||
|
||||
### 测试用例(新增、改动、可能影响的功能)
|
||||
|
||||
|
39
.github/workflows/coverity-scan.yml
vendored
39
.github/workflows/coverity-scan.yml
vendored
@ -1,39 +0,0 @@
|
||||
name: coverity-scan
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 10 * * *' # Daily at 10:00 UTC
|
||||
|
||||
jobs:
|
||||
latest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev
|
||||
|
||||
- name: Download Coverity
|
||||
run: |
|
||||
wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=behdad/harfbuzz" -O cov-analysis-linux64.tar.gz
|
||||
mkdir cov-analysis-linux64
|
||||
tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
||||
|
||||
# ideally we should've used meson and ninja here but it complains about coverage or something
|
||||
- run: cov-analysis-linux64/bin/cov-build --dir cov-int clang src/hb-*.cc -DHAVE_FREETYPE -DHAVE_GRAPHITE2 -DHAVE_GLIB -DHAVE_ICU `pkg-config --cflags freetype2 graphite2 glib-2.0 icu-uc` -DHAVE_ROUNDF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H -DHAVE_GETPAGESIZE -DHB_EXPERIMENTAL_API -c
|
||||
|
||||
- run: tar czvf harfbuzz.tgz cov-int
|
||||
|
||||
- name: submit to coverity
|
||||
run: |
|
||||
curl \
|
||||
--form project=behdad/harfbuzz \
|
||||
--form token=$TOKEN \
|
||||
--form email=harfbuzz-bots-chatter@googlegroups.com \
|
||||
--form file=@harfbuzz.tgz \
|
||||
--form version=trunk \
|
||||
--form description="`git rev-parse --short HEAD`" \
|
||||
https://scan.coverity.com/builds?project=behdad-harfbuzz
|
||||
env:
|
||||
TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
|
53
.github/workflows/linux-ci.yml
vendored
53
.github/workflows/linux-ci.yml
vendored
@ -1,53 +0,0 @@
|
||||
name: linux-ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: sudo apt-get install pkg-config gcc ragel gcovr gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-setuptools ninja-build gobject-introspection libgirepository1.0-dev
|
||||
- run: sudo pip3 install fonttools meson==0.47.0
|
||||
- name: run
|
||||
run: meson build -Db_coverage=true --auto-features=enabled -Dgraphite=enabled -Dchafa=disabled -Doptimization=2
|
||||
- name: ci
|
||||
run: meson test --print-errorlogs -Cbuild
|
||||
|
||||
- name: generate documentations
|
||||
run: ninja -Cbuild harfbuzz-doc
|
||||
- name: deploy documentations
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
run: .ci/deploy-docs.sh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_TOKEN }}
|
||||
REVISION: ${{ github.sha }}
|
||||
|
||||
# waiting for https://github.com/rhysd/github-action-benchmark/issues/36 to happen
|
||||
# - name: benchmark
|
||||
# run: build/perf/perf --benchmark_format=json > perf/result.json
|
||||
# - name: store benchmark result
|
||||
# uses: rhysd/github-action-benchmark@b2ee598
|
||||
# if: github.event_name != 'pull_request'
|
||||
# with:
|
||||
# name: C++ Benchmark
|
||||
# tool: 'googlecpp'
|
||||
# output-file-path: perf/result.json
|
||||
# gh-pages-branch: gh-pages
|
||||
# github-token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
|
||||
# auto-push: true
|
||||
# alert-threshold: '150%'
|
||||
# comment-on-alert: true
|
||||
# fail-on-alert: true
|
||||
|
||||
- name: cov
|
||||
run: ninja -Cbuild coverage
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: build/meson-logs/coverage.xml
|
52
.github/workflows/msvc-ci.yml
vendored
52
.github/workflows/msvc-ci.yml
vendored
@ -1,52 +0,0 @@
|
||||
name: msvc
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
msvc:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-2016, windows-latest]
|
||||
include:
|
||||
- name: msvc-2017-x86
|
||||
os: windows-2016
|
||||
ARCH: x86
|
||||
- name: msvc-2019-amd64
|
||||
os: windows-latest
|
||||
ARCH: amd64
|
||||
name: ${{ matrix.name }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch : ${{ matrix.ARCH }}
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
pip install --upgrade meson ninja fonttools
|
||||
- name: Build
|
||||
run: |
|
||||
# This dir contains a pkg-config which meson will happily use and later fail, so remove it
|
||||
$env:path = ($env:path.Split(';') | Where-Object { $_ -ne 'C:\Strawberry\perl\bin' }) -join ';'
|
||||
|
||||
meson setup build `
|
||||
--wrap-mode=default `
|
||||
--buildtype=release `
|
||||
-Dglib=enabled `
|
||||
-Dfreetype=enabled `
|
||||
-Dgdi=enabled `
|
||||
-Ddirectwrite=enabled
|
||||
|
||||
meson compile -C build
|
||||
- name: Test
|
||||
run: |
|
||||
meson test --print-errorlogs --suite=harfbuzz -C build
|
65
.github/workflows/msys2-ci.yml
vendored
65
.github/workflows/msys2-ci.yml
vendored
@ -1,65 +0,0 @@
|
||||
name: msys2
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
msys2:
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- MSYSTEM: MINGW32
|
||||
MSYS2_ARCH: i686
|
||||
- MSYSTEM: MINGW64
|
||||
MSYS2_ARCH: x86_64
|
||||
name: ${{ matrix.MSYSTEM }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.MSYSTEM }}
|
||||
update: true
|
||||
install: >-
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-icu
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-meson
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-python
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip
|
||||
mingw-w64-${{ matrix.MSYS2_ARCH }}-ragel
|
||||
- name: Install Python Dependencies
|
||||
run: |
|
||||
pip install --upgrade fonttools
|
||||
- name: Build
|
||||
run: |
|
||||
meson build \
|
||||
--wrap-mode=nodownload \
|
||||
--auto-features=enabled \
|
||||
-Ddirectwrite=enabled \
|
||||
-Dgdi=enabled \
|
||||
-Dgraphite=enabled \
|
||||
-Dchafa=disabled
|
||||
ninja -C build
|
||||
- name: Test
|
||||
run: |
|
||||
meson test \
|
||||
--print-errorlogs \
|
||||
--suite=harfbuzz \
|
||||
-C build
|
14
AUTHORS
14
AUTHORS
@ -1,14 +0,0 @@
|
||||
Behdad Esfahbod
|
||||
David Corbett
|
||||
David Turner
|
||||
Ebrahim Byagowi
|
||||
Garret Rieger
|
||||
Jonathan Kew
|
||||
Khaled Hosny
|
||||
Lars Knoll
|
||||
Martin Hosken
|
||||
Owen Taylor
|
||||
Roderick Sheeter
|
||||
Roozbeh Pournader
|
||||
Simon Hausmann
|
||||
Werner Lemberg
|
125
BUILD.gn
Executable file → Normal file
125
BUILD.gn
Executable file → Normal file
@ -14,63 +14,77 @@ if (defined(ohos_lite)) {
|
||||
import("//build/ohos.gni")
|
||||
}
|
||||
config("harfbuzz_config") {
|
||||
include_dirs = [ "//third_party/harfbuzz/src" ]
|
||||
include_dirs = [ "${target_gen_dir}/harfbuzz-2.8.2/src" ]
|
||||
}
|
||||
|
||||
harfbuzz_source = [
|
||||
"//third_party/harfbuzz/src/hb-aat-layout.cc",
|
||||
"//third_party/harfbuzz/src/hb-aat-map.cc",
|
||||
"//third_party/harfbuzz/src/hb-blob.cc",
|
||||
"//third_party/harfbuzz/src/hb-buffer-serialize.cc",
|
||||
"//third_party/harfbuzz/src/hb-buffer.cc",
|
||||
"//third_party/harfbuzz/src/hb-common.cc",
|
||||
"//third_party/harfbuzz/src/hb-face.cc",
|
||||
"//third_party/harfbuzz/src/hb-fallback-shape.cc",
|
||||
"//third_party/harfbuzz/src/hb-font.cc",
|
||||
"//third_party/harfbuzz/src/hb-map.cc",
|
||||
"//third_party/harfbuzz/src/hb-number.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-cff1-table.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-cff2-table.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-face.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-font.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-layout.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-map.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-math.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-meta.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-metrics.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-name.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-arabic.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-default.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-hangul.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-hebrew.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-indic-table.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-indic.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-khmer.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-myanmar.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-syllabic.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-thai.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-use.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-fallback.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape-normalize.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-shape.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-tag.cc",
|
||||
"//third_party/harfbuzz/src/hb-ot-var.cc",
|
||||
"//third_party/harfbuzz/src/hb-set.cc",
|
||||
"//third_party/harfbuzz/src/hb-shape-plan.cc",
|
||||
"//third_party/harfbuzz/src/hb-shape.cc",
|
||||
"//third_party/harfbuzz/src/hb-shaper.cc",
|
||||
"//third_party/harfbuzz/src/hb-static.cc",
|
||||
"//third_party/harfbuzz/src/hb-subset-cff2.cc",
|
||||
"//third_party/harfbuzz/src/hb-subset-cff-common.cc",
|
||||
"//third_party/harfbuzz/src/hb-ucd.cc",
|
||||
"//third_party/harfbuzz/src/hb-unicode.cc",
|
||||
]
|
||||
action("harfbuzz_action") {
|
||||
script = "//third_party/harfbuzz/install.py"
|
||||
outputs = [
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-aat-layout.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-aat-map.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-blob.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-buffer-serialize.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-buffer.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-common.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-face.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-fallback-shape.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-font.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-map.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-number.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-cff1-table.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-cff2-table.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-face.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-font.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-layout.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-map.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-math.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-meta.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-metrics.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-name.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-arabic.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-default.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-hangul.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-hebrew.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-indic-table.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-indic.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-khmer.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-myanmar.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-syllabic.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-thai.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-use.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-complex-vowel-constraints.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-fallback.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape-normalize.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-shape.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-tag.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ot-var.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-set.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-shape-plan.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-shape.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-shaper.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-static.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-subset-cff2.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-subset-cff-common.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-ucd.cc",
|
||||
"${target_gen_dir}/harfbuzz-2.8.2/src/hb-unicode.cc",
|
||||
]
|
||||
|
||||
inputs = [ "//third_party/harfbuzz/harfbuzz-2.8.2.tar.xz" ]
|
||||
harfbuzz_path = rebase_path("${target_gen_dir}", root_build_dir)
|
||||
harfbuzz_source_path = rebase_path("//third_party/harfbuzz", root_build_dir)
|
||||
args = [
|
||||
"--gen-dir",
|
||||
"$harfbuzz_path",
|
||||
"--source-dir",
|
||||
"$harfbuzz_source_path",
|
||||
]
|
||||
}
|
||||
|
||||
if (defined(ohos_lite)) {
|
||||
lite_library("harfbuzz") {
|
||||
output_name = "harfbuzz"
|
||||
sources = harfbuzz_source
|
||||
sources = get_target_outputs(":harfbuzz_action")
|
||||
deps = [ ":harfbuzz_action" ]
|
||||
public_configs = [ ":harfbuzz_config" ]
|
||||
if (defined(board_toolchain_type) && board_toolchain_type == "iccarm") {
|
||||
target_type = "static_library"
|
||||
@ -91,11 +105,12 @@ if (defined(ohos_lite)) {
|
||||
}
|
||||
} else {
|
||||
ohos_static_library("harfbuzz_static") {
|
||||
output_dir = "${root_out_dir}/thirdparty/harfbuzz"
|
||||
output_name = "harfbuzz"
|
||||
sources = harfbuzz_source
|
||||
include_dirs = [ "src\base" ]
|
||||
sources = get_target_outputs(":harfbuzz_action")
|
||||
deps = [ ":harfbuzz_action" ]
|
||||
include_dirs = [ "${target_gen_dir}/harfbuzz-2.8.2/src" ]
|
||||
defines = [ "HAVE_PTHREAD = 1" ]
|
||||
public_configs = [ ":harfbuzz_config" ]
|
||||
part_name = "harfbuzz"
|
||||
subsystem_name = "thirdparty"
|
||||
}
|
||||
}
|
||||
|
27
BUILD.md
27
BUILD.md
@ -1,27 +0,0 @@
|
||||
On Linux, install the development packages for FreeType,
|
||||
Cairo, and GLib. For example, on Ubuntu / Debian, you would do:
|
||||
|
||||
sudo apt-get install meson pkg-config ragel gtk-doc-tools gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev
|
||||
|
||||
whereas on Fedora, RHEL, CentOS, and other Red Hat based systems you would do:
|
||||
|
||||
sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-dev
|
||||
|
||||
and on ArchLinux and Manjaro:
|
||||
|
||||
sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
|
||||
|
||||
then use meson to build the project like `meson build && meson test -Cbuild`.
|
||||
|
||||
On macOS, `brew install pkg-config ragel gtk-doc freetype glib cairo meson` then use
|
||||
meson like above.
|
||||
|
||||
On Windows, meson can build the project like above if a working MSVC's cl.exe (`vcvarsall.bat`)
|
||||
or gcc/clang is already on your path, and if you use something like `meson build --wrap-mode=default`
|
||||
it fetches and compiles most of the dependencies also.
|
||||
|
||||
Our CI configurations is also a good source of learning how to build HarfBuzz.
|
||||
|
||||
There is also amalgam source provided with HarfBuzz which reduces whole process of building
|
||||
HarfBuzz like `g++ src/harfbuzz.cc -fno-exceptions` but there is not guarantee provided
|
||||
with buildability and reliability of features you get.
|
744
CMakeLists.txt
744
CMakeLists.txt
@ -1,744 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.0.0)
|
||||
project(harfbuzz)
|
||||
|
||||
message(WARN "HarfBuzz has a Meson port and tries to migrate all the other build systems to it, please consider using it as we might remove our cmake port soon.")
|
||||
|
||||
## 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_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_GDI "Enable GDI integration helpers on Windows" OFF)
|
||||
option(HB_HAVE_DIRECTWRITE "Enable DirectWrite shaper backend on Windows" OFF)
|
||||
endif ()
|
||||
option(HB_BUILD_UTILS "Build harfbuzz utils, needs cairo, freetype, and glib properly be installed" OFF)
|
||||
if (HB_BUILD_UTILS)
|
||||
set (HB_HAVE_GLIB ON)
|
||||
set (HB_HAVE_FREETYPE ON)
|
||||
endif ()
|
||||
|
||||
option(HB_BUILD_SUBSET "Build harfbuzz-subset" ON)
|
||||
|
||||
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 ()
|
||||
|
||||
include_directories(AFTER
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_BINARY_DIR}/src
|
||||
)
|
||||
|
||||
# We need PYTHON_EXECUTABLE to be set for running the tests...
|
||||
include (FindPythonInterp)
|
||||
|
||||
## 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} definition_to_add)
|
||||
check_function_exists(${func_name} HAVE_${definition_to_add})
|
||||
if (${HAVE_${definition_to_add}})
|
||||
add_definitions(-DHAVE_${definition_to_add})
|
||||
endif ()
|
||||
endforeach ()
|
||||
endmacro ()
|
||||
if (UNIX)
|
||||
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
|
||||
endif ()
|
||||
check_funcs(atexit mprotect sysconf getpagesize mmap isatty)
|
||||
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(stdbool.h HAVE_STDBOOL_H)
|
||||
if (${HAVE_STDBOOL_H})
|
||||
add_definitions(-DHAVE_STDBOOL_H)
|
||||
endif ()
|
||||
|
||||
# https://github.com/harfbuzz/harfbuzz/pull/2874#issuecomment-782859099
|
||||
if (NOT WIN32)
|
||||
add_definitions("-DHAVE_PTHREAD")
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
add_definitions(-wd4244 -wd4267 -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
|
||||
endif ()
|
||||
|
||||
|
||||
## Detect if we are running inside a distribution or regular repository folder
|
||||
# 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 ()
|
||||
|
||||
# https://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)
|
||||
|
||||
extract_make_variable(HB_BASE_headers ${SRCSOURCES})
|
||||
add_prefix_to_list(HB_BASE_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})
|
||||
#if (IN_HB_DIST)
|
||||
add_prefix_to_list(HB_BASE_RAGEL_GENERATED_sources "${PROJECT_SOURCE_DIR}/src/")
|
||||
#else ()
|
||||
# add_prefix_to_list(HB_BASE_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/")
|
||||
|
||||
|
||||
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 sources and headers of the project
|
||||
set (project_sources ${PROJECT_SOURCE_DIR}/src/harfbuzz.cc) # use amalgam source
|
||||
set (subset_project_sources ${HB_SUBSET_sources})
|
||||
set (project_extra_sources)
|
||||
set (project_headers ${HB_BASE_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_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_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_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_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/fdd7733f2f30eab7fe096a9791f98c60f62f49c0/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_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_headers ${PROJECT_SOURCE_DIR}/src/hb-coretext.h)
|
||||
|
||||
if (HB_IOS)
|
||||
find_library(COREFOUNDATION CoreFoundation)
|
||||
if (COREFOUNDATION)
|
||||
list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
|
||||
endif ()
|
||||
mark_as_advanced(COREFOUNDATION)
|
||||
|
||||
find_library(CORETEXT CoreText)
|
||||
if (CORETEXT)
|
||||
list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
|
||||
endif ()
|
||||
mark_as_advanced(CORETEXT)
|
||||
|
||||
find_library(COREGRAPHICS CoreGraphics)
|
||||
if (COREGRAPHICS)
|
||||
list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS})
|
||||
endif ()
|
||||
mark_as_advanced(COREGRAPHICS)
|
||||
else ()
|
||||
find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices)
|
||||
if (APPLICATION_SERVICES_FRAMEWORK)
|
||||
list(APPEND THIRD_PARTY_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND HB_HAVE_GDI)
|
||||
add_definitions(-DHAVE_GDI)
|
||||
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
|
||||
list(APPEND THIRD_PARTY_LIBS gdi32)
|
||||
endif ()
|
||||
|
||||
if (WIN32 AND HB_HAVE_UNISCRIBE)
|
||||
add_definitions(-DHAVE_UNISCRIBE)
|
||||
list(APPEND project_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_headers ${PROJECT_SOURCE_DIR}/src/hb-directwrite.h)
|
||||
list(APPEND THIRD_PARTY_LIBS dwrite rpcrt4)
|
||||
endif ()
|
||||
|
||||
if (HB_HAVE_GOBJECT)
|
||||
add_definitions(-DHAVE_GOBJECT)
|
||||
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 ()
|
||||
|
||||
|
||||
## Define harfbuzz library
|
||||
add_library(harfbuzz ${project_sources} ${project_extra_sources} ${project_headers})
|
||||
target_link_libraries(harfbuzz ${THIRD_PARTY_LIBS})
|
||||
target_include_directories(harfbuzz PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
|
||||
|
||||
## Define harfbuzz-icu library
|
||||
if (HB_HAVE_ICU)
|
||||
add_library(harfbuzz-icu ${PROJECT_SOURCE_DIR}/src/hb-icu.cc ${PROJECT_SOURCE_DIR}/src/hb-icu.h)
|
||||
add_dependencies(harfbuzz-icu harfbuzz)
|
||||
target_link_libraries(harfbuzz-icu harfbuzz ${THIRD_PARTY_LIBS})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz harfbuzz-icu PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
## Define harfbuzz-subset library
|
||||
if (HB_BUILD_SUBSET)
|
||||
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
|
||||
add_dependencies(harfbuzz-subset harfbuzz)
|
||||
target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (UNIX OR MINGW)
|
||||
# Make symbols link locally
|
||||
include (CheckCXXCompilerFlag)
|
||||
CHECK_CXX_COMPILER_FLAG(-Bsymbolic-functions CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
|
||||
if (CXX_SUPPORTS_FLAG_BSYMB_FUNCS)
|
||||
link_libraries(-Bsymbolic-functions)
|
||||
endif ()
|
||||
|
||||
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)
|
||||
if (HB_BUILD_SUBSET)
|
||||
set_target_properties(harfbuzz-subset PROPERTIES LINKER_LANGUAGE C)
|
||||
endif ()
|
||||
|
||||
# No threadsafe statics as we do it ourselves
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics")
|
||||
endif ()
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
|
||||
if (COMPILER_SUPPORTS_CXX11)
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
else()
|
||||
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
|
||||
## Define harfbuzz-gobject library
|
||||
if (HB_HAVE_GOBJECT)
|
||||
add_library(harfbuzz-gobject
|
||||
${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})
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(harfbuzz-gobject PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (BUILD_SHARED_LIBS AND WIN32 AND NOT MINGW)
|
||||
add_definitions("-DHB_DLL_EXPORT")
|
||||
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 ()
|
||||
|
||||
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list)
|
||||
foreach (s ${introspected_sources})
|
||||
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list "${s}\n")
|
||||
endforeach ()
|
||||
|
||||
# Finally, build the introspection files...
|
||||
add_custom_command(
|
||||
TARGET harfbuzz-gobject
|
||||
POST_BUILD
|
||||
COMMAND ${G_IR_SCANNER_CMD}
|
||||
--warn-all --no-libtool --verbose
|
||||
--namespace=HarfBuzz
|
||||
--nsversion=0.0
|
||||
--symbol-prefix=hb
|
||||
--symbol-prefix=hb_gobject
|
||||
--identifier-prefix=hb_
|
||||
--include GObject-2.0
|
||||
--pkg-export=harfbuzz-gobject
|
||||
--c-include=hb-gobject.h
|
||||
--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_AAT_H
|
||||
-DHB_AAT_H_IN
|
||||
-DHB_GOBJECT_H
|
||||
-DHB_GOBJECT_H_IN
|
||||
-DHB_EXTERN=
|
||||
--cflags-end
|
||||
--library=harfbuzz-gobject
|
||||
--library=harfbuzz
|
||||
-L${hb_libpath}
|
||||
${extra_libs}
|
||||
--filelist ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list
|
||||
-o ${hb_libpath}/HarfBuzz-0.0.gir
|
||||
DEPENDS harfbuzz-gobject harfbuzz ${CMAKE_CURRENT_BINARY_DIR}/src/hb_gir_list
|
||||
)
|
||||
|
||||
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
|
||||
EXPORT harfbuzzConfig
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
FRAMEWORK DESTINATION Library/Frameworks
|
||||
)
|
||||
install(EXPORT harfbuzzConfig
|
||||
NAMESPACE harfbuzz::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
|
||||
)
|
||||
if (HB_HAVE_ICU)
|
||||
install(TARGETS harfbuzz-icu
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
FRAMEWORK DESTINATION Library/Frameworks
|
||||
)
|
||||
endif ()
|
||||
if (HB_BUILD_UTILS)
|
||||
if (WIN32 AND BUILD_SHARED_LIBS)
|
||||
install(TARGETS harfbuzz-subset
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
endif ()
|
||||
install(TARGETS hb-view
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
install(TARGETS hb-subset
|
||||
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 ()
|
150
CONFIG.md
150
CONFIG.md
@ -1,150 +0,0 @@
|
||||
# Configuring HarfBuzz
|
||||
|
||||
Most of the time you will not need any custom configuration. The configuration
|
||||
options provided by `meson` should be enough. In particular, if you just want
|
||||
HarfBuzz library plus hb-shape / hb-view utilities, make sure FreeType and Cairo
|
||||
are available and found during configuration.
|
||||
|
||||
If you are building for distribution, you should more carefully consider whether
|
||||
you need Glib, ICU, Graphite2, as well as CoreText / Uniscribe / DWrite. Make
|
||||
sure the relevant ones are enabled.
|
||||
|
||||
If you are building for custom environment (embedded, downloadable app, etc)
|
||||
where you mostly just want to call `hb_shape()` and the binary size of the
|
||||
resulting library is very important to you, the rest of this file guides you
|
||||
through your options to disable features you may not need, in exchange for
|
||||
binary size savings.
|
||||
|
||||
## Compiler Options
|
||||
|
||||
Make sure you build with your compiler's "optimize for size" option. On `gcc`
|
||||
this is `-Os`, and can be enabled by passing `CXXFLAGS=-Os`. On clang there
|
||||
is an even more extreme flag, `-Oz`. Meson also provides `--buildtype=minsize`
|
||||
for more convenience.
|
||||
|
||||
HarfBuzz heavily uses inline functions and the optimize-size flag can make the
|
||||
library smaller by 20% or more. Moreover, sometimes, based on the target CPU,
|
||||
the optimize-size builds perform *faster* as well, thanks to lower code
|
||||
footprint and caching effects. So, definitely try that even if size is not
|
||||
extremely tight but you have a huge application. For example, Chrome does
|
||||
that. Note that this configuration also automatically enables certain internal
|
||||
optimizations. Search for `HB_OPTIMIZE_SIZE` for details, if you are using
|
||||
other compilers, or continue reading.
|
||||
|
||||
Another compiler option to consider is "link-time optimization", also known as
|
||||
'lto'. To enable that, feel free to use `-Db_lto=true` of meson.
|
||||
This, also, can have a huge impact on the final size, 20% or more.
|
||||
|
||||
Finally, if you are making a static library build or otherwise linking the
|
||||
library into your app, make sure your linker removes unused functions. This
|
||||
can be tricky and differ from environment to environment, but you definitely
|
||||
want to make sure this happens. Otherwise, every unused public function will
|
||||
be adding unneeded bytes to your binary. The following pointers might come
|
||||
handy:
|
||||
|
||||
* https://lwn.net/Articles/741494/ (all of the four-part series)
|
||||
* https://elinux.org/images/2/2d/ELC2010-gc-sections_Denys_Vlasenko.pdf
|
||||
|
||||
Combining the above three build options should already shrink your library a lot.
|
||||
The rest of this file shows you ways to shrink the library even further at the
|
||||
expense of removing functionality (that may not be needed). The remaining
|
||||
options are all enabled by defining pre-processor macros, which can be done
|
||||
via `CXXFLAGS` or `CPPFLAGS` similarly.
|
||||
|
||||
|
||||
## Unicode-functions
|
||||
|
||||
Access to Unicode data can be configured at compile time as well as run-time.
|
||||
By default, HarfBuzz ships with its own compact subset of properties from
|
||||
Unicode Character Database that it needs. This is a highly-optimized
|
||||
implementation that depending on compile settings (optimize-size or not)
|
||||
takes around ~40kb or ~60kb. Using this implementation (default) is highly
|
||||
recommended, as HarfBuzz always ships with data from latest version of Unicode.
|
||||
This implementation can be disabled by defining `HB_NO_UCD`.
|
||||
|
||||
For example, if you are enabling ICU as a built-in option, or GLib, those
|
||||
can provide Unicode data as well, so defining `HB_NO_UCD` might save you
|
||||
space without reducing functionality (to the extent that the Unicode version
|
||||
of those implementations is recent.)
|
||||
|
||||
If, however, you provide your own Unicode data to HarfBuzz at run-time by
|
||||
calling `hb_buffer_set_unicode_funcs` on every buffer you create, and you do
|
||||
not rely on `hb_unicode_funcs_get_default()` results, you can disable the
|
||||
internal implementation by defining both `HB_NO_UCD` and `HB_NO_UNICODE_FUNCS`.
|
||||
The latter is needed to guard against accidentally building a library without
|
||||
any default Unicode implementations.
|
||||
|
||||
|
||||
## Font-functions
|
||||
|
||||
Access to certain font functionalities can also be configured at run-time. By
|
||||
default, HarfBuzz uses an efficient internal implementation of OpenType
|
||||
functionality for this. This internal implementation is called `hb-ot-font`.
|
||||
All newly-created `hb_font_t` objects by default use `hb-ot-font`. Using this
|
||||
is highly recommended, and is what fonts use by default when they are created.
|
||||
|
||||
Most embedded uses will probably use HarfBuzz with FreeType using `hb-ft.h`.
|
||||
In that case, or if you otherwise provide those functions by calling
|
||||
`hb_font_set_funcs()` on every font you create, you can disable `hb-ot-font`
|
||||
without loss of functionality by defining `HB_NO_OT_FONT`.
|
||||
|
||||
|
||||
## Shapers
|
||||
|
||||
Most HarfBuzz clients use it for the main shaper, called "ot". However, it
|
||||
is legitimate to want to compile HarfBuzz with only another backend, eg.
|
||||
CoreText, for example for an iOS app. For that, you want `HB_NO_OT_SHAPE`.
|
||||
If you are going down that route, check if you want `HB_NO_OT`.
|
||||
|
||||
This is very rarely what you need. Make sure you understand exactly what you
|
||||
are doing.
|
||||
|
||||
Defining `HB_NO_FALLBACK_SHAPE` however is pretty harmless. That removes the
|
||||
(unused) "fallback" shaper.
|
||||
|
||||
|
||||
## Thread-safety
|
||||
|
||||
By default HarfBuzz builds as a thread-safe library. The exception is that
|
||||
the `HB_TINY` predefined configuring (more below) disables thread-safety.
|
||||
|
||||
If you do *not* need thread-safety in the library (eg. you always call into
|
||||
HarfBuzz from the same thread), you can disable thread-safety by defining
|
||||
`HB_NO_MT`. As noted already, this is enabled by `HB_TINY`.
|
||||
|
||||
|
||||
## Pre-defined configurations
|
||||
|
||||
The [`hb-config.hh`](src/hb-config.hh) internal header supports three
|
||||
pre-defined configurations as well grouping of various configuration options.
|
||||
The pre-defined configurations are:
|
||||
|
||||
* `HB_MINI`: Disables shaping of AAT as well as legacy fonts. Ie. it produces
|
||||
a capable OpenType shaper only.
|
||||
|
||||
* `HB_LEAN`: Disables various non-shaping functionality in the library, as well
|
||||
as esoteric or rarely-used shaping features. See the definition for details.
|
||||
|
||||
* `HB_TINY`: Enables both `HB_MINI` and `HB_LEAN` configurations, as well as
|
||||
disabling thread-safety and debugging, and use even more size-optimized data
|
||||
tables.
|
||||
|
||||
|
||||
## Tailoring configuration
|
||||
|
||||
Most of the time, one of the pre-defined configuration is exactly what one needs.
|
||||
Sometimes, however, the pre-defined configuration cuts out features that might
|
||||
be desired in the library. Unfortunately there is no quick way to undo those
|
||||
configurations from the command-line. But one can add a header file called
|
||||
`config-override.h` to undefine certain `HB_NO_*` symbols as desired. Then
|
||||
define `HAVE_CONFIG_OVERRIDE_H` to make `hb-config.hh` include your configuration
|
||||
overrides at the end.
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
Note that the config option `HB_NO_CFF`, which is enabled by `HB_LEAN` and
|
||||
`HB_TINY` does *not* mean that the resulting library won't work with CFF fonts.
|
||||
The library can shape valid CFF fonts just fine, with or without this option.
|
||||
This option disables (among other things) the code to calculate glyph extents
|
||||
for CFF fonts.
|
38
COPYING
38
COPYING
@ -1,38 +0,0 @@
|
||||
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
||||
For parts of HarfBuzz that are licensed under different licenses see individual
|
||||
files names COPYING in subdirectories where applicable.
|
||||
|
||||
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
|
||||
Copyright © 2018,2019,2020 Ebrahim Byagowi
|
||||
Copyright © 2019,2020 Facebook, Inc.
|
||||
Copyright © 2012 Mozilla Foundation
|
||||
Copyright © 2011 Codethink Limited
|
||||
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
||||
Copyright © 2009 Keith Stribley
|
||||
Copyright © 2009 Martin Hosken and SIL International
|
||||
Copyright © 2007 Chris Wilson
|
||||
Copyright © 2006 Behdad Esfahbod
|
||||
Copyright © 2005 David Turner
|
||||
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
|
||||
Copyright © 1998-2004 David Turner and Werner Lemberg
|
||||
|
||||
For full copyright notices consult the individual files in the package.
|
||||
|
||||
|
||||
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.
|
96
Makefile.am
96
Makefile.am
@ -1,96 +0,0 @@
|
||||
# Process this file with automake to produce Makefile.in
|
||||
|
||||
NULL =
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = src util test docs
|
||||
|
||||
EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
harfbuzz.doap \
|
||||
README.md \
|
||||
README.python.md \
|
||||
BUILD.md \
|
||||
CONFIG.md \
|
||||
RELEASING.md \
|
||||
TESTING.md \
|
||||
CMakeLists.txt \
|
||||
replace-enum-strings.cmake \
|
||||
meson.build \
|
||||
meson_options.txt \
|
||||
subprojects/expat.wrap \
|
||||
subprojects/freetype2.wrap \
|
||||
subprojects/glib.wrap \
|
||||
subprojects/libffi.wrap \
|
||||
subprojects/proxy-libintl.wrap \
|
||||
subprojects/zlib.wrap \
|
||||
subprojects/google-benchmark.wrap \
|
||||
perf/meson.build \
|
||||
perf/perf-draw.hh \
|
||||
perf/perf-extents.hh \
|
||||
perf/perf-shaping.hh \
|
||||
perf/perf.cc \
|
||||
perf/fonts/Amiri-Regular.ttf \
|
||||
perf/fonts/NotoNastaliqUrdu-Regular.ttf \
|
||||
perf/fonts/NotoSansDevanagari-Regular.ttf \
|
||||
perf/fonts/Roboto-Regular.ttf \
|
||||
perf/texts/en-thelittleprince.txt \
|
||||
perf/texts/en-words.txt \
|
||||
perf/texts/fa-monologue.txt \
|
||||
perf/texts/fa-thelittleprince.txt \
|
||||
mingw-configure.sh \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
$(GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL) \
|
||||
$(GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL) \
|
||||
$(GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN) \
|
||||
$(srcdir)/INSTALL \
|
||||
$(srcdir)/ChangeLog \
|
||||
$(srcdir)/gtk-doc.make \
|
||||
$(srcdir)/m4/gtk-doc.m4 \
|
||||
$(NULL)
|
||||
|
||||
|
||||
#
|
||||
# ChangeLog generation
|
||||
#
|
||||
CHANGELOG_RANGE =
|
||||
ChangeLog: $(srcdir)/ChangeLog
|
||||
$(srcdir)/ChangeLog:
|
||||
$(AM_V_GEN) if test -d "$(top_srcdir)/.git"; then \
|
||||
(GIT_DIR=$(top_srcdir)/.git \
|
||||
$(GIT) log $(CHANGELOG_RANGE) --stat) > $@.tmp \
|
||||
&& mv -f $@.tmp "$(srcdir)/ChangeLog" \
|
||||
|| ($(RM) $@.tmp; \
|
||||
echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
|
||||
(test -f $@ || echo git-log is required to generate this file >> "$(srcdir)/$@")); \
|
||||
else \
|
||||
test -f $@ || \
|
||||
(echo A git checkout and git-log is required to generate ChangeLog >&2 && \
|
||||
echo A git checkout and git-log is required to generate this file >> "$(srcdir)/$@"); \
|
||||
fi
|
||||
.PHONY: ChangeLog $(srcdir)/ChangeLog
|
||||
|
||||
|
||||
#
|
||||
# Release engineering
|
||||
#
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--enable-gtk-doc \
|
||||
--disable-doc-cross-references \
|
||||
--with-gobject \
|
||||
--enable-introspection \
|
||||
$(NULL)
|
||||
|
||||
# TAR_OPTIONS is not set as env var for 'make dist'. How to fix that?
|
||||
TAR_OPTIONS = --owner=0 --group=0
|
||||
|
||||
dist-hook: dist-clear-sticky-bits
|
||||
# Clean up any sticky bits we may inherit from parent dir
|
||||
dist-clear-sticky-bits:
|
||||
chmod -R a-s $(distdir)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
15
README
15
README
@ -1,15 +0,0 @@
|
||||
This is HarfBuzz, a text shaping library.
|
||||
|
||||
For bug reports, mailing list, and other information please visit:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see https://github.com/harfbuzz/harfbuzz/blob/master/COPYING
|
||||
|
||||
For build information, see https://github.com/harfbuzz/harfbuzz/blob/master/BUILD.md
|
||||
|
||||
For custom configurations, see https://github.com/harfbuzz/harfbuzz/blob/master/CONFIG.md
|
||||
|
||||
For test execution, see https://github.com/harfbuzz/harfbuzz/blob/master/TESTING.md
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
@ -3,7 +3,7 @@
|
||||
"Name" : "harfbuzz",
|
||||
"License" : "MIT License",
|
||||
"License File" : "COPYING",
|
||||
"Version Number" : "2.8.1",
|
||||
"Version Number" : "2.8.2",
|
||||
"Owner" : "liyujia4@huawei.com",
|
||||
"Upstream URL" : "https://github.com/harfbuzz/harfbuzz/releases/tag/2.8.1",
|
||||
"Description" : "HarfBuzz is a text shaping engine. It primarily supports OpenType, but also Apple Advanced Typography. HarfBuzz is used in Android, Chrome, ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt, XeTeX, and other places."
|
||||
|
33
README.md
33
README.md
@ -1,33 +0,0 @@
|
||||
[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
|
||||
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
|
||||
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
|
||||
[![Coverity Code Health](https://img.shields.io/coverity/scan/5450.svg)](https://scan.coverity.com/projects/behdad-harfbuzz)
|
||||
[![Codacy Code Health](https://api.codacy.com/project/badge/Grade/f17f1708783c447488bc8dd317150eaa)](https://app.codacy.com/app/behdad/harfbuzz)
|
||||
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/master/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
|
||||
[![Coverals Code Coverage](https://img.shields.io/coveralls/harfbuzz/harfbuzz.svg)](https://coveralls.io/r/harfbuzz/harfbuzz)
|
||||
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
|
||||
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
|
||||
|
||||
This is HarfBuzz, a text shaping library.
|
||||
|
||||
For bug reports, mailing list, and other information please visit:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see [COPYING](COPYING).
|
||||
|
||||
For build information, see [BUILD.md](BUILD.md).
|
||||
|
||||
For custom configurations, see [CONFIG.md](CONFIG.md).
|
||||
|
||||
For test execution, see [TESTING.md](TESTING.md).
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Packaging status of HarfBuzz</summary>
|
||||
|
||||
[![Packaging status](https://repology.org/badge/vertical-allrepos/harfbuzz.svg?header=harfbuzz)](https://repology.org/project/harfbuzz/versions)
|
||||
|
||||
</details>
|
@ -1,47 +0,0 @@
|
||||
For the development of HarfBuzz, the Microsoft shaping technology, Uniscribe,
|
||||
as a widely used and tested shaper is used as more-or-less OpenType reference
|
||||
implementation and that specially is important where OpenType specification
|
||||
is or wasn't that clear. For having access to Uniscribe on Linux/macOS these
|
||||
steps are recommended:
|
||||
|
||||
You want to follow the 32bit instructions. The 64bit equivalents are included
|
||||
for reference.
|
||||
|
||||
1. Install Wine.
|
||||
- Fedora: `dnf install wine`.
|
||||
|
||||
2. Install `mingw-w64` compiler.
|
||||
- Fedora, 32bit: `dnf install mingw32-gcc-c++`
|
||||
- Fedora, 64bit: `dnf install mingw64-gcc-c++`
|
||||
- Debian: `apt install g++-mingw-w64`
|
||||
- Mac: `brew install mingw-w64`
|
||||
|
||||
3. If you have drank the `meson` koolaid, look at `.ci/build-win32.sh` to see how to
|
||||
invoke `meson` now, or just run that script. Otherwise, here's how to use the
|
||||
old trusty autotools instead:
|
||||
|
||||
a) Install dependencies.
|
||||
- Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
|
||||
- Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
|
||||
|
||||
b) Configure:
|
||||
- `NOCONFIGURE=1 ./autogen.sh && mkdir winbuild && cd winbuild`
|
||||
- 32bit: `../mingw-configure.sh i686`
|
||||
- 64bit: `../mingw-configure.sh x86_64`
|
||||
|
||||
Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)`
|
||||
but if you like to shape with the Microsoft Uniscribe:
|
||||
|
||||
4. Bring a 32bit version of `usp10.dll` for yourself from `C:\Windows\SysWOW64\usp10.dll` of your
|
||||
Windows installation (assuming you have a 64-bit installation, otherwise
|
||||
`C:\Windows\System32\usp10.dll`) that it is not a DirectWrite proxy
|
||||
([for more info](https://en.wikipedia.org/wiki/Uniscribe)).
|
||||
Rule of thumb, your `usp10.dll` should have a size more than 500kb, otherwise
|
||||
it is designed to work with DirectWrite which Wine can't work with its original one.
|
||||
You want a Uniscribe from Windows 7 or older.
|
||||
|
||||
Put the DLL in the folder you are going to run the next command,
|
||||
|
||||
5. `WINEDLLOVERRIDES="usp10=n" wine hb-shape.exe fontname.ttf -u 0061,0062,0063 --shaper=uniscribe`
|
||||
|
||||
(`0061,0062,0063` means `abc`, use test/shaping/hb-unicode-decode to generate ones you need)
|
@ -1,31 +0,0 @@
|
||||
To enable HarfBuzz bindings for Python among other languages, make sure
|
||||
you have latest version of gobject-introspection available. On Ubuntu,
|
||||
you can install that this way:
|
||||
|
||||
```bash
|
||||
sudo apt-get install libgirepository1.0-dev
|
||||
```
|
||||
|
||||
And then run `meson setup` and make sure that `Introspection` is reported
|
||||
enabled in output.
|
||||
|
||||
Compile and install.
|
||||
|
||||
Make sure you have the installation lib dir in `LD_LIBRARY_PATH`, as needed
|
||||
for the linker to find the library.
|
||||
|
||||
Then make sure you also have `GI_TYPELIB_PATH` pointing to the resulting
|
||||
`$prefix/lib/girepository-*` directory.
|
||||
|
||||
Make sure you have pygobject installed. Then check that the following
|
||||
import works in your Python interpreter:
|
||||
|
||||
```python
|
||||
from gi.repository import HarfBuzz
|
||||
```
|
||||
|
||||
If it does, you are ready to call HarfBuzz from Python! Congratulations.
|
||||
See [`src/sample.py`](src/sample.py).
|
||||
|
||||
The Python API will change. Let us know on the mailing list if you are
|
||||
using it, and send lots of feedback.
|
44
RELEASING.md
44
RELEASING.md
@ -1,44 +0,0 @@
|
||||
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. Ensure all new API / deprecations are in listed correctly in
|
||||
docs/harfbuzz-sections.txt. If release added new API, add entry for new
|
||||
API index at the end of docs/harfbuzz-docs.xml.
|
||||
|
||||
If there's a backward-incompatible API change (including deletions for API
|
||||
used anywhere), that's a release blocker. Do NOT release.
|
||||
|
||||
2. Based on severity of changes, decide whether it's a minor or micro release
|
||||
number bump,
|
||||
|
||||
3. Search for REPLACEME on the repository and replace it with the chosen version
|
||||
for the release.
|
||||
|
||||
4. Make sure you have correct date and new version at the top of NEWS file.
|
||||
|
||||
5. Bump version in line 3 of meson.build and configure.ac.
|
||||
Do a `meson test -Cbuild` so it both checks the tests and updates
|
||||
hb-version.h (use `git diff` to see if is really updated).
|
||||
|
||||
6. Commit NEWS, meson.build, configure.ac, and src/hb-version.h, as well as any REPLACEME
|
||||
changes you made. The commit message is simply the release number. Eg. "1.4.7"
|
||||
|
||||
7. Do a `meson dist -Cbuild` that runs the tests against the latest commited changes.
|
||||
If doesn't pass, something fishy is going on, reset the repo and start over.
|
||||
|
||||
8. Tag the release and sign it: Eg. "git tag -s 1.4.7 -m 1.4.7". Enter your
|
||||
GPG password.
|
||||
|
||||
9. Build win32 bundle. See [README.mingw.md](README.mingw.md).
|
||||
|
||||
10. Push the commit and tag out: "git push --follow-tags".
|
||||
|
||||
11. Go to GitHub release page [here](https://github.com/harfbuzz/harfbuzz/releases),
|
||||
edit the tag, upload win32 bundle and NEWS entry and save.
|
||||
No need to upload source tarball as we rely to GitHub's automatic tar.gz generation.
|
55
TESTING.md
55
TESTING.md
@ -1,55 +0,0 @@
|
||||
## Build and Test
|
||||
|
||||
```shell
|
||||
meson build
|
||||
ninja -Cbuild
|
||||
meson test -Cbuild
|
||||
```
|
||||
|
||||
### Debug with GDB
|
||||
|
||||
```shell
|
||||
meson test -Cbuild --gdb testname
|
||||
```
|
||||
|
||||
## Build and Run
|
||||
|
||||
Depending on what area you are working in change or add `HB_DEBUG_<whatever>`.
|
||||
Values defined in `hb-debug.hh`.
|
||||
|
||||
```shell
|
||||
CPPFLAGS='-DHB_DEBUG_SUBSET=100' meson setup build --reconfigure
|
||||
meson test -C build
|
||||
```
|
||||
|
||||
### Run tests with asan
|
||||
|
||||
```shell
|
||||
meson setup build -Db_sanitize=address --reconfigure
|
||||
meson compile -C build
|
||||
meson test -C build
|
||||
```
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```shell
|
||||
CPPFLAGS=-DHB_DEBUG_SUBSET=100 meson build --reconfigure
|
||||
ninja -C build
|
||||
```
|
||||
|
||||
## Test with the Fuzzer
|
||||
|
||||
```shell
|
||||
CXXFLAGS="-fsanitize=address,fuzzer-no-link" meson fuzzbuild --default-library=static -Dfuzzer_ldflags="-fsanitize=address,fuzzer" -Dexperimental_api=true
|
||||
ninja -Cfuzzbuild test/fuzzing/hb-{shape,draw,subset,set}-fuzzer
|
||||
fuzzbuild/test/fuzzing/hb-subset-fuzzer test/fuzzing/fonts
|
||||
```
|
||||
|
||||
## Profiling
|
||||
|
||||
```
|
||||
meson build --reconfigure
|
||||
meson compile -C build
|
||||
build/perf/perf
|
||||
```
|
||||
|
7
THANKS
7
THANKS
@ -1,7 +0,0 @@
|
||||
Bradley Grainger
|
||||
Kenichi Ishibashi
|
||||
Ivan Kuckir <https://photopea.com/>
|
||||
Ryan Lortie
|
||||
Jeff Muizelaar
|
||||
suzuki toshiya
|
||||
Philip Withnall
|
28
TODO
28
TODO
@ -1,28 +0,0 @@
|
||||
API issues:
|
||||
===========
|
||||
|
||||
- API to accept a list of languages?
|
||||
|
||||
- Remove hb_ot_shape_glyphs_closure()?
|
||||
|
||||
|
||||
API additions
|
||||
=============
|
||||
|
||||
- Language to/from script.
|
||||
|
||||
- Add hb-cairo glue
|
||||
|
||||
- Add sanitize API.
|
||||
|
||||
- Add query / enumeration API for aalt-like features?
|
||||
|
||||
- Add segmentation API
|
||||
|
||||
- Add hb-fribidi glue?
|
||||
|
||||
|
||||
hb-view / hb-shape enhancements:
|
||||
===============================
|
||||
|
||||
- Add --width, --height, --auto-size, --ink-box, --align, etc?
|
48
autogen.sh
48
autogen.sh
@ -1,48 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
|
||||
test -n "$srcdir" || srcdir=`dirname "$0"`
|
||||
test -n "$srcdir" || srcdir=.
|
||||
|
||||
olddir=`pwd`
|
||||
cd $srcdir
|
||||
|
||||
#printf "checking for ragel... "
|
||||
#which ragel || {
|
||||
# echo "You need to install ragel... See http://www.complang.org/ragel/"
|
||||
# exit 1
|
||||
#}
|
||||
|
||||
printf "checking for pkg-config... "
|
||||
which pkg-config || {
|
||||
echo "*** No pkg-config found, please install it ***"
|
||||
exit 1
|
||||
}
|
||||
|
||||
printf "checking for libtoolize... "
|
||||
which glibtoolize || which libtoolize || {
|
||||
echo "*** No libtoolize (libtool) found, please install it ***"
|
||||
exit 1
|
||||
}
|
||||
printf "checking for gtkdocize... "
|
||||
if which gtkdocize ; then
|
||||
gtkdocize --copy || exit 1
|
||||
else
|
||||
echo "*** No gtkdocize (gtk-doc) found, skipping documentation ***"
|
||||
echo "EXTRA_DIST = " > gtk-doc.make
|
||||
fi
|
||||
|
||||
printf "checking for autoreconf... "
|
||||
which autoreconf || {
|
||||
echo "*** No autoreconf (autoconf) found, please install it ***"
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "running autoreconf --force --install --verbose"
|
||||
autoreconf --force --install --verbose || exit $?
|
||||
|
||||
cd $olddir
|
||||
test -n "$NOCONFIGURE" || {
|
||||
echo "running configure $@"
|
||||
"$srcdir/configure" "$@"
|
||||
}
|
37
backport-0001-CVE-2023-25193.patch
Normal file
37
backport-0001-CVE-2023-25193.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 56f11ec938260836387256225bc47665473e2bbe Mon Sep 17 00:00:00 2001
|
||||
From: Behdad Esfahbod <behdad@behdad.org>
|
||||
Date: Fri, 18 Feb 2022 14:08:43 -0600
|
||||
Subject: [PATCH] [buffer] Add HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT
|
||||
|
||||
---
|
||||
src/hb-buffer.h | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/hb-buffer.h b/src/hb-buffer.h
|
||||
index 865ccb2..51b1760 100644
|
||||
--- a/src/hb-buffer.h
|
||||
+++ b/src/hb-buffer.h
|
||||
@@ -296,7 +296,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
|
||||
* flag indicating that a dotted circle should
|
||||
* not be inserted in the rendering of incorrect
|
||||
* character sequences (such at <0905 093E>). Since: 2.4
|
||||
- *
|
||||
+ * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT:
|
||||
+ * flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
|
||||
+ * glyph-flag should be produced by the shaper. By default
|
||||
+ * it will not be produced since it incurs a cost. Since: REPLACEME
|
||||
* Flags for #hb_buffer_t.
|
||||
*
|
||||
* Since: 0.9.20
|
||||
@@ -307,7 +310,8 @@ typedef enum { /*< flags >*/
|
||||
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
|
||||
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
|
||||
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
|
||||
- HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
|
||||
+ HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
|
||||
+ HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u
|
||||
} hb_buffer_flags_t;
|
||||
|
||||
HB_EXTERN void
|
||||
--
|
||||
2.27.0
|
38
backport-0002-CVE-2023-25193.patch
Normal file
38
backport-0002-CVE-2023-25193.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 85be877925ddbf34f74a1229f3ca1716bb6170dc Mon Sep 17 00:00:00 2001
|
||||
From: Behdad Esfahbod <behdad@behdad.org>
|
||||
Date: Wed, 1 Feb 2023 20:00:43 -0700
|
||||
Subject: [PATCH] [layout] Limit how far we skip when looking back
|
||||
|
||||
See comments.
|
||||
---
|
||||
src/hb-ot-layout-gsubgpos.hh | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/hb-ot-layout-gsubgpos.hh b/src/hb-ot-layout-gsubgpos.hh
|
||||
index c17bf92..712e307 100644
|
||||
--- a/src/hb-ot-layout-gsubgpos.hh
|
||||
+++ b/src/hb-ot-layout-gsubgpos.hh
|
||||
@@ -535,7 +535,19 @@ struct hb_ot_apply_context_t :
|
||||
bool prev ()
|
||||
{
|
||||
assert (num_items > 0);
|
||||
- while (idx > num_items - 1)
|
||||
+ /* The alternate condition below is faster at string boundaries,
|
||||
+ * but produces subpar "unsafe-to-concat" values. */
|
||||
+ unsigned stop = num_items - 1;
|
||||
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
|
||||
+ stop = 1 - 1;
|
||||
+
|
||||
+ /* When looking back, limit how far we search; this function is mostly
|
||||
+ * used for looking back for base glyphs when attaching marks. If we
|
||||
+ * don't limit, we can get O(n^2) behavior where n is the number of
|
||||
+ * consecutive marks. */
|
||||
+ stop = (unsigned) hb_max ((int) stop, (int) idx - HB_MAX_CONTEXT_LENGTH);
|
||||
+
|
||||
+ while (idx > stop)
|
||||
{
|
||||
idx--;
|
||||
const hb_glyph_info_t &info = c->buffer->out_info[idx];
|
||||
--
|
||||
2.33.0
|
||||
|
29
backport-CVE-2022-33068.patch
Normal file
29
backport-CVE-2022-33068.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From 62e803b36173fd096d7ad460dd1d1db9be542593 Mon Sep 17 00:00:00 2001
|
||||
From: Behdad Esfahbod <behdad@behdad.org>
|
||||
Date: Wed, 1 Jun 2022 07:38:21 -0600
|
||||
Subject: [PATCH] [sbix] Limit glyph extents
|
||||
|
||||
Fixes https://github.com/harfbuzz/harfbuzz/issues/3557
|
||||
---
|
||||
src/hb-ot-color-sbix-table.hh | 6 ++++++
|
||||
test/fuzzing/fonts/sbix-extents.ttf | Bin 0 -> 582 bytes
|
||||
2 files changed, 6 insertions(+)
|
||||
create mode 100644 test/fuzzing/fonts/sbix-extents.ttf
|
||||
|
||||
diff --git a/src/hb-ot-color-sbix-table.hh b/src/hb-ot-color-sbix-table.hh
|
||||
index 9741ebd450..6efae43cda 100644
|
||||
--- a/src/hb-ot-color-sbix-table.hh
|
||||
+++ b/src/hb-ot-color-sbix-table.hh
|
||||
@@ -298,6 +298,12 @@ struct sbix
|
||||
|
||||
const PNGHeader &png = *blob->as<PNGHeader>();
|
||||
|
||||
+ if (png.IHDR.height >= 65536 | png.IHDR.width >= 65536)
|
||||
+ {
|
||||
+ hb_blob_destroy (blob);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
extents->x_bearing = x_offset;
|
||||
extents->y_bearing = png.IHDR.height + y_offset;
|
||||
extents->width = png.IHDR.width;
|
484
configure.ac
484
configure.ac
@ -1,484 +0,0 @@
|
||||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[2.8.1],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_SRCDIR([src/harfbuzz.pc.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.13.0 gnits tar-ustar dist-xz no-dist-gzip -Wall no-define color-tests -Wno-portability])
|
||||
AM_SILENT_RULES([yes])
|
||||
AX_CODE_COVERAGE
|
||||
|
||||
# Initialize libtool
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
LT_PREREQ([2.2])
|
||||
LT_INIT([disable-static])
|
||||
|
||||
# Check for programs
|
||||
AC_PROG_CC
|
||||
AC_PROG_CC_C99
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AX_CXX_COMPILE_STDCXX(11)
|
||||
AC_SYS_LARGEFILE
|
||||
PKG_PROG_PKG_CONFIG([0.28])
|
||||
AM_MISSING_PROG([RAGEL], [ragel])
|
||||
AM_MISSING_PROG([GIT], [git])
|
||||
|
||||
# Version
|
||||
m4_define(hb_version_triplet,m4_split(AC_PACKAGE_VERSION,[[.]]))
|
||||
m4_define(hb_version_major,m4_argn(1,hb_version_triplet))
|
||||
m4_define(hb_version_minor,m4_argn(2,hb_version_triplet))
|
||||
m4_define(hb_version_micro,m4_argn(3,hb_version_triplet))
|
||||
HB_VERSION_MAJOR=hb_version_major
|
||||
HB_VERSION_MINOR=hb_version_minor
|
||||
HB_VERSION_MICRO=hb_version_micro
|
||||
HB_VERSION=AC_PACKAGE_VERSION
|
||||
AC_SUBST(HB_VERSION_MAJOR)
|
||||
AC_SUBST(HB_VERSION_MINOR)
|
||||
AC_SUBST(HB_VERSION_MICRO)
|
||||
AC_SUBST(HB_VERSION)
|
||||
|
||||
# Libtool version
|
||||
m4_define([hb_version_int],
|
||||
m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro))
|
||||
HB_LIBTOOL_VERSION_INFO=hb_version_int:0:hb_version_int
|
||||
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], [
|
||||
GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
|
||||
if test "x$enable_gtk_doc" = xyes; then
|
||||
have_gtk_doc=true
|
||||
fi
|
||||
], [
|
||||
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 stdbool.h)
|
||||
|
||||
# Compiler flags
|
||||
AC_CANONICAL_HOST
|
||||
AC_CHECK_ALIGNOF([struct{char;}])
|
||||
if test "x$GCC" = "xyes"; then
|
||||
|
||||
# Make symbols link locally
|
||||
AX_CHECK_LINK_FLAG([[-Bsymbolic-functions]], [LDFLAGS="$LDFLAGS -Bsymbolic-functions"])
|
||||
|
||||
# Make it possible to not link to libstdc++
|
||||
# No threadsafe statics in C++ as we do it ourselves.
|
||||
# We don't use these features, so it's safe to disable them
|
||||
# even in the cases where we DO link to libstdc++.
|
||||
# Put -fno-rtti before $CXXFLAGS such that users can re-enable it
|
||||
# by overriding CXXFLAGS.
|
||||
CXXFLAGS="-fno-rtti $CXXFLAGS -fno-exceptions -fno-threadsafe-statics"
|
||||
|
||||
case "$host" in
|
||||
*-*-mingw*)
|
||||
;;
|
||||
*)
|
||||
# Hide inline methods
|
||||
CXXFLAGS="$CXXFLAGS -fvisibility-inlines-hidden"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$host" in
|
||||
arm-*-*)
|
||||
if test "x$ac_cv_alignof_struct_char__" != x1; then
|
||||
# Request byte alignment
|
||||
CXXFLAGS="$CXXFLAGS -mstructure-size-boundary=8"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_GCC, test "x$GCC" = "xyes")
|
||||
|
||||
hb_os_win32=no
|
||||
AC_MSG_CHECKING([for native Win32])
|
||||
case "$host" in
|
||||
*-*-mingw*)
|
||||
hb_os_win32=yes
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$hb_os_win32])
|
||||
AM_CONDITIONAL(OS_WIN32, test "$hb_os_win32" = "yes")
|
||||
|
||||
have_pthread=false
|
||||
AX_PTHREAD([have_pthread=true])
|
||||
if $have_pthread; then
|
||||
AC_DEFINE(HAVE_PTHREAD, 1, [Have POSIX threads])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_PTHREAD, $have_pthread)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(glib,
|
||||
[AS_HELP_STRING([--with-glib=@<:@yes/no/auto@:>@],
|
||||
[Use glib @<:@default=auto@:>@])],,
|
||||
[with_glib=auto])
|
||||
have_glib=false
|
||||
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, :)
|
||||
fi
|
||||
if test "x$with_glib" = "xyes" -a "x$have_glib" != "xtrue"; then
|
||||
AC_MSG_ERROR([glib support requested but glib-2.0 not found])
|
||||
fi
|
||||
if $have_glib; then
|
||||
AC_DEFINE(HAVE_GLIB, 1, [Have glib2 library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GLIB, $have_glib)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(gobject,
|
||||
[AS_HELP_STRING([--with-gobject=@<:@yes/no/auto@:>@],
|
||||
[Use gobject @<:@default=no@:>@])],,
|
||||
[with_gobject=no])
|
||||
have_gobject=false
|
||||
if test "x$with_gobject" = "xyes" -o "x$with_gobject" = "xauto"; then
|
||||
PKG_CHECK_MODULES(GOBJECT, gobject-2.0 glib-2.0, have_gobject=true, :)
|
||||
fi
|
||||
if test "x$with_gobject" = "xyes" -a "x$have_gobject" != "xtrue"; then
|
||||
AC_MSG_ERROR([gobject support requested but gobject-2.0 / glib-2.0 not found])
|
||||
fi
|
||||
if $have_gobject; then
|
||||
AC_DEFINE(HAVE_GOBJECT, 1, [Have gobject2 library])
|
||||
GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
|
||||
AC_SUBST(GLIB_MKENUMS)
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GOBJECT, $have_gobject)
|
||||
AC_SUBST(have_gobject)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
|
||||
dnl ===========================================================================
|
||||
# Gobject-Introspection
|
||||
have_introspection=false
|
||||
m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [
|
||||
if $have_gobject; then
|
||||
GOBJECT_INTROSPECTION_CHECK([1.34.0])
|
||||
if test "x$found_introspection" = xyes; then
|
||||
have_introspection=true
|
||||
fi
|
||||
else
|
||||
AM_CONDITIONAL([HAVE_INTROSPECTION], false)
|
||||
fi
|
||||
], [
|
||||
AM_CONDITIONAL([HAVE_INTROSPECTION], false)
|
||||
])
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(cairo,
|
||||
[AS_HELP_STRING([--with-cairo=@<:@yes/no/auto@:>@],
|
||||
[Use cairo @<:@default=auto@:>@])],,
|
||||
[with_cairo=auto])
|
||||
have_cairo=false
|
||||
if test "x$with_cairo" = "xyes" -o "x$with_cairo" = "xauto"; then
|
||||
PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, :)
|
||||
fi
|
||||
if test "x$with_cairo" = "xyes" -a "x$have_cairo" != "xtrue"; then
|
||||
AC_MSG_ERROR([cairo support requested but not found])
|
||||
fi
|
||||
if $have_cairo; then
|
||||
AC_DEFINE(HAVE_CAIRO, 1, [Have cairo graphics library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_CAIRO, $have_cairo)
|
||||
|
||||
have_cairo_ft=false
|
||||
if $have_cairo; then
|
||||
PKG_CHECK_MODULES(CAIRO_FT, cairo-ft, have_cairo_ft=true, :)
|
||||
fi
|
||||
if $have_cairo_ft; then
|
||||
AC_DEFINE(HAVE_CAIRO_FT, 1, [Have cairo-ft support in cairo graphics library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_CAIRO_FT, $have_cairo_ft)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(chafa,
|
||||
[AS_HELP_STRING([--with-chafa=@<:@yes/no/auto@:>@],
|
||||
[Use chafa @<:@default=auto@:>@])],,
|
||||
[with_chafa=auto])
|
||||
have_chafa=false
|
||||
if test "x$with_chafa" = "xyes" -o "x$with_chafa" = "xauto"; then
|
||||
PKG_CHECK_MODULES(CHAFA, chafa >= 1.6.0, have_chafa=true, :)
|
||||
fi
|
||||
if test "x$with_chafa" = "xyes" -a "x$have_chafa" != "xtrue"; then
|
||||
AC_MSG_ERROR([chafa support requested but not found])
|
||||
fi
|
||||
if $have_chafa; then
|
||||
AC_DEFINE(HAVE_CHAFA, 1, [Have chafa terminal graphics library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_CHAFA, $have_chafa)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(icu,
|
||||
[AS_HELP_STRING([--with-icu=@<:@yes/no/builtin/auto@:>@],
|
||||
[Use ICU @<:@default=auto@:>@])],,
|
||||
[with_icu=auto])
|
||||
have_icu=false
|
||||
if test "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" -o "x$with_icu" = "xauto"; then
|
||||
PKG_CHECK_MODULES(ICU, icu-uc, have_icu=true, :)
|
||||
fi
|
||||
if test \( "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" \) -a "x$have_icu" != "xtrue"; then
|
||||
AC_MSG_ERROR([icu support requested but icu-uc not found])
|
||||
fi
|
||||
|
||||
if $have_icu; then
|
||||
CXXFLAGS="$CXXFLAGS `$PKG_CONFIG --variable=CXXFLAGS icu-uc`"
|
||||
AC_DEFINE(HAVE_ICU, 1, [Have ICU library])
|
||||
if test "x$with_icu" = "xbuiltin"; then
|
||||
AC_DEFINE(HAVE_ICU_BUILTIN, 1, [Use hb-icu Unicode callbacks])
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_ICU, $have_icu)
|
||||
AM_CONDITIONAL(HAVE_ICU_BUILTIN, $have_icu && test "x$with_icu" = "xbuiltin")
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(graphite2,
|
||||
[AS_HELP_STRING([--with-graphite2=@<:@yes/no/auto@:>@],
|
||||
[Use the graphite2 library @<:@default=no@:>@])],,
|
||||
[with_graphite2=no])
|
||||
have_graphite2=false
|
||||
GRAPHITE2_DEPS="graphite2 >= 1.2.0"
|
||||
AC_SUBST(GRAPHITE2_DEPS)
|
||||
if test "x$with_graphite2" = "xyes" -o "x$with_graphite2" = "xauto"; then
|
||||
PKG_CHECK_MODULES(GRAPHITE2, $GRAPHITE2_DEPS, have_graphite2=true, :)
|
||||
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])
|
||||
fi
|
||||
if $have_graphite2; then
|
||||
AC_DEFINE(HAVE_GRAPHITE2, 1, [Have Graphite2 library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GRAPHITE2, $have_graphite2)
|
||||
|
||||
dnl ==========================================================================
|
||||
|
||||
AC_ARG_WITH(freetype,
|
||||
[AS_HELP_STRING([--with-freetype=@<:@yes/no/auto@:>@],
|
||||
[Use the FreeType library @<:@default=auto@:>@])],,
|
||||
[with_freetype=auto])
|
||||
have_freetype=false
|
||||
FREETYPE_DEPS="freetype2 >= 12.0.6"
|
||||
AC_SUBST(FREETYPE_DEPS)
|
||||
if test "x$with_freetype" = "xyes" -o "x$with_freetype" = "xauto"; then
|
||||
# See freetype/docs/VERSION.DLL; 12.0.6 means freetype-2.4.2
|
||||
PKG_CHECK_MODULES(FREETYPE, $FREETYPE_DEPS, have_freetype=true, :)
|
||||
fi
|
||||
if test "x$with_freetype" = "xyes" -a "x$have_freetype" != "xtrue"; then
|
||||
AC_MSG_ERROR([FreeType support requested but libfreetype2 not found])
|
||||
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)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(uniscribe,
|
||||
[AS_HELP_STRING([--with-uniscribe=@<:@yes/no/auto@:>@],
|
||||
[Use the Uniscribe library @<:@default=no@:>@])],,
|
||||
[with_uniscribe=no])
|
||||
have_uniscribe=false
|
||||
if test "x$with_uniscribe" = "xyes" -o "x$with_uniscribe" = "xauto"; then
|
||||
AC_CHECK_HEADERS(usp10.h windows.h, have_uniscribe=true)
|
||||
fi
|
||||
if test "x$with_uniscribe" = "xyes" -a "x$have_uniscribe" != "xtrue"; then
|
||||
AC_MSG_ERROR([uniscribe support requested but not found])
|
||||
fi
|
||||
if $have_uniscribe; then
|
||||
UNISCRIBE_CFLAGS=
|
||||
UNISCRIBE_LIBS="-lusp10 -lgdi32 -lrpcrt4"
|
||||
AC_SUBST(UNISCRIBE_CFLAGS)
|
||||
AC_SUBST(UNISCRIBE_LIBS)
|
||||
AC_DEFINE(HAVE_UNISCRIBE, 1, [Have Uniscribe library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_UNISCRIBE, $have_uniscribe)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(gdi,
|
||||
[AS_HELP_STRING([--with-gdi=@<:@yes/no/auto@:>@],
|
||||
[Provide GDI integration helpers @<:@default=no@:>@])],,
|
||||
[with_gdi=no])
|
||||
have_gdi=false
|
||||
if test "x$with_gdi" = "xyes" -o "x$with_gdi" = "xauto"; then
|
||||
AC_CHECK_HEADERS(windows.h, have_gdi=true)
|
||||
fi
|
||||
if test "x$with_gdi" = "xyes" -a "x$have_gdi" != "xtrue"; then
|
||||
AC_MSG_ERROR([gdi support requested but not found])
|
||||
fi
|
||||
if $have_gdi; then
|
||||
GDI_CFLAGS=
|
||||
GDI_LIBS="-lgdi32"
|
||||
AC_SUBST(GDI_CFLAGS)
|
||||
AC_SUBST(GDI_LIBS)
|
||||
AC_DEFINE(HAVE_GDI, 1, [Have GDI library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GDI, $have_gdi)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(directwrite,
|
||||
[AS_HELP_STRING([--with-directwrite=@<:@yes/no/auto@:>@],
|
||||
[Use the DirectWrite library (experimental) @<:@default=no@:>@])],,
|
||||
[with_directwrite=no])
|
||||
have_directwrite=false
|
||||
AC_LANG_PUSH([C++])
|
||||
if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
|
||||
AC_CHECK_HEADERS(dwrite.h, have_directwrite=true)
|
||||
fi
|
||||
AC_LANG_POP([C++])
|
||||
if test "x$with_directwrite" = "xyes" -a "x$have_directwrite" != "xtrue"; then
|
||||
AC_MSG_ERROR([directwrite support requested but not found])
|
||||
fi
|
||||
if $have_directwrite; then
|
||||
DIRECTWRITE_CXXFLAGS=
|
||||
DIRECTWRITE_LIBS=
|
||||
AC_SUBST(DIRECTWRITE_CXXFLAGS)
|
||||
AC_SUBST(DIRECTWRITE_LIBS)
|
||||
AC_DEFINE(HAVE_DIRECTWRITE, 1, [Have DirectWrite library])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_DIRECTWRITE, $have_directwrite)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_ARG_WITH(coretext,
|
||||
[AS_HELP_STRING([--with-coretext=@<:@yes/no/auto@:>@],
|
||||
[Use CoreText @<:@default=no@:>@])],,
|
||||
[with_coretext=no])
|
||||
have_coretext=false
|
||||
if test "x$with_coretext" = "xyes" -o "x$with_coretext" = "xauto"; then
|
||||
AC_CHECK_TYPE(CTFontRef, have_coretext=true,, [#include <ApplicationServices/ApplicationServices.h>])
|
||||
|
||||
if $have_coretext; then
|
||||
CORETEXT_CFLAGS=
|
||||
CORETEXT_LIBS="-framework ApplicationServices"
|
||||
AC_SUBST(CORETEXT_CFLAGS)
|
||||
AC_SUBST(CORETEXT_LIBS)
|
||||
else
|
||||
# On iOS CoreText and CoreGraphics are stand-alone frameworks
|
||||
if test "x$have_coretext" != "xtrue"; then
|
||||
# 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 -framework CoreFoundation"
|
||||
AC_SUBST(CORETEXT_CFLAGS)
|
||||
AC_SUBST(CORETEXT_LIBS)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
if test "x$with_coretext" = "xyes" -a "x$have_coretext" != "xtrue"; then
|
||||
AC_MSG_ERROR([CoreText support requested but libcoretext not found])
|
||||
fi
|
||||
if $have_coretext; then
|
||||
AC_DEFINE(HAVE_CORETEXT, 1, [Have Core Text backend])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_CORETEXT, $have_coretext)
|
||||
|
||||
dnl ===========================================================================
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
src/harfbuzz-config.cmake
|
||||
util/Makefile
|
||||
test/Makefile
|
||||
test/api/Makefile
|
||||
test/fuzzing/Makefile
|
||||
test/shaping/Makefile
|
||||
test/shaping/data/Makefile
|
||||
test/shaping/data/aots/Makefile
|
||||
test/shaping/data/in-house/Makefile
|
||||
test/shaping/data/text-rendering-tests/Makefile
|
||||
test/subset/Makefile
|
||||
test/subset/data/Makefile
|
||||
test/subset/data/repack_tests/Makefile
|
||||
docs/Makefile
|
||||
docs/version.xml
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo
|
||||
echo "C++ compiler version:"
|
||||
$CXX --version
|
||||
echo
|
||||
|
||||
AC_MSG_NOTICE([
|
||||
|
||||
Autotools is no longer our supported build system for building the library
|
||||
for *nix distributions, please migrate to meson.
|
||||
|
||||
])
|
||||
|
||||
|
||||
AC_MSG_NOTICE([
|
||||
|
||||
Build configuration:
|
||||
|
||||
Unicode callbacks (you want at least one):
|
||||
Builtin true
|
||||
Glib: ${have_glib}
|
||||
ICU: ${have_icu}
|
||||
|
||||
Font callbacks (the more the merrier):
|
||||
FreeType: ${have_freetype}
|
||||
|
||||
Tools used for command-line utilities:
|
||||
Cairo: ${have_cairo}
|
||||
Chafa: ${have_chafa}
|
||||
|
||||
Additional shapers:
|
||||
Graphite2: ${have_graphite2}
|
||||
|
||||
Platform shapers (not normally needed):
|
||||
CoreText: ${have_coretext}
|
||||
DirectWrite: ${have_directwrite}
|
||||
GDI: ${have_gdi}
|
||||
Uniscribe: ${have_uniscribe}
|
||||
|
||||
Other features:
|
||||
Documentation: ${enable_gtk_doc}
|
||||
GObject bindings: ${have_gobject}
|
||||
Introspection: ${have_introspection}
|
||||
])
|
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB |
@ -1,8 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 682.667 682.667">
|
||||
<!-- Harf -->
|
||||
<path d="M168.422 500.826c-23.477-.144-41.602-1.179-54.375-3.125-22.227-3.47-38.06-10.137-47.5-20-8.477-7.637-12.709-18.054-12.709-31.25 0-5.137.482-12.5 1.459-22.084a406.941 406.941 0 013.958-28.75c.69-4.023 1.315-7.636 1.875-10.833.417-2.22.97-4.024 1.667-5.417.69-1.386 1.458-2.187 2.291-2.396.834-.208 1.628.352 2.396 1.667.762 1.322 1.491 3.58 2.188 6.77a114.35 114.35 0 002.291 10.834c2.22 9.03 8.262 15.768 18.125 20.209 25 10.696 63.19 16.25 114.584 16.666 21.25-.273 40.97-1.041 59.166-2.291 18.607-1.387 39.584-4.649 62.917-9.792 23.333-5.137 41.908-10.762 55.73-16.875 13.814-6.107 25.585-12.708 35.312-19.792 7.636-5.553 11.458-10.898 11.458-16.041 0-2.084-1.98-4.545-5.938-7.396-3.958-2.845-6.562-4.271-7.812-4.271-2.363 1.113-5.143 1.98-8.333 2.604-3.197.625-6.114.8-8.75.52-7.364-.832-12.852-3.124-16.459-6.874-3.613-3.75-5.416-8.815-5.416-15.208 0-4.024 5.345-16.667 16.041-37.917 4.304-8.607 8.086-14.616 11.354-18.02 3.262-3.4 7.741-5.105 13.438-5.105 9.023 0 17.396 4.863 25.104 14.583 7.708 9.727 11.563 22.155 11.563 37.292 0 15-2.019 27.988-6.042 38.958-5 15-11.81 28.893-20.417 41.667-10.833 15.417-22.708 27.604-35.625 36.562-12.916 8.959-25.976 16.081-39.166 21.355-11.81 5.833-27.051 11.289-45.73 16.354-18.684 5.071-41.354 9.205-68.02 12.396-26.394 3.196-49.935 4.856-70.625 5zM430.222 133.162c1.107 4.03 1.074 8.196-.104 12.5-1.185 4.31-3.373 8.821-6.563 13.541-1.946 3.197-3.997 6.081-6.146 8.646a114.073 114.073 0 01-6.77 7.396c-.697.833-1.81 1.875-3.334 3.125a60.28 60.28 0 01-4.791 3.542c-1.667 1.113-3.269 1.914-4.792 2.396-1.53.488-2.643.312-3.333-.521-5-4.024-9.935-8.125-14.792-12.292-4.863-4.167-10.208-8.053-16.042-11.667-.976-.69-1.426-1.354-1.354-1.979.065-.625.45-1.562 1.146-2.812l33.333-50.834c.97-1.386 1.94-2.044 2.917-1.979.97.072 2.012.456 3.125 1.146a102.942 102.942 0 018.75 5.625 70.208 70.208 0 018.125 6.77 47.58 47.58 0 016.562 7.918c1.875 2.851 3.23 6.009 4.063 9.479zM599.13 319.784a589.994 589.994 0 01-9.583 16.354 123.488 123.488 0 01-11.146 15.52 97.741 97.741 0 01-13.542 13.23c-4.935 3.958-10.52 7.122-16.77 9.48-5.144 2.083-9.519 4.413-13.126 6.978-3.613 2.572-6.601 5.313-8.958 8.23-3.613 3.893-6.738 9.27-9.375 16.145a2240.458 2240.458 0 00-8.23 21.771 307.032 307.032 0 01-9.374 22.396c-3.405 7.292-7.676 13.3-12.813 18.02-7.083 7.5-17.571 12.573-31.458 15.21l-38.125 6.458c-1.113.143-2.467.247-4.063.312-1.601.072-2.747.04-3.437-.104-3.19-.97-4.167-3.086-2.917-6.354 1.25-3.262 4.512-6.563 9.792-9.896 10.69-7.083 19.232-12.813 25.625-17.188a6164.29 6164.29 0 0015.625-10.729c4.023-2.773 7.253-5.065 9.687-6.875a271.19 271.19 0 007.813-6.041c11.25-8.47 19.023-17.357 23.333-26.667 2.5-4.857 4.792-9.583 6.875-14.167a305.502 305.502 0 016.563-13.541 226.164 226.164 0 017.396-13.23c2.636-4.375 5.69-8.782 9.166-13.229 3.607-4.44 8.47-8.782 14.584-13.02 6.106-4.232 13.47-8.438 22.083-12.605.97-.416 2.565-1.354 4.792-2.812 2.22-1.459 4.928-3.783 8.125-6.98 3.19-3.19 6.836-7.532 10.937-13.02 4.095-5.482 8.438-12.461 13.021-20.938-1.667-1.666-6.458-3.958-14.375-6.875-7.917-3.053-15.417-4.791-22.5-5.208-6.53-.417-11.914.768-16.146 3.542-4.238 2.78-8.092 6.738-11.562 11.875-3.477 5.143-6.459 7.5-8.959 7.083-.833-.417-.976-2.149-.416-5.208a51.587 51.587 0 012.916-8.959c5.274-12.083 11.25-21.041 17.917-26.875 6.803-5.97 14.928-8.958 24.375-8.958 6.803 0 15.345 1.667 25.625 5 6.387 2.226 11.875 3.333 16.458 3.333 9.584 0 19.095-3.398 28.542-10.208 2.083 0 2.812 1.354 2.187 4.062-.625 2.709-1.562 5.873-2.812 9.48-1.113 3.613-1.875 6.041-2.292 7.291-2.083 6.53-3.75 10.352-5 11.459-1.25.976-4.863 3.613-10.833 7.916a42.505 42.505 0 00-8.646 8.646c-2.435 3.268-4.896 7.122-7.396 11.563-2.5 4.446-5.696 10.56-9.583 18.333zm0 0"/>
|
||||
<!-- B -->
|
||||
<path d="M229.342 300.489c2.084-8.887 4.375-16.667 6.875-23.333 2.5-6.667 4.935-12.188 7.292-16.563 2.363-4.375 4.655-7.74 6.875-10.104 2.226-2.357 4.167-3.75 5.833-4.167v13.75c0 17.5 4.649 29.727 13.959 36.667 5.69 3.75 11.354 5 16.979 3.75s9.928-4.167 12.916-8.75c2.982-4.583 5.521-9.96 7.605-16.146 2.083-6.178 4.095-9.27 6.041-9.27 2.22 0 3.125 2.226 2.709 6.666-.144 7.5-2.468 19.688-6.98 36.563-4.518 16.875-10.625 30.729-18.333 41.562-7.708 10.833-17.05 16.53-28.02 17.083-11.25-.416-20-6.731-26.25-18.958-5.69-12.083-8.19-27.708-7.5-46.875zM286.783 583.04c1.107 4.023 1.075 8.19-.104 12.5-1.185 4.303-3.372 8.815-6.562 13.542-1.947 3.19-3.998 6.074-6.146 8.645a117.59 117.59 0 01-6.771 7.396c-.697.834-1.81 1.875-3.333 3.125a61.927 61.927 0 01-4.792 3.542c-1.667 1.107-3.268 1.907-4.792 2.396-1.53.481-2.643.312-3.333-.521-5-4.03-9.935-8.125-14.792-12.292-4.856-4.166-10.208-8.06-16.041-11.666-.97-.697-1.42-1.355-1.354-1.98.071-.625.455-1.562 1.145-2.812l33.334-50.833c.97-1.394 1.94-2.051 2.916-1.98.97.066 2.012.45 3.125 1.146a102.94 102.94 0 018.75 5.625 69.555 69.555 0 018.125 6.771 47.057 47.057 0 016.563 7.917c1.875 2.845 3.229 6.002 4.062 9.479z"/>
|
||||
<!-- uzz -->
|
||||
<path d="M205.592 196.114c-5.976 36.667-11.354 64.03-16.146 82.083-4.791 18.06-9.134 31.843-13.02 41.355-3.894 9.518-8.164 16.77-12.813 21.77-4.655 5-13.197 9.76-25.625 14.271-12.435 4.518-22.812 7.676-31.146 9.48-8.333 1.81-13.541 2.78-15.625 2.916-2.083-.137-3.405-.52-3.958-1.146-.56-.625-.072-2.116 1.458-4.479 2.637-3.75 8.158-8.887 16.563-15.417 8.398-6.523 18.333-14.648 29.791-24.375 11.459-9.72 20.033-18.294 25.73-25.729 5.69-7.428 10.729-17.565 15.104-30.416 4.375-12.846 8.646-26.283 12.812-40.313 4.167-14.023 7.188-23.542 9.063-28.542 1.875-5 3.782-7.428 5.729-7.291 2.22.416 2.917 2.363 2.083 5.833zm14.792-114.375c1.107 4.03 1.074 8.197-.104 12.5-1.185 4.31-3.373 8.822-6.563 13.542-1.946 3.196-3.997 6.08-6.146 8.646a114.072 114.072 0 01-6.77 7.395c-.697.834-1.81 1.875-3.334 3.125a60.279 60.279 0 01-4.791 3.542c-1.667 1.113-3.269 1.914-4.792 2.396-1.53.488-2.643.312-3.333-.521-5-4.023-9.935-8.125-14.792-12.292-4.863-4.166-10.208-8.053-16.042-11.666-.976-.69-1.426-1.354-1.354-1.98.065-.624.45-1.562 1.146-2.812l33.333-50.833c.97-1.387 1.94-2.045 2.917-1.98.97.072 2.012.456 3.125 1.146a102.945 102.945 0 018.75 5.625 70.208 70.208 0 018.125 6.771 47.58 47.58 0 016.562 7.917c1.875 2.851 3.23 6.009 4.063 9.479zm0 0M256.217 250.489c-1.113 13.893-4.238 25.697-9.375 35.417-5.143 9.726-10.976 14.583-17.5 14.583 0-5.273 1.7-21.667 5.104-49.167 3.399-27.5 5.97-47.187 7.709-59.062 1.731-11.875 3.71-24.48 5.937-37.813 2.22-13.333 4.375-24.095 6.459-32.291a574.618 574.618 0 017.604-20.625 683.688 683.688 0 018.437-20.625c1.94-3.054 3.19-2.565 3.75 1.458-3.476 23.06-6.666 46.98-9.583 71.77-2.917 24.793-4.896 42.54-5.938 53.23-1.041 10.697-1.562 16.947-1.562 18.75-.697 11.393-1.042 19.518-1.042 24.375zm0 0"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 6.6 KiB |
123
docs/Makefile.am
123
docs/Makefile.am
@ -1,123 +0,0 @@
|
||||
# Process this file with automake to produce Makefile.in
|
||||
|
||||
# We require automake 1.6 at least.
|
||||
AUTOMAKE_OPTIONS = 1.6
|
||||
|
||||
# This is a blank Makefile.am for using gtk-doc.
|
||||
# Copy this to your project's API docs directory and modify the variables to
|
||||
# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
|
||||
# of using the various options.
|
||||
|
||||
# The name of the module, e.g. 'glib'.
|
||||
DOC_MODULE=harfbuzz
|
||||
|
||||
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
|
||||
#DOC_MODULE_VERSION=$(HB_VERSION_MAJOR)
|
||||
|
||||
# The top-level SGML file. You can change this if you want to.
|
||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
|
||||
|
||||
# Directories containing the source code.
|
||||
# gtk-doc will search all .c and .h files beneath these paths
|
||||
# for inline comments documenting functions and macros.
|
||||
# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
|
||||
DOC_SOURCE_DIR=$(top_srcdir)/src $(top_builddir)/src
|
||||
|
||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||
SCANGOBJ_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-scan.
|
||||
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
|
||||
SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \
|
||||
--ignore-decorators='HB_EXTERN|HB_DEPRECATED'
|
||||
|
||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||
IGNORE_HFILES=`cd $(top_srcdir)/src; find . -path './*/*.h' | sed 's@^.*/@@'`
|
||||
IGNORE_HFILES+=hb-gobject.h hb-gobject-enums.h hb-gobject-structs.h
|
||||
|
||||
# Extra options to supply to gtkdoc-mkdb.
|
||||
# e.g. MKDB_OPTIONS=--xml-mode --output-format=xml
|
||||
MKDB_OPTIONS=--source-suffixes=h,cc --xml-mode --output-format=xml --ignore-files="$(IGNORE_HFILES)"
|
||||
|
||||
# Extra options to supply to gtkdoc-mktmpl
|
||||
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
|
||||
MKTMPL_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-mkhtml
|
||||
MKHTML_OPTIONS=
|
||||
|
||||
# Extra options to supply to gtkdoc-fixref. Not normally needed.
|
||||
# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
|
||||
FIXXREF_OPTIONS=
|
||||
|
||||
# Used for dependencies. The docs will be rebuilt if any of these change.
|
||||
# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
|
||||
# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
|
||||
HFILE_GLOB=$(top_srcdir)/src/hb.h $(top_srcdir)/src/hb-*.h
|
||||
CFILE_GLOB=$(top_srcdir)/src/hb-*.cc
|
||||
|
||||
# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
|
||||
# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
|
||||
|
||||
# Images to copy into HTML directory.
|
||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||||
HTML_IMAGES= \
|
||||
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
|
||||
content_files= \
|
||||
usermanual-what-is-harfbuzz.xml \
|
||||
usermanual-install-harfbuzz.xml \
|
||||
usermanual-getting-started.xml \
|
||||
usermanual-glyph-information.xml \
|
||||
usermanual-shaping-concepts.xml \
|
||||
usermanual-object-model.xml \
|
||||
usermanual-buffers-language-script-and-direction.xml \
|
||||
usermanual-fonts-and-faces.xml \
|
||||
usermanual-opentype-features.xml \
|
||||
usermanual-clusters.xml \
|
||||
usermanual-utilities.xml \
|
||||
usermanual-integration.xml \
|
||||
version.xml
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
# These files must be listed here *and* in content_files
|
||||
# e.g. expand_content_files=running.sgml
|
||||
expand_content_files=
|
||||
|
||||
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
|
||||
# Only needed if you are using gtkdoc-scangobj to dynamically query widget
|
||||
# signals and properties.
|
||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||
GTKDOC_CFLAGS=
|
||||
GTKDOC_LIBS=$(top_builddir)/src/libharfbuzz.la
|
||||
if HAVE_GOBJECT
|
||||
GTKDOC_LIBS+=$(top_builddir)/src/libharfbuzz-gobject.la
|
||||
endif
|
||||
|
||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
||||
# Other files to distribute
|
||||
# e.g. EXTRA_DIST += version.xml.in
|
||||
EXTRA_DIST += version.xml.in meson.build
|
||||
|
||||
# Files not to distribute
|
||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
|
||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
|
||||
#DISTCLEANFILES +=
|
||||
|
||||
# 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) && \
|
||||
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
|
||||
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
|
||||
#TESTS = $(GTKDOC_CHECK)
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
@ -1,188 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<book id="index">
|
||||
<bookinfo>
|
||||
<title>HarfBuzz Manual</title>
|
||||
<abstract>
|
||||
<title>HarfBuzz</title>
|
||||
<graphic fileref="HarfBuzz.png" format="PNG" align="center"/>
|
||||
<para>
|
||||
HarfBuzz is a text shaping library. Using the HarfBuzz library allows
|
||||
programs to convert a sequence of Unicode input into
|
||||
properly formatted and positioned glyph output—for any writing
|
||||
system and language.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The canonical source-code tree is available at
|
||||
<ulink url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
|
||||
See <xref linkend="download" endterm="download.title"/> for
|
||||
release tarballs.
|
||||
</para>
|
||||
</abstract>
|
||||
</bookinfo>
|
||||
|
||||
<part id="user-manual">
|
||||
<title>User's manual</title>
|
||||
<xi:include href="usermanual-what-is-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-install-harfbuzz.xml"/>
|
||||
<xi:include href="usermanual-getting-started.xml"/>
|
||||
<xi:include href="usermanual-shaping-concepts.xml"/>
|
||||
<xi:include href="usermanual-object-model.xml"/>
|
||||
<xi:include href="usermanual-buffers-language-script-and-direction.xml"/>
|
||||
<xi:include href="usermanual-fonts-and-faces.xml"/>
|
||||
<xi:include href="usermanual-opentype-features.xml"/>
|
||||
<xi:include href="usermanual-clusters.xml"/>
|
||||
<xi:include href="usermanual-utilities.xml"/>
|
||||
<xi:include href="usermanual-integration.xml"/>
|
||||
</part>
|
||||
|
||||
<part id="reference-manual">
|
||||
<partinfo>
|
||||
<releaseinfo>
|
||||
This document is for HarfBuzz &version;.
|
||||
<!--The latest version of this documentation can be found on-line at
|
||||
<ulink role="online-location" url="http://[SERVER]/libharfbuzz/index.html">http://[SERVER]/libharfbuzz/</ulink>.-->
|
||||
</releaseinfo>
|
||||
</partinfo>
|
||||
|
||||
<title>Reference manual</title>
|
||||
<chapter id="core-api">
|
||||
<title>Core API</title>
|
||||
<xi:include href="xml/hb-blob.xml"/>
|
||||
<xi:include href="xml/hb-buffer.xml"/>
|
||||
<xi:include href="xml/hb-common.xml"/>
|
||||
<xi:include href="xml/hb-deprecated.xml"/>
|
||||
<xi:include href="xml/hb-face.xml"/>
|
||||
<xi:include href="xml/hb-font.xml"/>
|
||||
<xi:include href="xml/hb-map.xml"/>
|
||||
<xi:include href="xml/hb-set.xml"/>
|
||||
<xi:include href="xml/hb-shape-plan.xml"/>
|
||||
<xi:include href="xml/hb-shape.xml"/>
|
||||
<xi:include href="xml/hb-unicode.xml"/>
|
||||
<xi:include href="xml/hb-version.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="opentype-api">
|
||||
<title>OpenType API</title>
|
||||
<xi:include href="xml/hb-ot-color.xml"/>
|
||||
<xi:include href="xml/hb-ot-font.xml"/>
|
||||
<xi:include href="xml/hb-ot-layout.xml"/>
|
||||
<xi:include href="xml/hb-ot-math.xml"/>
|
||||
<xi:include href="xml/hb-ot-meta.xml"/>
|
||||
<xi:include href="xml/hb-ot-metrics.xml"/>
|
||||
<xi:include href="xml/hb-ot-name.xml"/>
|
||||
<xi:include href="xml/hb-ot-shape.xml"/>
|
||||
<xi:include href="xml/hb-ot-var.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="apple-advanced-typography-api">
|
||||
<title>Apple Advanced Typography API</title>
|
||||
<xi:include href="xml/hb-aat-layout.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="integration-api">
|
||||
<title>Integration API</title>
|
||||
<xi:include href="xml/hb-coretext.xml"/>
|
||||
<xi:include href="xml/hb-ft.xml"/>
|
||||
<xi:include href="xml/hb-glib.xml"/>
|
||||
<xi:include href="xml/hb-graphite2.xml"/>
|
||||
<xi:include href="xml/hb-icu.xml"/>
|
||||
<xi:include href="xml/hb-uniscribe.xml"/>
|
||||
<xi:include href="xml/hb-gdi.xml"/>
|
||||
<xi:include href="xml/hb-directwrite.xml"/>
|
||||
</chapter>
|
||||
|
||||
<!--chapter id="object-tree">
|
||||
<title>Object Hierarchy</title>
|
||||
<xi:include href="xml/tree_index.sgml"/>
|
||||
</chapter-->
|
||||
|
||||
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
|
||||
|
||||
<index id="api-index-2-7-3" role="2.7.3"><title>Index of new symbols in 2.7.3</title><xi:include href="xml/api-index-2.7.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-6-8" role="2.6.8"><title>Index of new symbols in 2.6.8</title><xi:include href="xml/api-index-2.6.8.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-6-5" role="2.6.5"><title>Index of new symbols in 2.6.5</title><xi:include href="xml/api-index-2.6.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-6-3" role="2.6.3"><title>Index of new symbols in 2.6.3</title><xi:include href="xml/api-index-2.6.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-6-0" role="2.6.0"><title>Index of new symbols in 2.6.0</title><xi:include href="xml/api-index-2.6.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-5-0" role="2.5.0"><title>Index of new symbols in 2.5.0</title><xi:include href="xml/api-index-2.5.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-4-0" role="2.4.0"><title>Index of new symbols in 2.4.0</title><xi:include href="xml/api-index-2.4.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-3-0" role="2.3.0"><title>Index of new symbols in 2.3.0</title><xi:include href="xml/api-index-2.3.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-2-0" role="2.2.0"><title>Index of new symbols in 2.2.0</title><xi:include href="xml/api-index-2.2.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-1-0" role="2.1.0"><title>Index of new symbols in 2.1.0</title><xi:include href="xml/api-index-2.1.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-2-0-0" role="2.0.0"><title>Index of new symbols in 2.0.0</title><xi:include href="xml/api-index-2.0.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-9-0" role="1.9.0"><title>Index of new symbols in 1.9.0</title><xi:include href="xml/api-index-1.9.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-6" role="1.8.6"><title>Index of new symbols in 1.8.6</title><xi:include href="xml/api-index-1.8.6.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-5" role="1.8.5"><title>Index of new symbols in 1.8.5</title><xi:include href="xml/api-index-1.8.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-1" role="1.8.1"><title>Index of new symbols in 1.8.1</title><xi:include href="xml/api-index-1.8.1.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-8-0" role="1.8.0"><title>Index of new symbols in 1.8.0</title><xi:include href="xml/api-index-1.8.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-7-7" role="1.7.7"><title>Index of new symbols in 1.7.7</title><xi:include href="xml/api-index-1.7.7.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-7-5" role="1.7.5"><title>Index of new symbols in 1.7.5</title><xi:include href="xml/api-index-1.7.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-7-2" role="1.7.2"><title>Index of new symbols in 1.7.2</title><xi:include href="xml/api-index-1.7.2.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-6-0" role="1.6.0"><title>Index of new symbols in 1.6.0</title><xi:include href="xml/api-index-1.6.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-5-0" role="1.5.0"><title>Index of new symbols in 1.5.0</title><xi:include href="xml/api-index-1.5.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-4-3" role="1.4.3"><title>Index of new symbols in 1.4.3</title><xi:include href="xml/api-index-1.4.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-4-2" role="1.4.2"><title>Index of new symbols in 1.4.2</title><xi:include href="xml/api-index-1.4.2.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-4-0" role="1.4.0"><title>Index of new symbols in 1.4.0</title><xi:include href="xml/api-index-1.4.0.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-3-3" role="1.3.3"><title>Index of new symbols in 1.3.3</title><xi:include href="xml/api-index-1.3.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-2-3" role="1.2.3"><title>Index of new symbols in 1.2.3</title><xi:include href="xml/api-index-1.2.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-1-3" role="1.1.3"><title>Index of new symbols in 1.1.3</title><xi:include href="xml/api-index-1.1.3.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-1-2" role="1.1.2"><title>Index of new symbols in 1.1.2</title><xi:include href="xml/api-index-1.1.2.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-1-0-5" role="1.0.5"><title>Index of new symbols in 1.0.5</title><xi:include href="xml/api-index-1.0.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-42" role="0.9.42"><title>Index of new symbols in 0.9.42</title><xi:include href="xml/api-index-0.9.42.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-41" role="0.9.41"><title>Index of new symbols in 0.9.41</title><xi:include href="xml/api-index-0.9.41.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-39" role="0.9.39"><title>Index of new symbols in 0.9.39</title><xi:include href="xml/api-index-0.9.39.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-38" role="0.9.38"><title>Index of new symbols in 0.9.38</title><xi:include href="xml/api-index-0.9.38.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-33" role="0.9.33"><title>Index of new symbols in 0.9.33</title><xi:include href="xml/api-index-0.9.33.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-31" role="0.9.31"><title>Index of new symbols in 0.9.31</title><xi:include href="xml/api-index-0.9.31.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-30" role="0.9.30"><title>Index of new symbols in 0.9.30</title><xi:include href="xml/api-index-0.9.30.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-28" role="0.9.28"><title>Index of new symbols in 0.9.28</title><xi:include href="xml/api-index-0.9.28.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-26" role="0.9.26"><title>Index of new symbols in 0.9.26</title><xi:include href="xml/api-index-0.9.26.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-22" role="0.9.22"><title>Index of new symbols in 0.9.22</title><xi:include href="xml/api-index-0.9.22.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-21" role="0.9.21"><title>Index of new symbols in 0.9.21</title><xi:include href="xml/api-index-0.9.21.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-20" role="0.9.20"><title>Index of new symbols in 0.9.20</title><xi:include href="xml/api-index-0.9.20.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-11" role="0.9.11"><title>Index of new symbols in 0.9.11</title><xi:include href="xml/api-index-0.9.11.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-10" role="0.9.10"><title>Index of new symbols in 0.9.10</title><xi:include href="xml/api-index-0.9.10.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-8" role="0.9.8"><title>Index of new symbols in 0.9.8</title><xi:include href="xml/api-index-0.9.8.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-7" role="0.9.7"><title>Index of new symbols in 0.9.7</title><xi:include href="xml/api-index-0.9.7.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-5" role="0.9.5"><title>Index of new symbols in 0.9.5</title><xi:include href="xml/api-index-0.9.5.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-9-2" role="0.9.2"><title>Index of new symbols in 0.9.2</title><xi:include href="xml/api-index-0.9.2.xml"><xi:fallback /></xi:include></index>
|
||||
<index id="api-index-0-6-0" role="0.6.0"><title>Index of new symbols in 0.6.0</title><xi:include href="xml/api-index-0.6.0.xml"><xi:fallback /></xi:include></index>
|
||||
|
||||
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
|
||||
</part>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The current HarfBuzz codebase is versioned 2.x.x and is stable
|
||||
and under active maintenance. This is what is used in latest
|
||||
versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice,
|
||||
XeTeX, Android, and KDE, among other places.
|
||||
</para>
|
||||
<para>
|
||||
Prior to 2012, the original HarfBuzz codebase (which, these days, is
|
||||
referred to as <emphasis>harfbuzz-old</emphasis>) was derived from code
|
||||
in <ulink url="http://freetype.org/">FreeType</ulink>,
|
||||
<ulink url="http://pango.org/">Pango</ulink>, and
|
||||
<ulink url="http://qt-project.org/">Qt</ulink>.
|
||||
It is <emphasis>not</emphasis> actively developed or maintained, and is
|
||||
extremely buggy. All users of harfbuzz-old are encouraged to switch over
|
||||
to the new HarfBuzz as soon as possible.
|
||||
</para>
|
||||
<para>
|
||||
To make this distinction clearer in discussions, the current HarfBuzz
|
||||
codebase is sometimes referred to as <emphasis>harfbuzz-ng</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
For reference purposes, the harfbuzz-old source tree is archived
|
||||
<ulink url="http://cgit.freedesktop.org/harfbuzz.old/">here</ulink>.
|
||||
There are no release tarballs of harfbuzz-old whatsoever.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</book>
|
@ -1,705 +0,0 @@
|
||||
<SUBSECTION Private>
|
||||
HB_H_IN
|
||||
HB_OT_H_IN
|
||||
HB_AAT_H_IN
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-aat-layout</FILE>
|
||||
HB_AAT_LAYOUT_NO_SELECTOR_INDEX
|
||||
hb_aat_layout_feature_type_t
|
||||
hb_aat_layout_feature_selector_t
|
||||
hb_aat_layout_feature_selector_info_t
|
||||
hb_aat_layout_feature_type_get_name_id
|
||||
hb_aat_layout_feature_type_get_selector_infos
|
||||
hb_aat_layout_get_feature_types
|
||||
hb_aat_layout_has_positioning
|
||||
hb_aat_layout_has_substitution
|
||||
hb_aat_layout_has_tracking
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-blob</FILE>
|
||||
hb_blob_create
|
||||
hb_blob_create_from_file
|
||||
hb_blob_create_sub_blob
|
||||
hb_blob_copy_writable_or_fail
|
||||
hb_blob_destroy
|
||||
hb_blob_get_data
|
||||
hb_blob_get_data_writable
|
||||
hb_blob_get_empty
|
||||
hb_blob_get_length
|
||||
hb_blob_get_user_data
|
||||
hb_blob_is_immutable
|
||||
hb_blob_make_immutable
|
||||
hb_blob_reference
|
||||
hb_blob_set_user_data
|
||||
hb_blob_t
|
||||
hb_memory_mode_t
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-buffer</FILE>
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
|
||||
hb_buffer_create
|
||||
hb_buffer_reference
|
||||
hb_buffer_get_empty
|
||||
hb_buffer_destroy
|
||||
hb_buffer_reset
|
||||
hb_buffer_clear_contents
|
||||
hb_buffer_pre_allocate
|
||||
hb_buffer_allocation_successful
|
||||
hb_buffer_add
|
||||
hb_buffer_add_codepoints
|
||||
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
|
||||
hb_buffer_get_direction
|
||||
hb_buffer_set_script
|
||||
hb_buffer_get_script
|
||||
hb_buffer_set_language
|
||||
hb_buffer_get_language
|
||||
hb_buffer_set_flags
|
||||
hb_buffer_get_flags
|
||||
hb_buffer_set_cluster_level
|
||||
hb_buffer_get_cluster_level
|
||||
hb_buffer_set_length
|
||||
hb_buffer_get_length
|
||||
hb_buffer_set_segment_properties
|
||||
hb_buffer_get_segment_properties
|
||||
hb_buffer_guess_segment_properties
|
||||
hb_buffer_set_unicode_funcs
|
||||
hb_buffer_get_unicode_funcs
|
||||
hb_buffer_set_user_data
|
||||
hb_buffer_get_user_data
|
||||
hb_buffer_get_glyph_infos
|
||||
hb_buffer_get_glyph_positions
|
||||
hb_buffer_has_positions
|
||||
hb_buffer_get_invisible_glyph
|
||||
hb_buffer_set_invisible_glyph
|
||||
hb_buffer_set_replacement_codepoint
|
||||
hb_buffer_get_replacement_codepoint
|
||||
hb_buffer_normalize_glyphs
|
||||
hb_buffer_reverse
|
||||
hb_buffer_reverse_range
|
||||
hb_buffer_reverse_clusters
|
||||
hb_buffer_serialize
|
||||
hb_buffer_serialize_glyphs
|
||||
hb_buffer_deserialize_glyphs
|
||||
hb_buffer_serialize_unicode
|
||||
hb_buffer_deserialize_unicode
|
||||
hb_buffer_serialize_format_from_string
|
||||
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
|
||||
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>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-common</FILE>
|
||||
hb_tag_from_string
|
||||
hb_tag_to_string
|
||||
hb_direction_from_string
|
||||
hb_direction_to_string
|
||||
hb_script_from_iso15924_tag
|
||||
hb_script_from_string
|
||||
hb_script_to_iso15924_tag
|
||||
hb_script_get_horizontal_direction
|
||||
hb_language_from_string
|
||||
hb_language_to_string
|
||||
hb_language_get_default
|
||||
hb_feature_from_string
|
||||
hb_feature_to_string
|
||||
hb_variation_from_string
|
||||
hb_variation_to_string
|
||||
hb_bool_t
|
||||
hb_codepoint_t
|
||||
hb_destroy_func_t
|
||||
hb_direction_t
|
||||
hb_language_t
|
||||
hb_feature_t
|
||||
hb_variation_t
|
||||
hb_mask_t
|
||||
hb_position_t
|
||||
hb_tag_t
|
||||
hb_script_t
|
||||
hb_user_data_key_t
|
||||
HB_TAG
|
||||
HB_TAG_NONE
|
||||
HB_TAG_MAX
|
||||
HB_TAG_MAX_SIGNED
|
||||
HB_UNTAG
|
||||
HB_DIRECTION_REVERSE
|
||||
HB_DIRECTION_IS_BACKWARD
|
||||
HB_DIRECTION_IS_FORWARD
|
||||
HB_DIRECTION_IS_HORIZONTAL
|
||||
HB_DIRECTION_IS_VALID
|
||||
HB_DIRECTION_IS_VERTICAL
|
||||
HB_LANGUAGE_INVALID
|
||||
HB_FEATURE_GLOBAL_END
|
||||
HB_FEATURE_GLOBAL_START
|
||||
<SUBSECTION Private>
|
||||
HB_BEGIN_DECLS
|
||||
HB_END_DECLS
|
||||
hb_var_int_t
|
||||
int16_t
|
||||
int32_t
|
||||
int64_t
|
||||
int8_t
|
||||
uint16_t
|
||||
uint32_t
|
||||
uint64_t
|
||||
uint8_t
|
||||
<SUBSECTION Private>
|
||||
HB_EXTERN
|
||||
HB_DEPRECATED
|
||||
HB_DEPRECATED_FOR
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-deprecated</FILE>
|
||||
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_MATH_GLYPH_PART_FLAG_EXTENDER
|
||||
hb_ot_layout_table_choose_script
|
||||
hb_ot_layout_table_find_script
|
||||
hb_ot_tag_from_language
|
||||
hb_ot_tags_from_script
|
||||
HB_OT_VAR_NO_AXIS_INDEX
|
||||
hb_ot_var_axis_t
|
||||
hb_ot_var_find_axis
|
||||
hb_ot_var_get_axes
|
||||
hb_set_invert
|
||||
hb_unicode_eastasian_width_func_t
|
||||
hb_unicode_eastasian_width
|
||||
hb_unicode_funcs_set_eastasian_width_func
|
||||
HB_UNICODE_MAX_DECOMPOSITION_LEN
|
||||
hb_unicode_decompose_compatibility_func_t
|
||||
hb_unicode_decompose_compatibility
|
||||
hb_unicode_funcs_set_decompose_compatibility_func
|
||||
hb_font_funcs_set_glyph_v_kerning_func
|
||||
hb_font_get_glyph_v_kerning
|
||||
hb_font_get_glyph_v_kerning_func_t
|
||||
</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>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-directwrite</FILE>
|
||||
hb_directwrite_face_create
|
||||
hb_directwrite_face_get_font_face
|
||||
<SUBSECTION Private>
|
||||
hb_directwrite_shape_experimental_width
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-face</FILE>
|
||||
hb_face_count
|
||||
hb_face_t
|
||||
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
|
||||
hb_face_get_user_data
|
||||
hb_face_is_immutable
|
||||
hb_face_make_immutable
|
||||
hb_face_reference
|
||||
hb_face_reference_blob
|
||||
hb_face_reference_table
|
||||
hb_face_set_glyph_count
|
||||
hb_face_set_index
|
||||
hb_face_set_upem
|
||||
hb_face_set_user_data
|
||||
hb_face_collect_unicodes
|
||||
hb_face_collect_variation_selectors
|
||||
hb_face_collect_variation_unicodes
|
||||
hb_face_builder_create
|
||||
hb_face_builder_add_table
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-font</FILE>
|
||||
hb_font_add_glyph_origin_for_direction
|
||||
hb_font_create
|
||||
hb_font_create_sub_font
|
||||
hb_font_destroy
|
||||
hb_font_funcs_create
|
||||
hb_font_funcs_destroy
|
||||
hb_font_funcs_get_empty
|
||||
hb_font_funcs_get_user_data
|
||||
hb_font_funcs_is_immutable
|
||||
hb_font_funcs_make_immutable
|
||||
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_h_advance_func
|
||||
hb_font_funcs_set_glyph_h_advances_func
|
||||
hb_font_funcs_set_glyph_h_kerning_func
|
||||
hb_font_funcs_set_glyph_h_origin_func
|
||||
hb_font_funcs_set_glyph_name_func
|
||||
hb_font_funcs_set_glyph_v_advance_func
|
||||
hb_font_funcs_set_glyph_v_advances_func
|
||||
hb_font_funcs_set_glyph_v_origin_func
|
||||
hb_font_funcs_set_nominal_glyph_func
|
||||
hb_font_funcs_set_nominal_glyphs_func
|
||||
hb_font_funcs_set_user_data
|
||||
hb_font_funcs_set_variation_glyph_func
|
||||
hb_font_funcs_t
|
||||
hb_font_get_empty
|
||||
hb_font_get_face
|
||||
hb_font_get_glyph
|
||||
hb_font_get_glyph_advance_for_direction
|
||||
hb_font_get_glyph_advance_func_t
|
||||
hb_font_get_glyph_advances_for_direction
|
||||
hb_font_get_glyph_advances_func_t
|
||||
hb_font_get_glyph_contour_point
|
||||
hb_font_get_glyph_contour_point_for_origin
|
||||
hb_font_get_glyph_contour_point_func_t
|
||||
hb_font_get_glyph_extents
|
||||
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_h_advance
|
||||
hb_font_get_glyph_h_advance_func_t
|
||||
hb_font_get_glyph_h_advances
|
||||
hb_font_get_glyph_h_advances_func_t
|
||||
hb_font_get_glyph_h_kerning
|
||||
hb_font_get_glyph_h_kerning_func_t
|
||||
hb_font_get_glyph_h_origin
|
||||
hb_font_get_glyph_h_origin_func_t
|
||||
hb_font_get_glyph_kerning_for_direction
|
||||
hb_font_get_glyph_kerning_func_t
|
||||
hb_font_get_glyph_name
|
||||
hb_font_get_glyph_name_func_t
|
||||
hb_font_get_glyph_origin_for_direction
|
||||
hb_font_get_glyph_origin_func_t
|
||||
hb_font_get_glyph_v_advance
|
||||
hb_font_get_glyph_v_advance_func_t
|
||||
hb_font_get_glyph_v_advances
|
||||
hb_font_get_glyph_v_advances_func_t
|
||||
hb_font_get_glyph_v_origin
|
||||
hb_font_get_glyph_v_origin_func_t
|
||||
hb_font_get_nominal_glyph
|
||||
hb_font_get_nominal_glyph_func_t
|
||||
hb_font_get_nominal_glyphs
|
||||
hb_font_get_nominal_glyphs_func_t
|
||||
hb_font_get_parent
|
||||
hb_font_get_ppem
|
||||
hb_font_get_ptem
|
||||
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_font_set_variations
|
||||
hb_font_set_var_coords_design
|
||||
hb_font_set_var_coords_normalized
|
||||
hb_font_set_var_named_instance
|
||||
hb_font_subtract_glyph_origin_for_direction
|
||||
hb_font_t
|
||||
hb_reference_table_func_t
|
||||
hb_font_funcs_set_font_h_extents_func
|
||||
hb_font_funcs_set_font_v_extents_func
|
||||
hb_font_get_extents_for_direction
|
||||
hb_font_get_font_extents_func_t
|
||||
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_extents_t
|
||||
hb_glyph_extents_t
|
||||
<SUBSECTION Private>
|
||||
hb_font_get_var_coords_design
|
||||
hb_font_draw_glyph
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ft</FILE>
|
||||
hb_ft_face_create
|
||||
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_lock_face
|
||||
hb_ft_font_unlock_face
|
||||
hb_ft_font_set_load_flags
|
||||
hb_ft_font_get_load_flags
|
||||
hb_ft_font_set_funcs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-gdi</FILE>
|
||||
hb_gdi_face_create
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-glib</FILE>
|
||||
hb_glib_get_unicode_funcs
|
||||
hb_glib_script_from_script
|
||||
hb_glib_script_to_script
|
||||
hb_glib_blob_create
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-graphite2</FILE>
|
||||
HB_GRAPHITE2_TAG_SILF
|
||||
hb_graphite2_face_get_gr_face
|
||||
hb_graphite2_font_get_gr_font
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-icu</FILE>
|
||||
hb_icu_get_unicode_funcs
|
||||
hb_icu_script_from_script
|
||||
hb_icu_script_to_script
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-map</FILE>
|
||||
HB_MAP_VALUE_INVALID
|
||||
hb_map_allocation_successful
|
||||
hb_map_clear
|
||||
hb_map_create
|
||||
hb_map_del
|
||||
hb_map_destroy
|
||||
hb_map_get
|
||||
hb_map_get_empty
|
||||
hb_map_get_population
|
||||
hb_map_get_user_data
|
||||
hb_map_has
|
||||
hb_map_is_empty
|
||||
hb_map_reference
|
||||
hb_map_set
|
||||
hb_map_set_user_data
|
||||
hb_map_t
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-color</FILE>
|
||||
hb_color_t
|
||||
HB_COLOR
|
||||
hb_color_get_alpha
|
||||
hb_color_get_blue
|
||||
hb_color_get_green
|
||||
hb_color_get_red
|
||||
hb_ot_color_glyph_get_layers
|
||||
hb_ot_color_glyph_reference_png
|
||||
hb_ot_color_glyph_reference_svg
|
||||
hb_ot_color_has_layers
|
||||
hb_ot_color_has_palettes
|
||||
hb_ot_color_has_png
|
||||
hb_ot_color_has_svg
|
||||
hb_ot_color_layer_t
|
||||
hb_ot_color_palette_color_get_name_id
|
||||
hb_ot_color_palette_flags_t
|
||||
hb_ot_color_palette_get_colors
|
||||
hb_ot_color_palette_get_count
|
||||
hb_ot_color_palette_get_flags
|
||||
hb_ot_color_palette_get_name_id
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-font</FILE>
|
||||
hb_ot_font_set_funcs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-name</FILE>
|
||||
hb_ot_name_id_t
|
||||
HB_OT_NAME_ID_INVALID
|
||||
hb_ot_name_entry_t
|
||||
hb_ot_name_list_names
|
||||
hb_ot_name_get_utf16
|
||||
hb_ot_name_get_utf32
|
||||
hb_ot_name_get_utf8
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-layout</FILE>
|
||||
HB_OT_MAX_TAGS_PER_LANGUAGE
|
||||
HB_OT_MAX_TAGS_PER_SCRIPT
|
||||
HB_OT_TAG_DEFAULT_LANGUAGE
|
||||
HB_OT_TAG_DEFAULT_SCRIPT
|
||||
hb_ot_tag_to_language
|
||||
hb_ot_tag_to_script
|
||||
hb_ot_tags_from_script_and_language
|
||||
hb_ot_tags_to_script_and_language
|
||||
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX
|
||||
HB_OT_LAYOUT_NO_FEATURE_INDEX
|
||||
HB_OT_LAYOUT_NO_SCRIPT_INDEX
|
||||
HB_OT_LAYOUT_NO_VARIATIONS_INDEX
|
||||
HB_OT_TAG_BASE
|
||||
HB_OT_TAG_GDEF
|
||||
HB_OT_TAG_GPOS
|
||||
HB_OT_TAG_GSUB
|
||||
HB_OT_TAG_JSTF
|
||||
hb_ot_layout_baseline_tag_t
|
||||
hb_ot_layout_collect_lookups
|
||||
hb_ot_layout_collect_features
|
||||
hb_ot_layout_feature_get_characters
|
||||
hb_ot_layout_feature_get_lookups
|
||||
hb_ot_layout_feature_get_name_ids
|
||||
hb_ot_layout_feature_with_variations_get_lookups
|
||||
hb_ot_layout_get_attach_points
|
||||
hb_ot_layout_get_baseline
|
||||
hb_ot_layout_get_glyph_class
|
||||
hb_ot_layout_get_glyphs_in_class
|
||||
hb_ot_layout_get_ligature_carets
|
||||
hb_ot_layout_get_size_params
|
||||
hb_ot_layout_glyph_class_t
|
||||
hb_ot_layout_has_glyph_classes
|
||||
hb_ot_layout_has_positioning
|
||||
hb_ot_layout_has_substitution
|
||||
hb_ot_layout_language_find_feature
|
||||
hb_ot_layout_language_get_feature_indexes
|
||||
hb_ot_layout_language_get_feature_tags
|
||||
hb_ot_layout_language_get_required_feature
|
||||
hb_ot_layout_lookup_collect_glyphs
|
||||
hb_ot_layout_lookup_get_glyph_alternates
|
||||
hb_ot_layout_lookup_substitute_closure
|
||||
hb_ot_layout_lookups_substitute_closure
|
||||
hb_ot_layout_lookup_would_substitute
|
||||
hb_ot_layout_script_find_language
|
||||
hb_ot_layout_script_get_language_tags
|
||||
hb_ot_layout_script_select_language
|
||||
hb_ot_layout_table_find_feature_variations
|
||||
hb_ot_layout_table_get_feature_tags
|
||||
hb_ot_layout_table_get_script_tags
|
||||
hb_ot_layout_table_get_lookup_count
|
||||
hb_ot_layout_table_select_script
|
||||
hb_ot_shape_plan_collect_lookups
|
||||
hb_ot_layout_language_get_required_feature_index
|
||||
<SUBSECTION Private>
|
||||
Xhb_ot_layout_lookup_enumerate_sequences
|
||||
Xhb_ot_layout_lookup_position
|
||||
Xhb_ot_layout_lookup_substitute
|
||||
hb_ot_layout_glyph_sequence_t
|
||||
hb_ot_layout_glyph_sequence_func_t
|
||||
</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-meta</FILE>
|
||||
hb_ot_meta_tag_t
|
||||
hb_ot_meta_get_entry_tags
|
||||
hb_ot_meta_reference_entry
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-metrics</FILE>
|
||||
hb_ot_metrics_tag_t
|
||||
hb_ot_metrics_get_position
|
||||
hb_ot_metrics_get_variation
|
||||
hb_ot_metrics_get_x_variation
|
||||
hb_ot_metrics_get_y_variation
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-shape</FILE>
|
||||
hb_ot_shape_glyphs_closure
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-var</FILE>
|
||||
HB_OT_TAG_VAR_AXIS_ITALIC
|
||||
HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE
|
||||
HB_OT_TAG_VAR_AXIS_SLANT
|
||||
HB_OT_TAG_VAR_AXIS_WEIGHT
|
||||
HB_OT_TAG_VAR_AXIS_WIDTH
|
||||
hb_ot_var_has_data
|
||||
hb_ot_var_axis_flags_t
|
||||
hb_ot_var_axis_info_t
|
||||
hb_ot_var_find_axis_info
|
||||
hb_ot_var_get_axis_count
|
||||
hb_ot_var_get_axis_infos
|
||||
hb_ot_var_get_named_instance_count
|
||||
hb_ot_var_named_instance_get_subfamily_name_id
|
||||
hb_ot_var_named_instance_get_postscript_name_id
|
||||
hb_ot_var_named_instance_get_design_coords
|
||||
hb_ot_var_normalize_variations
|
||||
hb_ot_var_normalize_coords
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-set</FILE>
|
||||
HB_SET_VALUE_INVALID
|
||||
hb_set_add
|
||||
hb_set_add_range
|
||||
hb_set_allocation_successful
|
||||
hb_set_clear
|
||||
hb_set_create
|
||||
hb_set_del
|
||||
hb_set_del_range
|
||||
hb_set_destroy
|
||||
hb_set_get_empty
|
||||
hb_set_get_max
|
||||
hb_set_get_min
|
||||
hb_set_get_population
|
||||
hb_set_get_user_data
|
||||
hb_set_has
|
||||
hb_set_intersect
|
||||
hb_set_is_empty
|
||||
hb_set_is_equal
|
||||
hb_set_is_subset
|
||||
hb_set_next
|
||||
hb_set_next_range
|
||||
hb_set_previous
|
||||
hb_set_previous_range
|
||||
hb_set_reference
|
||||
hb_set_set
|
||||
hb_set_set_user_data
|
||||
hb_set_subtract
|
||||
hb_set_symmetric_difference
|
||||
hb_set_t
|
||||
hb_set_union
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-shape</FILE>
|
||||
hb_shape
|
||||
hb_shape_full
|
||||
hb_shape_list_shapers
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<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
|
||||
hb_shape_plan_get_shaper
|
||||
hb_shape_plan_get_user_data
|
||||
hb_shape_plan_reference
|
||||
hb_shape_plan_set_user_data
|
||||
hb_shape_plan_t
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-unicode</FILE>
|
||||
HB_UNICODE_MAX
|
||||
hb_unicode_combining_class
|
||||
hb_unicode_combining_class_func_t
|
||||
hb_unicode_combining_class_t
|
||||
hb_unicode_compose
|
||||
hb_unicode_compose_func_t
|
||||
hb_unicode_decompose
|
||||
hb_unicode_decompose_func_t
|
||||
hb_unicode_funcs_create
|
||||
hb_unicode_funcs_destroy
|
||||
hb_unicode_funcs_get_default
|
||||
hb_unicode_funcs_get_empty
|
||||
hb_unicode_funcs_get_parent
|
||||
hb_unicode_funcs_get_user_data
|
||||
hb_unicode_funcs_is_immutable
|
||||
hb_unicode_funcs_make_immutable
|
||||
hb_unicode_funcs_reference
|
||||
hb_unicode_funcs_set_combining_class_func
|
||||
hb_unicode_funcs_set_compose_func
|
||||
hb_unicode_funcs_set_decompose_func
|
||||
hb_unicode_funcs_set_general_category_func
|
||||
hb_unicode_funcs_set_mirroring_func
|
||||
hb_unicode_funcs_set_script_func
|
||||
hb_unicode_funcs_set_user_data
|
||||
hb_unicode_funcs_t
|
||||
hb_unicode_general_category
|
||||
hb_unicode_general_category_func_t
|
||||
hb_unicode_general_category_t
|
||||
hb_unicode_mirroring
|
||||
hb_unicode_mirroring_func_t
|
||||
hb_unicode_script
|
||||
hb_unicode_script_func_t
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-uniscribe</FILE>
|
||||
hb_uniscribe_font_get_hfont
|
||||
hb_uniscribe_font_get_logfontw
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-version</FILE>
|
||||
HB_VERSION_ATLEAST
|
||||
HB_VERSION_MAJOR
|
||||
HB_VERSION_MICRO
|
||||
HB_VERSION_MINOR
|
||||
HB_VERSION_STRING
|
||||
hb_version
|
||||
hb_version_atleast
|
||||
hb_version_string
|
||||
</SECTION>
|
@ -1,66 +0,0 @@
|
||||
if build_machine.system() == 'windows'
|
||||
message('Skipping gtk-doc while building on Windows')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
if not find_program('gtkdoc-scan', required: get_option('docs')).found()
|
||||
message('Not building documentation as gtk-doc was not found')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
conf.set('HAVE_GTK_DOC', 1)
|
||||
|
||||
gnome = import('gnome')
|
||||
|
||||
docconf = configuration_data()
|
||||
docconf.set('HB_VERSION', meson.project_version())
|
||||
|
||||
version_xml = configure_file(input: 'version.xml.in',
|
||||
output: 'version.xml',
|
||||
configuration: docconf)
|
||||
|
||||
content_files = [
|
||||
'usermanual-what-is-harfbuzz.xml',
|
||||
'usermanual-install-harfbuzz.xml',
|
||||
'usermanual-getting-started.xml',
|
||||
'usermanual-glyph-information.xml',
|
||||
'usermanual-shaping-concepts.xml',
|
||||
'usermanual-object-model.xml',
|
||||
'usermanual-buffers-language-script-and-direction.xml',
|
||||
'usermanual-fonts-and-faces.xml',
|
||||
'usermanual-opentype-features.xml',
|
||||
'usermanual-clusters.xml',
|
||||
'usermanual-utilities.xml',
|
||||
'usermanual-integration.xml',
|
||||
version_xml,
|
||||
]
|
||||
|
||||
html_images = [
|
||||
'HarfBuzz.png',
|
||||
'HarfBuzz.svg',
|
||||
]
|
||||
|
||||
ignore_headers = [
|
||||
'hb-gobject.h',
|
||||
'hb-gobject-enums.h',
|
||||
'hb-gobject-enums-tmp.h',
|
||||
'hb-gobject-structs.h',
|
||||
]
|
||||
|
||||
gnome.gtkdoc('harfbuzz',
|
||||
main_sgml: 'harfbuzz-docs.xml',
|
||||
src_dir: [join_paths(meson.current_source_dir(), '../src'),
|
||||
join_paths(meson.current_build_dir(), '../src'),
|
||||
],
|
||||
scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED',
|
||||
'--ignore-decorators=HB_EXTERN|HB_DEPRECATED',
|
||||
],
|
||||
mkdb_args: ['--source-suffixes=h,cc',
|
||||
'--xml-mode',
|
||||
'--output-format=xml',
|
||||
],
|
||||
content_files: content_files,
|
||||
html_assets: html_images,
|
||||
ignore_headers: ignore_headers,
|
||||
dependencies: [libharfbuzz_dep],
|
||||
install: true)
|
@ -1,412 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="buffers-language-script-and-direction">
|
||||
<title>Buffers, language, script and direction</title>
|
||||
<para>
|
||||
The input to the HarfBuzz shaper is a series of Unicode characters, stored in a
|
||||
buffer. In this chapter, we'll look at how to set up a buffer with
|
||||
the text that we want and how to customize the properties of the
|
||||
buffer. We'll also look at a piece of lower-level machinery that
|
||||
you will need to understand before proceeding: the functions that
|
||||
HarfBuzz uses to retrieve Unicode information.
|
||||
</para>
|
||||
<para>
|
||||
After shaping is complete, HarfBuzz puts its output back
|
||||
into the buffer. But getting that output requires setting up a
|
||||
face and a font first, so we will look at that in the next chapter
|
||||
instead of here.
|
||||
</para>
|
||||
<section id="creating-and-destroying-buffers">
|
||||
<title>Creating and destroying buffers</title>
|
||||
<para>
|
||||
As we saw in our <emphasis>Getting Started</emphasis> example, a
|
||||
buffer is created and
|
||||
initialized with <function>hb_buffer_create()</function>. This
|
||||
produces a new, empty buffer object, instantiated with some
|
||||
default values and ready to accept your Unicode strings.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages the memory of objects (such as buffers) that it
|
||||
creates, so you don't have to. When you have finished working on
|
||||
a buffer, you can call <function>hb_buffer_destroy()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_t *buf = hb_buffer_create();
|
||||
...
|
||||
hb_buffer_destroy(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
This will destroy the object and free its associated memory -
|
||||
unless some other part of the program holds a reference to this
|
||||
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>
|
||||
<programlisting language="C">
|
||||
void somefunc(hb_buffer_t *buf) {
|
||||
buf = hb_buffer_reference(buf);
|
||||
...
|
||||
</programlisting>
|
||||
<para>
|
||||
And then decrease it once you're done with it:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
While we are on the subject of reference-counting buffers, it is
|
||||
worth noting that an individual buffer can only meaningfully be
|
||||
used by one thread at a time.
|
||||
</para>
|
||||
<para>
|
||||
To throw away all the data in your buffer and start from scratch,
|
||||
call <function>hb_buffer_reset(buf)</function>. If you want to
|
||||
throw away the string in the buffer but keep the options, you can
|
||||
instead call <function>hb_buffer_clear_contents(buf)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="adding-text-to-the-buffer">
|
||||
<title>Adding text to the buffer</title>
|
||||
<para>
|
||||
Now we have a brand new HarfBuzz buffer. Let's start filling it
|
||||
with text! From HarfBuzz's perspective, a buffer is just a stream
|
||||
of Unicode code points, but your input string is probably in one of
|
||||
the standard Unicode character encodings (UTF-8, UTF-16, or
|
||||
UTF-32). HarfBuzz provides convenience functions that accept
|
||||
each of these encodings:
|
||||
<function>hb_buffer_add_utf8()</function>,
|
||||
<function>hb_buffer_add_utf16()</function>, and
|
||||
<function>hb_buffer_add_utf32()</function>. Other than the
|
||||
character encoding they accept, they function identically.
|
||||
</para>
|
||||
<para>
|
||||
You can add UTF-8 text to a buffer by passing in the text array,
|
||||
the array's length, an offset into the array for the first
|
||||
character to add, and the length of the segment to add:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8 (hb_buffer_t *buf,
|
||||
const char *text,
|
||||
int text_length,
|
||||
unsigned int item_offset,
|
||||
int item_length)
|
||||
</programlisting>
|
||||
<para>
|
||||
So, in practice, you can say:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text));
|
||||
</programlisting>
|
||||
<para>
|
||||
This will append your new characters to
|
||||
<parameter>buf</parameter>, not replace its existing
|
||||
contents. Also, note that you can use <literal>-1</literal> in
|
||||
place of the first instance of <function>strlen(text)</function>
|
||||
if your text array is NULL-terminated. Similarly, you can also use
|
||||
<literal>-1</literal> as the final argument want to add its full
|
||||
contents.
|
||||
</para>
|
||||
<para>
|
||||
Whatever start <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> you provide, HarfBuzz will also
|
||||
attempt to grab the five characters <emphasis>before</emphasis>
|
||||
the offset point and the five characters
|
||||
<emphasis>after</emphasis> the designated end. These are the
|
||||
before and after "context" segments, which are used internally
|
||||
for HarfBuzz to make shaping decisions. They will not be part of
|
||||
the final output, but they ensure that HarfBuzz's
|
||||
script-specific shaping operations are correct. If there are
|
||||
fewer than five characters available for the before or after
|
||||
contexts, HarfBuzz will just grab what is there.
|
||||
</para>
|
||||
<para>
|
||||
For longer text runs, such as full paragraphs, it might be
|
||||
tempting to only add smaller sub-segments to a buffer and
|
||||
shape them in piecemeal fashion. Generally, this is not a good
|
||||
idea, however, because a lot of shaping decisions are
|
||||
dependent on this context information. For example, in Arabic
|
||||
and other connected scripts, HarfBuzz needs to know the code
|
||||
points before and after each character in order to correctly
|
||||
determine which glyph to return.
|
||||
</para>
|
||||
<para>
|
||||
The safest approach is to add all of the text available (even
|
||||
if your text contains a mix of scripts, directions, languages
|
||||
and fonts), then use <parameter>item_offset</parameter> and
|
||||
<parameter>item_length</parameter> to indicate which characters you
|
||||
want shaped (which must all have the same script, direction,
|
||||
language and font), so that HarfBuzz has access to any context.
|
||||
</para>
|
||||
<para>
|
||||
You can also add Unicode code points directly with
|
||||
<function>hb_buffer_add_codepoints()</function>. The arguments
|
||||
to this function are the same as those for the UTF
|
||||
encodings. But it is particularly important to note that
|
||||
HarfBuzz does not do validity checking on the text that is added
|
||||
to a buffer. Invalid code points will be replaced, but it is up
|
||||
to you to do any deep-sanity checking necessary.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="setting-buffer-properties">
|
||||
<title>Setting buffer properties</title>
|
||||
<para>
|
||||
Buffers containing input characters still need several
|
||||
properties set before HarfBuzz can shape their text correctly.
|
||||
</para>
|
||||
<para>
|
||||
Initially, all buffers are set to the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_INVALID</literal> content
|
||||
type. After adding text, the buffer should be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_UNICODE</literal> instead, which
|
||||
indicates that it contains un-shaped input
|
||||
characters. After shaping, the buffer will have the
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal> content type.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_buffer_add_utf8()</function> and the
|
||||
other UTF functions set the content type of their buffer
|
||||
automatically. But if you are reusing a buffer you may want to
|
||||
check its state with
|
||||
<function>hb_buffer_get_content_type(buffer)</function>. If
|
||||
necessary you can set the content type with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_content_type(buf, HB_BUFFER_CONTENT_TYPE_UNICODE);
|
||||
</programlisting>
|
||||
<para>
|
||||
to prepare for shaping.
|
||||
</para>
|
||||
<para>
|
||||
Buffers also need to carry information about the script,
|
||||
language, and text direction of their contents. You can set
|
||||
these properties individually:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<para>
|
||||
However, since these properties are often repeated for
|
||||
multiple text runs, you can also save them in a
|
||||
<literal>hb_segment_properties_t</literal> for reuse:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_segment_properties_t *savedprops;
|
||||
hb_buffer_get_segment_properties (buf, savedprops);
|
||||
...
|
||||
hb_buffer_set_segment_properties (buf2, savedprops);
|
||||
</programlisting>
|
||||
<para>
|
||||
HarfBuzz also provides getter functions to retrieve a buffer's
|
||||
direction, script, and language properties individually.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz recognizes four text directions in
|
||||
<type>hb_direction_t</type>: left-to-right
|
||||
(<literal>HB_DIRECTION_LTR</literal>), right-to-left (<literal>HB_DIRECTION_RTL</literal>),
|
||||
top-to-bottom (<literal>HB_DIRECTION_TTB</literal>), and
|
||||
bottom-to-top (<literal>HB_DIRECTION_BTT</literal>). For the
|
||||
script property, HarfBuzz uses identifiers based on the
|
||||
<ulink
|
||||
url="https://unicode.org/iso15924/">ISO 15924
|
||||
standard</ulink>. For languages, HarfBuzz uses tags based on the
|
||||
<ulink url="https://tools.ietf.org/html/bcp47">IETF BCP 47</ulink> standard.
|
||||
</para>
|
||||
<para>
|
||||
Helper functions are provided to convert character strings into
|
||||
the necessary script and language tag types.
|
||||
</para>
|
||||
<para>
|
||||
Two additional buffer properties to be aware of are the
|
||||
"invisible glyph" and the replacement code point. The
|
||||
replacement code point is inserted into buffer output in place of
|
||||
any invalid code points encountered in the input. By default, it
|
||||
is the Unicode <literal>REPLACEMENT CHARACTER</literal> code
|
||||
point, <literal>U+FFFD</literal> "�". You can change this with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_replacement_codepoint(buf, replacement);
|
||||
</programlisting>
|
||||
<para>
|
||||
passing in the replacement Unicode code point as the
|
||||
<parameter>replacement</parameter> parameter.
|
||||
</para>
|
||||
<para>
|
||||
The invisible glyph is used to replace all output glyphs that
|
||||
are invisible. By default, the standard space character
|
||||
<literal>U+0020</literal> is used; you can replace this (for
|
||||
example, when using a font that provides script-specific
|
||||
spaces) with
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_invisible_glyph(buf, replacement_glyph);
|
||||
</programlisting>
|
||||
<para>
|
||||
Do note that in the <parameter>replacement_glyph</parameter>
|
||||
parameter, you must provide the glyph ID of the replacement you
|
||||
wish to use, not the Unicode code point.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz supports a few additional flags you might want to set
|
||||
on your buffer under certain circumstances. The
|
||||
<literal>HB_BUFFER_FLAG_BOT</literal> and
|
||||
<literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
|
||||
that the buffer represents the beginning or end (respectively)
|
||||
of a text element (such as a paragraph or other block). Knowing
|
||||
this allows HarfBuzz to apply certain contextual font features
|
||||
when shaping, such as initial or final variants in connected
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
<literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
|
||||
tells HarfBuzz not to hide glyphs with the
|
||||
<literal>Default_Ignorable</literal> property in Unicode. This
|
||||
property designates control characters and other non-printing
|
||||
code points, such as joiners and variation selectors. Normally
|
||||
HarfBuzz replaces them in the output buffer with zero-width
|
||||
space glyphs (using the "invisible glyph" property discussed
|
||||
above); setting this flag causes them to be printed, which can
|
||||
be helpful for troubleshooting.
|
||||
</para>
|
||||
<para>
|
||||
Conversely, setting the
|
||||
<literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
|
||||
tells HarfBuzz to remove <literal>Default_Ignorable</literal>
|
||||
glyphs from the output buffer entirely. Finally, setting the
|
||||
<literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
|
||||
flag tells HarfBuzz not to insert the dotted-circle glyph
|
||||
(<literal>U+25CC</literal>, "◌"), which is normally
|
||||
inserted into buffer output when broken character sequences are
|
||||
encountered (such as combining marks that are not attached to a
|
||||
base character).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="customizing-unicode-functions">
|
||||
<title>Customizing Unicode functions</title>
|
||||
<para>
|
||||
HarfBuzz requires some simple functions for accessing
|
||||
information from the Unicode Character Database (such as the
|
||||
<literal>General_Category</literal> (gc) and
|
||||
<literal>Script</literal> (sc) properties) that is useful
|
||||
for shaping, as well as some useful operations like composing and
|
||||
decomposing code points.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz includes its own internal, lightweight set of Unicode
|
||||
functions. At build time, it is also possible to compile support
|
||||
for some other options, such as the Unicode functions provided
|
||||
by GLib or the International Components for Unicode (ICU)
|
||||
library. Generally, this option is only of interest for client
|
||||
programs that have specific integration requirements or that do
|
||||
a significant amount of customization.
|
||||
</para>
|
||||
<para>
|
||||
If your program has access to other Unicode functions, however,
|
||||
such as through a system library or application framework, you
|
||||
might prefer to use those instead of the built-in
|
||||
options. HarfBuzz supports this by implementing its Unicode
|
||||
functions as a set of virtual methods that you can replace —
|
||||
without otherwise affecting HarfBuzz's functionality.
|
||||
</para>
|
||||
<para>
|
||||
The Unicode functions are specified in a structure called
|
||||
<literal>unicode_funcs</literal> which is attached to each
|
||||
buffer. But even though <literal>unicode_funcs</literal> is
|
||||
associated with a <type>hb_buffer_t</type>, the functions
|
||||
themselves are called by other HarfBuzz APIs that access
|
||||
buffers, so it would be unwise for you to hook different
|
||||
functions into different buffers.
|
||||
</para>
|
||||
<para>
|
||||
In addition, you can mark your <literal>unicode_funcs</literal>
|
||||
as immutable by calling
|
||||
<function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
|
||||
This is especially useful if your code is a
|
||||
library or framework that will have its own client programs. By
|
||||
marking your Unicode function choices as immutable, you prevent
|
||||
your own client programs from changing the
|
||||
<literal>unicode_funcs</literal> configuration and introducing
|
||||
inconsistencies and errors downstream.
|
||||
</para>
|
||||
<para>
|
||||
You can retrieve the Unicode-functions configuration for
|
||||
your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_t *ufunctions;
|
||||
ufunctions = hb_buffer_get_unicode_funcs(buf);
|
||||
</programlisting>
|
||||
<para>
|
||||
The current version of <literal>unicode_funcs</literal> uses six functions:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_combining_class_func_t</function>:
|
||||
returns the Canonical Combining Class of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_general_category_func_t</function>:
|
||||
returns the General Category (gc) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_mirroring_func_t</function>: returns
|
||||
the Mirroring Glyph code point (for bi-directional
|
||||
replacement) of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_script_func_t</function>: returns the
|
||||
Script (sc) property of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_compose_func_t</function>: returns the
|
||||
canonical composition of a sequence of two code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_unicode_decompose_func_t</function>: returns
|
||||
the canonical decomposition of a code point.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Note, however, that future HarfBuzz releases may alter this set.
|
||||
</para>
|
||||
<para>
|
||||
Each Unicode function has a corresponding setter, with which you
|
||||
can assign a callback to your replacement function. For example,
|
||||
to replace
|
||||
<function>hb_unicode_general_category_func_t</function>, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)
|
||||
</programlisting>
|
||||
<para>
|
||||
Virtualizing this set of Unicode functions is primarily intended
|
||||
to improve portability. There is no need for every client
|
||||
program to make the effort to replace the default options, so if
|
||||
you are unsure, do not feel any pressure to customize
|
||||
<literal>unicode_funcs</literal>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -1,697 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="clusters">
|
||||
<title>Clusters</title>
|
||||
<section id="clusters-and-shaping">
|
||||
<title>Clusters and shaping</title>
|
||||
<para>
|
||||
In text shaping, a <emphasis>cluster</emphasis> is a sequence of
|
||||
characters that needs to be treated as a single, indivisible
|
||||
unit. A single letter or symbol can be a cluster of its
|
||||
own. Other clusters correspond to longer subsequences of the
|
||||
input code points — such as a ligature or conjunct form
|
||||
— and require the shaper to ensure that the cluster is not
|
||||
broken during the shaping process.
|
||||
</para>
|
||||
<para>
|
||||
A cluster is distinct from a <emphasis>grapheme</emphasis>,
|
||||
which is the smallest unit of meaning in a writing system or
|
||||
script.
|
||||
</para>
|
||||
<para>
|
||||
The definitions of the two terms are similar. However, clusters
|
||||
are only relevant for script shaping and glyph layout. In
|
||||
contrast, graphemes are a property of the underlying script, and
|
||||
are of interest when client programs implement orthographic
|
||||
or linguistic functionality.
|
||||
</para>
|
||||
<para>
|
||||
For example, two individual letters are often two separate
|
||||
graphemes. When two letters form a ligature, however, they
|
||||
combine into a single glyph. They are then part of the same
|
||||
cluster and are treated as a unit by the shaping engine —
|
||||
even though the two original, underlying letters remain separate
|
||||
graphemes.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz is concerned with clusters, <emphasis>not</emphasis>
|
||||
with graphemes — although client programs using HarfBuzz
|
||||
may still care about graphemes for other reasons from time to time.
|
||||
</para>
|
||||
<para>
|
||||
During the shaping process, there are several shaping operations
|
||||
that may merge adjacent characters (for example, when two code
|
||||
points form a ligature or a conjunct form and are replaced by a
|
||||
single glyph) or split one character into several (for example,
|
||||
when decomposing a code point through the
|
||||
<literal>ccmp</literal> feature). Operations like these alter
|
||||
clusters; HarfBuzz tracks the changes to ensure that no clusters
|
||||
get lost or broken during shaping.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz records cluster information independently from how
|
||||
shaping operations affect the individual glyphs returned in an
|
||||
output buffer. Consequently, a client program using HarfBuzz can
|
||||
utilize the cluster information to implement features such as:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Correctly positioning the cursor within a shaped text run,
|
||||
even when characters have formed ligatures, composed or
|
||||
decomposed, reordered, or undergone other shaping operations.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Correctly highlighting a text selection that includes some,
|
||||
but not all, of the characters in a word.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Applying text attributes (such as color or underlining) to
|
||||
part, but not all, of a word.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Generating output document formats (such as PDF) with
|
||||
embedded text that can be fully extracted.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Determining the mapping between input characters and output
|
||||
glyphs, such as which glyphs are ligatures.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Performing line-breaking, justification, and other
|
||||
line-level or paragraph-level operations that must be done
|
||||
after shaping is complete, but which require examining
|
||||
character-level properties.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section id="working-with-harfbuzz-clusters">
|
||||
<title>Working with HarfBuzz clusters</title>
|
||||
<para>
|
||||
When you add text to a HarfBuzz buffer, each code point must be
|
||||
assigned a <emphasis>cluster value</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
This cluster value is an arbitrary number; HarfBuzz uses it only
|
||||
to distinguish between clusters. Many client programs will use
|
||||
the index of each code point in the input text stream as the
|
||||
cluster value. This is for the sake of convenience; the actual
|
||||
value does not matter.
|
||||
</para>
|
||||
<para>
|
||||
Some of the shaping operations performed by HarfBuzz —
|
||||
such as reordering, composition, decomposition, and substitution
|
||||
— may alter the cluster values of some characters. The
|
||||
final cluster values in the buffer at the end of the shaping
|
||||
process will indicate to client programs which subsequences of
|
||||
glyphs represent a cluster and, therefore, must not be
|
||||
separated.
|
||||
</para>
|
||||
<para>
|
||||
In addition, client programs can query the final cluster values
|
||||
to discern other potentially important information about the
|
||||
glyphs in the output buffer (such as whether or not a ligature
|
||||
was formed).
|
||||
</para>
|
||||
<para>
|
||||
For example, if the initial sequence of cluster values was:
|
||||
</para>
|
||||
<programlisting>
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
and the final sequence of cluster values is:
|
||||
</para>
|
||||
<programlisting>
|
||||
0,0,3,3
|
||||
</programlisting>
|
||||
<para>
|
||||
then there are two clusters in the output buffer: the first
|
||||
cluster includes the first two glyphs, and the second cluster
|
||||
includes the third and fourth glyphs. It is also evident that a
|
||||
ligature or conjunct has been formed, because there are fewer
|
||||
glyphs in the output buffer (four) than there were code points
|
||||
in the input buffer (five).
|
||||
</para>
|
||||
<para>
|
||||
Although client programs using HarfBuzz are free to assign
|
||||
initial cluster values in any manner they choose to, HarfBuzz
|
||||
does offer some useful guarantees if the cluster values are
|
||||
assigned in a monotonic (either non-decreasing or non-increasing)
|
||||
order.
|
||||
</para>
|
||||
<para>
|
||||
For buffers in the left-to-right (LTR)
|
||||
or top-to-bottom (TTB) text flow direction,
|
||||
HarfBuzz will preserve the monotonic property: client programs
|
||||
are guaranteed that monotonically increasing initial cluster
|
||||
values will be returned as monotonically increasing final
|
||||
cluster values.
|
||||
</para>
|
||||
<para>
|
||||
For buffers in the right-to-left (RTL)
|
||||
or bottom-to-top (BTT) text flow direction,
|
||||
the directionality of the buffer itself is reversed for final
|
||||
output as a matter of design. Therefore, HarfBuzz inverts the
|
||||
monotonic property: client programs are guaranteed that
|
||||
monotonically increasing initial cluster values will be
|
||||
returned as monotonically <emphasis>decreasing</emphasis> final
|
||||
cluster values.
|
||||
</para>
|
||||
<para>
|
||||
Client programs can adjust how HarfBuzz handles clusters during
|
||||
shaping by setting the
|
||||
<literal>cluster_level</literal> of the
|
||||
buffer. HarfBuzz offers three <emphasis>levels</emphasis> of
|
||||
clustering support for this property:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><emphasis>Level 0</emphasis> is the default and
|
||||
reproduces the behavior of the old HarfBuzz library.
|
||||
</para>
|
||||
<para>
|
||||
The distinguishing feature of level 0 behavior is that, at
|
||||
the beginning of processing the buffer, all code points that
|
||||
are categorized as <emphasis>marks</emphasis>,
|
||||
<emphasis>modifier symbols</emphasis>, or
|
||||
<emphasis>Emoji extended pictographic</emphasis> modifiers,
|
||||
as well as the <emphasis>Zero Width Joiner</emphasis> and
|
||||
<emphasis>Zero Width Non-Joiner</emphasis> code points, are
|
||||
assigned the cluster value of the closest preceding code
|
||||
point from <emphasis>different</emphasis> category.
|
||||
</para>
|
||||
<para>
|
||||
In essence, whenever a base character is followed by a mark
|
||||
character or a sequence of mark characters, those marks are
|
||||
reassigned to the same initial cluster value as the base
|
||||
character. This reassignment is referred to as
|
||||
"merging" the affected clusters. This behavior is based on
|
||||
the Grapheme Cluster Boundary specification in <ulink
|
||||
url="https://www.unicode.org/reports/tr29/#Regex_Definitions">Unicode
|
||||
Technical Report 29</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Client programs can specify level 0 behavior for a buffer by
|
||||
setting its <literal>cluster_level</literal> to
|
||||
<literal>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Level 1</emphasis> tweaks the old behavior
|
||||
slightly to produce better results. Therefore, level 1
|
||||
clustering is recommended for code that is not required to
|
||||
implement backward compatibility with the old HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
Level 1 differs from level 0 by not merging the
|
||||
clusters of marks and other modifier code points with the
|
||||
preceding "base" code point's cluster. By preserving the
|
||||
separate cluster values of these marks and modifier code
|
||||
points, script shapers can perform additional operations
|
||||
that might lead to improved results (for example, reordering
|
||||
a sequence of marks).
|
||||
</para>
|
||||
<para>
|
||||
Client programs can specify level 1 behavior for a buffer by
|
||||
setting its <literal>cluster_level</literal> to
|
||||
<literal>HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>Level 2</emphasis> differs significantly in how it
|
||||
treats cluster values. In level 2, HarfBuzz never merges
|
||||
clusters.
|
||||
</para>
|
||||
<para>
|
||||
This difference can be seen most clearly when HarfBuzz processes
|
||||
ligature substitutions and glyph decompositions. In level 0
|
||||
and level 1, ligatures and glyph decomposition both involve
|
||||
merging clusters; in level 2, neither of these operations
|
||||
triggers a merge.
|
||||
</para>
|
||||
<para>
|
||||
Client programs can specify level 2 behavior for a buffer by
|
||||
setting its <literal>cluster_level</literal> to
|
||||
<literal>HB_BUFFER_CLUSTER_LEVEL_CHARACTERS</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As mentioned earlier, client programs using HarfBuzz often
|
||||
assign initial cluster values in a buffer by reusing the indices
|
||||
of the code points in the input text. This gives a sequence of
|
||||
cluster values that is monotonically increasing (for example,
|
||||
0,1,2,3,4).
|
||||
</para>
|
||||
<para>
|
||||
It is not <emphasis>required</emphasis> that the cluster values
|
||||
in a buffer be monotonically increasing. However, if the initial
|
||||
cluster values in a buffer are monotonic and the buffer is
|
||||
configured to use cluster level 0 or 1, then HarfBuzz
|
||||
guarantees that the final cluster values in the shaped buffer
|
||||
will also be monotonic. No such guarantee is made for cluster
|
||||
level 2.
|
||||
</para>
|
||||
<para>
|
||||
In levels 0 and 1, HarfBuzz implements the following conceptual
|
||||
model for cluster values:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
If the sequence of input cluster values is monotonic, the
|
||||
sequence of cluster values will remain monotonic.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Each cluster value represents a single cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Each cluster contains one or more glyphs and one or more
|
||||
characters.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
In practice, this model offers several benefits. Assuming that
|
||||
the initial cluster values were monotonically increasing
|
||||
and distinct before shaping began, then, in the final output:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
All adjacent glyphs having the same final cluster
|
||||
value belong to the same cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Each character belongs to the cluster that has the highest
|
||||
cluster value <emphasis>not larger than</emphasis> its
|
||||
initial cluster value.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="a-clustering-example-for-levels-0-and-1">
|
||||
<title>A clustering example for levels 0 and 1</title>
|
||||
<para>
|
||||
The basic shaping operations affect clusters in a predictable
|
||||
manner when using level 0 or level 1:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When two or more clusters <emphasis>merge</emphasis>, the
|
||||
resulting merged cluster takes as its cluster value the
|
||||
<emphasis>minimum</emphasis> of the incoming cluster values.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
When a cluster <emphasis>decomposes</emphasis>, all of the
|
||||
resulting child clusters inherit as their cluster value the
|
||||
cluster value of the parent cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
When a character is <emphasis>reordered</emphasis>, the
|
||||
reordered character and all clusters that the character
|
||||
moves past as part of the reordering are merged into one cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
The functionality, guarantees, and benefits of level 0 and level
|
||||
1 behavior can be seen with some examples. First, let us examine
|
||||
what happens with cluster values when shaping involves cluster
|
||||
merging with ligatures and decomposition.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Let's say we start with the following character sequence (top row) and
|
||||
initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
During shaping, HarfBuzz maps these characters to glyphs from
|
||||
the font. For simplicity, let us assume that each character maps
|
||||
to the corresponding, identical-looking glyph:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now if, for example, <literal>B</literal> and <literal>C</literal>
|
||||
form a ligature, then the clusters to which they belong
|
||||
"merge". This merged cluster takes for its cluster
|
||||
value the minimum of all the cluster values of the clusters that
|
||||
went in to the ligature. In this case, we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC,D,E
|
||||
0,1 ,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
because 1 is the minimum of the set {1,2}, which were the
|
||||
cluster values of <literal>B</literal> and
|
||||
<literal>C</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Next, let us say that the <literal>BC</literal> ligature glyph
|
||||
decomposes into three components, and <literal>D</literal> also
|
||||
decomposes into two components. Whenever a cluster decomposes,
|
||||
its components each inherit the cluster value of their parent:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2,D0,D1,E
|
||||
0,1 ,1 ,1 ,3 ,3 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Next, if <literal>BC2</literal> and <literal>D0</literal> form a
|
||||
ligature, then their clusters (cluster values 1 and 3) merge into
|
||||
<literal>min(1,3) = 1</literal>:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,BC0,BC1,BC2D0,D1,E
|
||||
0,1 ,1 ,1 ,1 ,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Note that the entirety of cluster 3 merges into cluster 1, not
|
||||
just the <literal>D0</literal> glyph. This reflects the fact
|
||||
that the cluster <emphasis>must</emphasis> be treated as an
|
||||
indivisible unit.
|
||||
</para>
|
||||
<para>
|
||||
At this point, cluster 1 means: the character sequence
|
||||
<literal>BCD</literal> is represented by glyphs
|
||||
<literal>BC0,BC1,BC2D0,D1</literal> and cannot be broken down any
|
||||
further.
|
||||
</para>
|
||||
</section>
|
||||
<section id="reordering-in-levels-0-and-1">
|
||||
<title>Reordering in levels 0 and 1</title>
|
||||
<para>
|
||||
Another common operation in the more complex shapers is glyph
|
||||
reordering. In order to maintain a monotonic cluster sequence
|
||||
when glyph reordering takes place, HarfBuzz merges the clusters
|
||||
of everything in the reordering sequence.
|
||||
</para>
|
||||
<para>
|
||||
For example, let us again start with the character sequence (top
|
||||
row) and initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
If <literal>D</literal> is reordered to the position immediately
|
||||
before <literal>B</literal>, then HarfBuzz merges the
|
||||
<literal>B</literal>, <literal>C</literal>, and
|
||||
<literal>D</literal> clusters — all the clusters between
|
||||
the final position of the reordered glyph and its original
|
||||
position. This means that we get:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,1,1,1,4
|
||||
</programlisting>
|
||||
<para>
|
||||
as the final cluster sequence.
|
||||
</para>
|
||||
<para>
|
||||
Merging this many clusters is not ideal, but it is the only
|
||||
sensible way for HarfBuzz to maintain the guarantee that the
|
||||
sequence of cluster values remains monotonic and to retain the
|
||||
true relationship between glyphs and characters.
|
||||
</para>
|
||||
</section>
|
||||
<section id="the-distinction-between-levels-0-and-1">
|
||||
<title>The distinction between levels 0 and 1</title>
|
||||
<para>
|
||||
The preceding examples demonstrate the main effects of using
|
||||
cluster levels 0 and 1. The only difference between the two
|
||||
levels is this: in level 0, at the very beginning of the shaping
|
||||
process, HarfBuzz merges the cluster of each base character
|
||||
with the clusters of all Unicode marks (combining or not) and
|
||||
modifiers that follow it.
|
||||
</para>
|
||||
<para>
|
||||
For example, let us start with the following character sequence
|
||||
(top row) and accompanying initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,1 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
The <literal>acute</literal> is a Unicode mark. If HarfBuzz is
|
||||
using cluster level 0 on this sequence, then the
|
||||
<literal>A</literal> and <literal>acute</literal> clusters will
|
||||
merge, and the result will become:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B
|
||||
0,0 ,2
|
||||
</programlisting>
|
||||
<para>
|
||||
This merger is performed before any other script-shaping
|
||||
steps.
|
||||
</para>
|
||||
<para>
|
||||
This initial cluster merging is the default behavior of the
|
||||
Windows shaping engine, and the old HarfBuzz codebase copied
|
||||
that behavior to maintain compatibility. Consequently, it has
|
||||
remained the default behavior in the new HarfBuzz codebase.
|
||||
</para>
|
||||
<para>
|
||||
But this initial cluster-merging behavior makes it impossible
|
||||
for client programs to implement some features (such as to
|
||||
color diacritic marks differently from their base
|
||||
characters). That is why, in level 1, HarfBuzz does not perform
|
||||
the initial merging step.
|
||||
</para>
|
||||
<para>
|
||||
For client programs that rely on HarfBuzz cluster values to
|
||||
perform cursor positioning, level 0 is more convenient. But
|
||||
relying on cluster boundaries for cursor positioning is wrong: cursor
|
||||
positions should be determined based on Unicode grapheme
|
||||
boundaries, not on shaping-cluster boundaries. As such, using
|
||||
level 1 clustering behavior is recommended.
|
||||
</para>
|
||||
<para>
|
||||
One final facet of levels 0 and 1 is worth noting. HarfBuzz
|
||||
currently does not allow any
|
||||
<emphasis>multiple-substitution</emphasis> GSUB lookups to
|
||||
replace a glyph with zero glyphs (in other words, to delete a
|
||||
glyph).
|
||||
</para>
|
||||
<para>
|
||||
But, in some other situations, glyphs can be deleted. In
|
||||
those cases, if the glyph being deleted is the last glyph of its
|
||||
cluster, HarfBuzz makes sure to merge the deleted glyph's
|
||||
cluster with a neighboring cluster.
|
||||
</para>
|
||||
<para>
|
||||
This is done primarily to make sure that the starting cluster of the
|
||||
text always has the cluster index pointing to the start of the text
|
||||
for the run; more than one client program currently relies on this
|
||||
guarantee.
|
||||
</para>
|
||||
<para>
|
||||
Incidentally, Apple's CoreText does something different to
|
||||
maintain the same promise: it inserts a glyph with id 65535 at
|
||||
the beginning of the glyph string if the glyph corresponding to
|
||||
the first character in the run was deleted. HarfBuzz might do
|
||||
something similar in the future.
|
||||
</para>
|
||||
</section>
|
||||
<section id="level-2">
|
||||
<title>Level 2</title>
|
||||
<para>
|
||||
HarfBuzz's level 2 cluster behavior uses a significantly
|
||||
different model than that of level 0 and level 1.
|
||||
</para>
|
||||
<para>
|
||||
The level 2 behavior is easy to describe, but it may be
|
||||
difficult to understand in practical terms. In brief, level 2
|
||||
performs no merging of clusters whatsoever.
|
||||
</para>
|
||||
<para>
|
||||
This means that there is no initial base-and-mark merging step
|
||||
(as is done in level 0), and it means that reordering moves and
|
||||
ligature substitutions do not trigger a cluster merge.
|
||||
</para>
|
||||
<para>
|
||||
Only one shaping operation directly affects clusters when using
|
||||
level 2:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
When a cluster <emphasis>decomposes</emphasis>, all of the
|
||||
resulting child clusters inherit as their cluster value the
|
||||
cluster value of the parent cluster.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
When glyphs do form a ligature (or when some other feature
|
||||
substitutes multiple glyphs with one glyph) the cluster value
|
||||
of the first glyph is retained as the cluster value for the
|
||||
resulting ligature.
|
||||
</para>
|
||||
<para>
|
||||
This occurrence sounds similar to a cluster merge, but it is
|
||||
different. In particular, no subsequent characters —
|
||||
including marks and modifiers — are affected. They retain
|
||||
their previous cluster values.
|
||||
</para>
|
||||
<para>
|
||||
Level 2 cluster behavior is ultimately less complex than level 0
|
||||
or level 1, but there are several cases for which processing
|
||||
cluster values produced at level 2 may be tricky.
|
||||
</para>
|
||||
<section id="ligatures-with-combining-marks-in-level-2">
|
||||
<title>Ligatures with combining marks in level 2</title>
|
||||
<para>
|
||||
The first example of how HarfBuzz's level 2 cluster behavior
|
||||
can be tricky is when the text to be shaped includes combining
|
||||
marks attached to ligatures.
|
||||
</para>
|
||||
<para>
|
||||
Let us start with an input sequence with the following
|
||||
characters (top row) and initial cluster values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,acute,B,breve,C,circumflex
|
||||
0,1 ,2,3 ,4,5
|
||||
</programlisting>
|
||||
<para>
|
||||
If the sequence <literal>A,B,C</literal> forms a ligature,
|
||||
then these are the cluster values HarfBuzz will return under
|
||||
the various cluster levels:
|
||||
</para>
|
||||
<para>
|
||||
Level 0:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC,acute,breve,circumflex
|
||||
0 ,0 ,0 ,0
|
||||
</programlisting>
|
||||
<para>
|
||||
Level 1:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC,acute,breve,circumflex
|
||||
0 ,0 ,0 ,5
|
||||
</programlisting>
|
||||
<para>
|
||||
Level 2:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC,acute,breve,circumflex
|
||||
0 ,1 ,3 ,5
|
||||
</programlisting>
|
||||
<para>
|
||||
Making sense of the level 2 result is the hardest for a client
|
||||
program, because there is nothing in the cluster values that
|
||||
indicates that <literal>B</literal> and <literal>C</literal>
|
||||
formed a ligature with <literal>A</literal>.
|
||||
</para>
|
||||
<para>
|
||||
In contrast, the "merged" cluster values of the mark glyphs
|
||||
that are seen in the level 0 and level 1 output are evidence
|
||||
that a ligature substitution took place.
|
||||
</para>
|
||||
</section>
|
||||
<section id="reordering-in-level-2">
|
||||
<title>Reordering in level 2</title>
|
||||
<para>
|
||||
Another example of how HarfBuzz's level 2 cluster behavior
|
||||
can be tricky is when glyphs reorder. Consider an input sequence
|
||||
with the following characters (top row) and initial cluster
|
||||
values (bottom row):
|
||||
</para>
|
||||
<programlisting>
|
||||
A,B,C,D,E
|
||||
0,1,2,3,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Now imagine <literal>D</literal> moves before
|
||||
<literal>B</literal> in a reordering operation. The cluster
|
||||
values will then be:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,D,B,C,E
|
||||
0,3,1,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
Next, if <literal>D</literal> forms a ligature with
|
||||
<literal>B</literal>, the output is:
|
||||
</para>
|
||||
<programlisting>
|
||||
A,DB,C,E
|
||||
0,3 ,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
However, in a different scenario, in which the shaping rules
|
||||
of the script instead caused <literal>A</literal> and
|
||||
<literal>B</literal> to form a ligature
|
||||
<emphasis>before</emphasis> the <literal>D</literal> reordered, the
|
||||
result would be:
|
||||
</para>
|
||||
<programlisting>
|
||||
AB,D,C,E
|
||||
0 ,3,2,4
|
||||
</programlisting>
|
||||
<para>
|
||||
There is no way for a client program to differentiate between
|
||||
these two scenarios based on the cluster values
|
||||
alone. Consequently, client programs that use level 2 might
|
||||
need to undertake additional work in order to manage cursor
|
||||
positioning, text attributes, or other desired features.
|
||||
</para>
|
||||
</section>
|
||||
<section id="other-considerations-in-level-2">
|
||||
<title>Other considerations in level 2</title>
|
||||
<para>
|
||||
There may be other problems encountered with ligatures under
|
||||
level 2, such as if the direction of the text is forced to
|
||||
the opposite of its natural direction (for example, Arabic text
|
||||
that is forced into left-to-right directionality). But,
|
||||
generally speaking, these other scenarios are minor corner
|
||||
cases that are too obscure for most client programs to need to
|
||||
worry about.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
@ -1,467 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="fonts-and-faces">
|
||||
<title>Fonts, faces, and output</title>
|
||||
<para>
|
||||
In the previous chapter, we saw how to set up a buffer and fill
|
||||
it with text as Unicode code points. In order to shape this
|
||||
buffer text with HarfBuzz, you will need also need a font
|
||||
object.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides abstractions to help you cache and reuse the
|
||||
heavier parts of working with binary fonts, so we will look at
|
||||
how to do that. We will also look at how to work with the
|
||||
FreeType font-rendering library and at how you can customize
|
||||
HarfBuzz to work with other libraries.
|
||||
</para>
|
||||
<para>
|
||||
Finally, we will look at how to work with OpenType variable
|
||||
fonts, the latest update to the OpenType font format, and at
|
||||
some other recent additions to OpenType.
|
||||
</para>
|
||||
|
||||
<section id="fonts-and-faces-objects">
|
||||
<title>Font and face objects</title>
|
||||
<para>
|
||||
The outcome of shaping a run of text depends on the contents of
|
||||
a specific font file (such as the substitutions and positioning
|
||||
moves in the 'GSUB' and 'GPOS' tables), so HarfBuzz makes
|
||||
accessing those internals fast.
|
||||
</para>
|
||||
<para>
|
||||
An <type>hb_face_t</type> represents a <emphasis>face</emphasis>
|
||||
in HarfBuzz. This data type is a wrapper around an
|
||||
<type>hb_blob_t</type> blob that holds the contents of a binary
|
||||
font file. Since HarfBuzz supports TrueType Collections and
|
||||
OpenType Collections (each of which can include multiple
|
||||
typefaces), a HarfBuzz face also requires an index number
|
||||
specifying which typeface in the file you want to use. Most of
|
||||
the font files you will encounter in the wild include just a
|
||||
single face, however, so most of the time you would pass in
|
||||
<literal>0</literal> as the index when you create a face:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_t* blob = hb_blob_create_from_file(file);
|
||||
...
|
||||
hb_face_t* face = hb_face_create(blob, 0);
|
||||
</programlisting>
|
||||
<para>
|
||||
On its own, a face object is not quite ready to use for
|
||||
shaping. The typeface must be set to a specific point size in
|
||||
order for some details (such as hinting) to work. In addition,
|
||||
if the font file in question is an OpenType Variable Font, then
|
||||
you may need to specify one or variation-axis settings (or a
|
||||
named instance) in order to get the output you need.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, you do this by creating a <emphasis>font</emphasis>
|
||||
object from your face.
|
||||
</para>
|
||||
<para>
|
||||
Font objects also have the advantage of being considerably
|
||||
lighter-weight than face objects (remember that a face contains
|
||||
the contents of a binary font file mapped into memory). As a
|
||||
result, you can cache and reuse a font object, but you could
|
||||
also create a new one for each additional size you needed.
|
||||
Creating new fonts incurs some additional overhead, of course,
|
||||
but whether or not it is excessive is your call in the end. In
|
||||
contrast, face objects are substantially larger, and you really
|
||||
should cache them and reuse them whenever possible.
|
||||
</para>
|
||||
<para>
|
||||
You can create a font object from a face object:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_t* hb_font = hb_font_create(hb_face);
|
||||
</programlisting>
|
||||
<para>
|
||||
After creating a font, there are a few properties you should
|
||||
set. Many fonts enable and disable hints based on the size it
|
||||
is used at, so setting this is important for font
|
||||
objects. <function>hb_font_set_ppem(font, x_ppem,
|
||||
y_ppem)</function> sets the pixels-per-EM value of the font. You
|
||||
can also set the point size of the font with
|
||||
<function>hb_font_set_ptem(font, ptem)</function>. HarfBuzz uses the
|
||||
industry standard 72 points per inch.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz lets you specify the degree subpixel precision you want
|
||||
through a scaling factor. You can set horizontal and
|
||||
vertical scaling factors on the
|
||||
font by calling <function>hb_font_set_scale(font, x_scale,
|
||||
y_scale)</function>.
|
||||
</para>
|
||||
<para>
|
||||
There may be times when you are handed a font object and need to
|
||||
access the face object that it comes from. For that, you can call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_face = hb_font_get_face(hb_font);
|
||||
</programlisting>
|
||||
<para>
|
||||
You can also create a font object from an existing font object
|
||||
using the <function>hb_font_create_sub_font()</function>
|
||||
function. This creates a child font object that is initiated
|
||||
with the same attributes as its parent; it can be used to
|
||||
quickly set up a new font for the purpose of overriding a specific
|
||||
font-functions method.
|
||||
</para>
|
||||
<para>
|
||||
All face objects and font objects are lifecycle-managed by
|
||||
HarfBuzz. After creating a face, you increase its reference
|
||||
count with <function>hb_face_reference(face)</function> and
|
||||
decrease it with
|
||||
<function>hb_face_destroy(face)</function>. Likewise, you
|
||||
increase the reference count on a font with
|
||||
<function>hb_font_reference(font)</function> and decrease it
|
||||
with <function>hb_font_destroy(font)</function>.
|
||||
</para>
|
||||
<para>
|
||||
You can also attach user data to face objects and font objects.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="fonts-and-faces-custom-functions">
|
||||
<title>Customizing font functions</title>
|
||||
<para>
|
||||
During shaping, HarfBuzz frequently needs to query font objects
|
||||
to get at the contents and parameters of the glyphs in a font
|
||||
file. It includes a built-in set of functions that is tailored
|
||||
to working with OpenType fonts. However, as was the case with
|
||||
Unicode functions in the buffers chapter, HarfBuzz also wants to
|
||||
make it easy for you to assign a substitute set of font
|
||||
functions if you are developing a program to work with a library
|
||||
or platform that provides its own font functions.
|
||||
</para>
|
||||
<para>
|
||||
Therefore, the HarfBuzz API defines a set of virtual
|
||||
methods for accessing font-object properties, and you can
|
||||
replace the defaults with your own selections without
|
||||
interfering with the shaping process. Each font object in
|
||||
HarfBuzz includes a structure called
|
||||
<literal>font_funcs</literal> that serves as a vtable for the
|
||||
font object. The virtual methods in
|
||||
<literal>font_funcs</literal> are:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_font_h_extents_func_t</function>: returns
|
||||
the extents of the font for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_font_v_extents_func_t</function>: returns
|
||||
the extents of the font for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_nominal_glyph_func_t</function>: returns
|
||||
the font's nominal glyph for a given code point.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_variation_glyph_func_t</function>: returns
|
||||
the font's glyph for a given code point when it is followed by a
|
||||
given Variation Selector.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_nominal_glyphs_func_t</function>: returns
|
||||
the font's nominal glyphs for a series of code points.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_advance_func_t</function>: returns
|
||||
the advance for a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_advance_func_t</function>: returns
|
||||
the advance for a glyph for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_advance_func_t</function>:returns
|
||||
the advance for a glyph for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs for horizontal text .
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_advances_func_t</function>: returns
|
||||
the advances for a series of glyphs for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_h_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph for horizontal text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_v_origin_func_t</function>: returns
|
||||
the origin coordinates of a glyph for vertical text.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_extents_func_t</function>: returns
|
||||
the extents for a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_contour_point_func_t</function>:
|
||||
returns the coordinates of a specific contour point from a glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_name_func_t</function>: returns the
|
||||
name of a glyph (from its glyph index).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<function>hb_font_get_glyph_from_name_func_t</function>: returns
|
||||
the glyph index that corresponds to a given glyph name.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
You can create new font-functions by calling
|
||||
<function>hb_font_funcs_create()</function>:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
|
||||
hb_font_set_funcs (font, ffunctions, font_data, destroy);
|
||||
</programlisting>
|
||||
<para>
|
||||
The individual methods can each be set with their own setter
|
||||
function, such as
|
||||
<function>hb_font_funcs_set_nominal_glyph_func(ffunctions,
|
||||
func, user_data, destroy)</function>.
|
||||
</para>
|
||||
<para>
|
||||
Font-functions structures can be reused for multiple font
|
||||
objects, and can be reference counted with
|
||||
<function>hb_font_funcs_reference()</function> and
|
||||
<function>hb_font_funcs_destroy()</function>. Just like other
|
||||
objects in HarfBuzz, you can set user-data for each
|
||||
font-functions structure and assign a destroy callback for
|
||||
it.
|
||||
</para>
|
||||
<para>
|
||||
You can also mark a font-functions structure as immutable,
|
||||
with <function>hb_font_funcs_make_immutable()</function>. This
|
||||
is especially useful if your code is a library or framework that
|
||||
will have its own client programs. By marking your
|
||||
font-functions structures as immutable, you prevent your client
|
||||
programs from changing the configuration and introducing
|
||||
inconsistencies and errors downstream.
|
||||
</para>
|
||||
<para>
|
||||
To override only some functions while using the default implementation
|
||||
for the others, you will need to create a sub-font. By default, the
|
||||
sub-font uses the font functions of its parent except for the functions
|
||||
that were explicitly set. The following code will override only the
|
||||
<function>hb_font_get_nominal_glyph_func_t</function> for the sub-font:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_t *subfont = hb_font_create_sub_font (font)
|
||||
hb_font_funcs_t *ffunctions = hb_font_funcs_create ();
|
||||
hb_font_funcs_set_nominal_glyph_func (ffunctions, func, user_data, destroy);
|
||||
hb_font_set_funcs (subfont, ffunctions, font_data, destroy);
|
||||
hb_font_funcs_destroy (ffunctions);
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="fonts-and-faces-native-opentype">
|
||||
<title>Font objects and HarfBuzz's native OpenType implementation</title>
|
||||
<para>
|
||||
By default, whenever HarfBuzz creates a font object, it will
|
||||
configure the font to use a built-in set of font functions that
|
||||
supports contemporary OpenType font internals. If you want to
|
||||
work with OpenType or TrueType fonts, you should be able to use
|
||||
these functions without difficulty.
|
||||
</para>
|
||||
<para>
|
||||
Many of the methods in the font-functions structure deal with
|
||||
the fundamental properties of glyphs that are required for
|
||||
shaping text: extents (the maximums and minimums on each axis),
|
||||
origins (the <literal>(0,0)</literal> coordinate point which
|
||||
glyphs are drawn in reference to), and advances (the amount that
|
||||
the cursor needs to be moved after drawing each glyph, including
|
||||
any empty space for the glyph's side bearings).
|
||||
</para>
|
||||
<para>
|
||||
As you can see in the list of functions, there are separate "horizontal"
|
||||
and "vertical" variants depending on whether the text is set in
|
||||
the horizontal or vertical direction. For some scripts, fonts
|
||||
that are designed to support text set horizontally or vertically (for
|
||||
example, in Japanese) may include metrics for both text
|
||||
directions. When fonts don't include this information, HarfBuzz
|
||||
does its best to transform what the font provides.
|
||||
</para>
|
||||
<para>
|
||||
In addition to the direction-specific functions, HarfBuzz
|
||||
provides some higher-level functions for fetching information
|
||||
like extents and advances for a glyph. If you call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_font_get_glyph_advance_for_direction(font, direction, extents);
|
||||
</programlisting>
|
||||
<para>
|
||||
then you can provide any <type>hb_direction_t</type> as the
|
||||
<parameter>direction</parameter> parameter, and HarfBuzz will
|
||||
use the correct function variant for the text direction. There
|
||||
are similar higher-level versions of the functions for fetching
|
||||
extents, origin coordinates, and contour-point
|
||||
coordinates. There are also addition and subtraction functions
|
||||
for moving points with respect to the origin.
|
||||
</para>
|
||||
<para>
|
||||
There are also methods for fetching the glyph ID that
|
||||
corresponds to a Unicode code point (possibly when followed by a
|
||||
variation-selector code point), fetching the glyph name from the
|
||||
font, and fetching the glyph ID that corresponds to a glyph name
|
||||
you already have.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides functions for converting between glyph
|
||||
names and string
|
||||
variables. <function>hb_font_glyph_to_string(font, glyph, s,
|
||||
size)</function> retrieves the name for the glyph ID
|
||||
<parameter>glyph</parameter> from the font object. It generates a
|
||||
generic name of the form <literal>gidDDD</literal> (where DDD is
|
||||
the glyph index) if there is no name for the glyph in the
|
||||
font. The <function>hb_font_glyph_from_string(font, s, len,
|
||||
glyph)</function> takes an input string <parameter>s</parameter>
|
||||
and looks for a glyph with that name in the font, returning its
|
||||
glyph ID in the <parameter>glyph</parameter>
|
||||
output parameter. It automatically parses
|
||||
<literal>gidDDD</literal> and <literal>uniUUUU</literal> strings.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Commenting out FreeType integration section-holder for now. May move
|
||||
to the full-blown Integration Chapter. -->
|
||||
|
||||
<!-- <section id="fonts-and-faces-freetype">
|
||||
<title>Using FreeType</title>
|
||||
<para>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
|
||||
</para>
|
||||
</section> -->
|
||||
|
||||
<section id="fonts-and-faces-variable">
|
||||
<title>Working with OpenType Variable Fonts</title>
|
||||
<para>
|
||||
If you are working with OpenType Variable Fonts, there are a few
|
||||
additional functions you should use to specify the
|
||||
variation-axis settings of your font object. Without doing so,
|
||||
your variable font's font object can still be used, but only at
|
||||
the default setting for every axis (which, of course, is
|
||||
sometimes what you want, but does not cover general usage).
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz manages variation settings in the
|
||||
<type>hb_variation_t</type> data type, which holds a <property>tag</property> for the
|
||||
variation-axis identifier tag and a <property>value</property> for its
|
||||
setting. You can retrieve the list of variation axes in a font
|
||||
binary from the face object (not from a font object, notably) by
|
||||
calling <function>hb_ot_var_get_axis_count(face)</function> to
|
||||
find the number of axes, then using
|
||||
<function>hb_ot_var_get_axis_infos()</function> to collect the
|
||||
axis structures:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
axes = hb_ot_var_get_axis_count(face);
|
||||
...
|
||||
hb_ot_var_get_axis_infos(face, 0, axes, axes_array);
|
||||
</programlisting>
|
||||
<para>
|
||||
For each axis returned in the array, you can can access the
|
||||
identifier in its <property>tag</property>. HarfBuzz also has
|
||||
tag definitions predefined for the five standard axes specified
|
||||
in OpenType (<literal>ital</literal> for italic,
|
||||
<literal>opsz</literal> for optical size,
|
||||
<literal>slnt</literal> for slant, <literal>wdth</literal> for
|
||||
width, and <literal>wght</literal> for weight). Each axis also
|
||||
has a <property>min_value</property>, a
|
||||
<property>default_value</property>, and a <property>max_value</property>.
|
||||
</para>
|
||||
<para>
|
||||
To set your font object's variation settings, you call the
|
||||
<function>hb_font_set_variations()</function> function with an
|
||||
array of <type>hb_variation_t</type> variation settings. Let's
|
||||
say our font has weight and width axes. We need to specify each
|
||||
of the axes by tag and assign a value on the axis:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
unsigned int variation_count = 2;
|
||||
hb_variation_t variation_data[variation_count];
|
||||
variation_data[0].tag = HB_OT_TAG_VAR_AXIS_WIDTH;
|
||||
variation_data[1].tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
|
||||
variation_data[0].value = 80;
|
||||
variation_data[1].value = 750;
|
||||
...
|
||||
hb_font_set_variations(font, variation_data, variation_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
That should give us a slightly condensed font ("normal" on the
|
||||
<literal>wdth</literal> axis is 100) at a noticeably bolder
|
||||
weight ("regular" is 400 on the <literal>wght</literal> axis).
|
||||
</para>
|
||||
<para>
|
||||
In practice, though, you should always check that the value you
|
||||
want to set on the axis is within the
|
||||
[<property>min_value</property>,<property>max_value</property>]
|
||||
range actually implemented in the font's variation axis. After
|
||||
all, a font might only provide lighter-than-regular weights, and
|
||||
setting a heavier value on the <literal>wght</literal> axis will
|
||||
not change that.
|
||||
</para>
|
||||
<para>
|
||||
Once your variation settings are specified on your font object,
|
||||
however, shaping with a variable font is just like shaping a
|
||||
static font.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -1,312 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="getting-started">
|
||||
<title>Getting started with HarfBuzz</title>
|
||||
<section id="an-overview-of-the-harfbuzz-shaping-api">
|
||||
<title>An overview of the HarfBuzz shaping API</title>
|
||||
<para>
|
||||
The core of the HarfBuzz shaping API is the function
|
||||
<function>hb_shape()</function>. This function takes a font, a
|
||||
buffer containing a string of Unicode codepoints and
|
||||
(optionally) a list of font features as its input. It replaces
|
||||
the codepoints in the buffer with the corresponding glyphs from
|
||||
the font, correctly ordered and positioned, and with any of the
|
||||
optional font features applied.
|
||||
</para>
|
||||
<para>
|
||||
In addition to holding the pre-shaping input (the Unicode
|
||||
codepoints that comprise the input string) and the post-shaping
|
||||
output (the glyphs and positions), a HarfBuzz buffer has several
|
||||
properties that affect shaping. The most important are the
|
||||
text-flow direction (e.g., left-to-right, right-to-left,
|
||||
top-to-bottom, or bottom-to-top), the script tag, and the
|
||||
language tag.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For input string buffers, flags are available to denote when the
|
||||
buffer represents the beginning or end of a paragraph, to
|
||||
indicate whether or not to visibly render Unicode <literal>Default
|
||||
Ignorable</literal> codepoints, and to modify the cluster-merging
|
||||
behavior for the buffer. For shaped output buffers, the
|
||||
individual X and Y offsets and <literal>advances</literal>
|
||||
(the logical dimensions) of each glyph are
|
||||
accessible. HarfBuzz also flags glyphs as
|
||||
<literal>UNSAFE_TO_BREAK</literal> if breaking the string at
|
||||
that glyph (e.g., in a line-breaking or hyphenation process)
|
||||
would require re-shaping the text.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz also provides methods to compare the contents of
|
||||
buffers, join buffers, normalize buffer contents, and handle
|
||||
invalid codepoints, as well as to determine the state of a
|
||||
buffer (e.g., input codepoints or output glyphs). Buffer
|
||||
lifecycles are managed and all buffers are reference-counted.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Although the default <function>hb_shape()</function> function is
|
||||
sufficient for most use cases, a variant is also provide that
|
||||
lets you specify which of HarfBuzz's shapers to use on a buffer.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz can read TrueType fonts, TrueType collections, OpenType
|
||||
fonts, and OpenType collections. Functions are provided to query
|
||||
font objects about metrics, Unicode coverage, available tables and
|
||||
features, and variation selectors. Individual glyphs can also be
|
||||
queried for metrics, variations, and glyph names. OpenType
|
||||
variable fonts are supported, and HarfBuzz allows you to set
|
||||
variation-axis coordinates on font objects.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz provides glue code to integrate with various other
|
||||
libraries, including FreeType, GObject, and CoreText. Support
|
||||
for integrating with Uniscribe and DirectWrite is experimental
|
||||
at present.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="terminology">
|
||||
<title>Terminology</title>
|
||||
<para>
|
||||
|
||||
</para>
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term>script</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In text shaping, a <emphasis>script</emphasis> is a
|
||||
writing system: a set of symbols, rules, and conventions
|
||||
that is used to represent a language or multiple
|
||||
languages.
|
||||
</para>
|
||||
<para>
|
||||
In general computing lingo, the word "script" can also
|
||||
be used to mean an executable program (usually one
|
||||
written in a human-readable programming language). For
|
||||
the sake of clarity, HarfBuzz documents will always use
|
||||
more specific terminology when referring to this
|
||||
meaning, such as "Python script" or "shell script." In
|
||||
all other instances, "script" refers to a writing system.
|
||||
</para>
|
||||
<para>
|
||||
For developers using HarfBuzz, it is important to note
|
||||
the distinction between a script and a language. Most
|
||||
scripts are used to write a variety of different
|
||||
languages, and many languages may be written in more
|
||||
than one script.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>shaper</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In HarfBuzz, a <emphasis>shaper</emphasis> is a
|
||||
handler for a specific script-shaping model. HarfBuzz
|
||||
implements separate shapers for Indic, Arabic, Thai and
|
||||
Lao, Khmer, Myanmar, Tibetan, Hangul, Hebrew, the
|
||||
Universal Shaping Engine (USE), and a default shaper for
|
||||
non-complex scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>cluster</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In text shaping, a <emphasis>cluster</emphasis> is a
|
||||
sequence of codepoints that must be treated as an
|
||||
indivisible unit. Clusters can include code-point
|
||||
sequences that form a ligature or base-and-mark
|
||||
sequences. Tracking and preserving clusters is important
|
||||
when shaping operations might separate or reorder
|
||||
code points.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides three cluster
|
||||
<emphasis>levels</emphasis> that implement different
|
||||
approaches to the problem of preserving clusters during
|
||||
shaping operations.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>grapheme</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In linguistics, a <emphasis>grapheme</emphasis> is one
|
||||
of the indivisible units that make up a writing system or
|
||||
script. Often, graphemes are individual symbols (letters,
|
||||
numbers, punctuation marks, logograms, etc.) but,
|
||||
depending on the writing system, a particular grapheme
|
||||
might correspond to a sequence of several Unicode code
|
||||
points.
|
||||
</para>
|
||||
<para>
|
||||
In practice, HarfBuzz and other text-shaping engines
|
||||
are not generally concerned with graphemes. However, it
|
||||
is important for developers using HarfBuzz to recognize
|
||||
that there is a difference between graphemes and shaping
|
||||
clusters (see above). The two concepts may overlap
|
||||
frequently, but there is no guarantee that they will be
|
||||
identical.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>syllable</term>
|
||||
<listitem>
|
||||
<para>
|
||||
In linguistics, a <emphasis>syllable</emphasis> is an
|
||||
a sequence of sounds that makes up a building block of a
|
||||
particular language. Every language has its own set of
|
||||
rules describing what constitutes a valid syllable.
|
||||
</para>
|
||||
<para>
|
||||
For text-shaping purposes, the various definitions of
|
||||
"syllable" are important because script-specific shaping
|
||||
operations may be applied at the syllable level. For
|
||||
example, a reordering rule might specify that a vowel
|
||||
mark be reordered to the beginning of the syllable.
|
||||
</para>
|
||||
<para>
|
||||
Syllables will consist of one or more Unicode code
|
||||
points. The definition of a syllable for a particular
|
||||
writing system might correspond to how HarfBuzz
|
||||
identifies clusters (see above) for the same writing
|
||||
system. However, it is important for developers using
|
||||
HarfBuzz to recognize that there is a difference between
|
||||
syllables and shaping clusters. The two concepts may
|
||||
overlap frequently, but there is no guarantee that they
|
||||
will be identical.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section id="a-simple-shaping-example">
|
||||
<title>A simple shaping example</title>
|
||||
|
||||
<para>
|
||||
Below is the simplest HarfBuzz shaping example possible.
|
||||
</para>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem>
|
||||
<para>
|
||||
Create a buffer and put your text in it.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
#include <hb.h>
|
||||
|
||||
hb_buffer_t *buf;
|
||||
buf = hb_buffer_create();
|
||||
hb_buffer_add_utf8(buf, text, -1, 0, -1);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="2">
|
||||
<para>
|
||||
Set the script, language and direction of the buffer.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_set_direction(buf, HB_DIRECTION_LTR);
|
||||
hb_buffer_set_script(buf, HB_SCRIPT_LATIN);
|
||||
hb_buffer_set_language(buf, hb_language_from_string("en", -1));
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="3">
|
||||
<para>
|
||||
Create a face and a font from a font file.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_blob_t *blob = hb_blob_create_from_file(filename);
|
||||
hb_face_t *face = hb_face_create(blob, 0);
|
||||
hb_font_t *font = hb_font_create(face);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="4">
|
||||
<para>
|
||||
Shape!
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting>
|
||||
hb_shape(font, buf, NULL, 0);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="5">
|
||||
<para>
|
||||
Get the glyph and position information.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
unsigned int glyph_count;
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="6">
|
||||
<para>
|
||||
Iterate over each glyph.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_position_t cursor_x = 0;
|
||||
hb_position_t cursor_y = 0;
|
||||
for (unsigned int i = 0; i < glyph_count; i++) {
|
||||
hb_codepoint_t glyphid = glyph_info[i].codepoint;
|
||||
hb_position_t x_offset = glyph_pos[i].x_offset;
|
||||
hb_position_t y_offset = glyph_pos[i].y_offset;
|
||||
hb_position_t x_advance = glyph_pos[i].x_advance;
|
||||
hb_position_t y_advance = glyph_pos[i].y_advance;
|
||||
/* draw_glyph(glyphid, cursor_x + x_offset, cursor_y + y_offset); */
|
||||
cursor_x += x_advance;
|
||||
cursor_y += y_advance;
|
||||
}
|
||||
</programlisting>
|
||||
<orderedlist numeration="arabic">
|
||||
<listitem override="7">
|
||||
<para>
|
||||
Tidy up.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<programlisting language="C">
|
||||
hb_buffer_destroy(buf);
|
||||
hb_font_destroy(font);
|
||||
hb_face_destroy(face);
|
||||
hb_blob_destroy(blob);
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
This example shows enough to get us started using HarfBuzz. In
|
||||
the sections that follow, we will use the remainder of
|
||||
HarfBuzz's API to refine and extend the example and improve its
|
||||
text-shaping capabilities.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<sect1 id="glyph-information">
|
||||
<title>Glyph information</title>
|
||||
<sect2 id="names-and-numbers">
|
||||
<title>Names and numbers</title>
|
||||
<para>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
@ -1,350 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="install-harfbuzz">
|
||||
<title>Installing HarfBuzz</title>
|
||||
|
||||
<section id="download">
|
||||
<title id="download.title">Downloading HarfBuzz</title>
|
||||
<para>
|
||||
The HarfBuzz source code is hosted at <ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz">github.com/harfbuzz/harfbuzz</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Tarball releases and Win32 binary bundles (which include the
|
||||
libharfbuzz DLL, hb-view.exe, hb-shape.exe, and all
|
||||
dependencies) of HarfBuzz can be downloaded from <ulink
|
||||
url="https://github.com/harfbuzz/harfbuzz/releases">github.com/harfbuzz/harfbuzz/releases</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Release notes are posted with each new release to provide an
|
||||
overview of the changes. The project <ulink url="https://github.com/harfbuzz/harfbuzz/issues">tracks bug
|
||||
reports and other issues</ulink> on GitHub. Discussion and
|
||||
questions are welcome on the <ulink
|
||||
url="http://freedesktop.org/mailman/listinfo/harfbuzz/">HarfBuzz
|
||||
mailing list</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
The API included in the <filename
|
||||
class='headerfile'>hb.h</filename> file will not change in a
|
||||
compatibility-breaking way in any release. However, other,
|
||||
peripheral headers are more likely to go through minor
|
||||
modifications. We will do our best to never change APIs in an
|
||||
incompatible way. We will <emphasis>never</emphasis> break the ABI.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="building">
|
||||
<title>Building HarfBuzz</title>
|
||||
|
||||
<section id="building.linux">
|
||||
<title>Building on Linux</title>
|
||||
<para>
|
||||
<emphasis>(1)</emphasis> To build HarfBuzz on Linux, you must first install the
|
||||
development packages for FreeType, Cairo, and GLib. The exact
|
||||
commands required for this step will vary depending on
|
||||
the Linux distribution you use.
|
||||
</para>
|
||||
<para>
|
||||
For example, on an Ubuntu or Debian system, you would run:
|
||||
<programlisting><command>sudo apt install</command> <package>gcc g++ libfreetype6-dev libglib2.0-dev libcairo2-dev</package></programlisting>
|
||||
On Fedora, RHEL, CentOS, or other Red-Hat–based systems, you would run:
|
||||
<programlisting><command>sudo yum install</command> <package>gcc gcc-c++ freetype-devel glib2-devel cairo-devel</package></programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>(2)</emphasis> The next step depends on whether you
|
||||
are building from the source in a downloaded release tarball or
|
||||
from the source directly from the git repository.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(a)</emphasis> If you downloaded the HarfBuzz
|
||||
source code in a tarball, you can now extract the source.
|
||||
</para>
|
||||
<para>
|
||||
From a shell in the top-level directory of the extracted source
|
||||
code, you can run <command>meson build</command> followed by
|
||||
<command>meson compile -C build</command> as with any other standard package.
|
||||
</para>
|
||||
<para>
|
||||
This should leave you with a shared
|
||||
library in the <filename>src/</filename> directory, and a few
|
||||
utility programs including <command>hb-view</command> and
|
||||
<command>hb-shape</command> under the <filename>util/</filename>
|
||||
directory.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(b)</emphasis> If you are building from the source in the HarfBuzz git
|
||||
repository, rather than installing from a downloaded tarball
|
||||
release, then you must install two more auxiliary tools before you
|
||||
can build for the first time: <package>pkg-config</package>.
|
||||
</para>
|
||||
<para>
|
||||
On Ubuntu or Debian, run:
|
||||
<programlisting><command>sudo apt-get install</command> <package>meson pkg-config gtk-doc-tools</package></programlisting>
|
||||
On Fedora, RHEL, CentOS, run:
|
||||
<programlisting><command>sudo yum install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
|
||||
|
||||
</para>
|
||||
<para>
|
||||
With <package>pkg-config</package> installed, you can now run
|
||||
<command>meson build</command> then
|
||||
<command>meson compile -C build</command> to build HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="building.windows">
|
||||
<title>Building on Windows</title>
|
||||
|
||||
<para>
|
||||
<ulink url="https://mesonbuild.com/Getting-meson.html">Install meson</ulink>
|
||||
and run (from the console) <command>meson build</command> (by default
|
||||
bundled dependencies are not built, <command>--wrap-mode=default</command>
|
||||
overrides this), then <command>meson compile -C build</command> to
|
||||
build HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="building.macos">
|
||||
<title>Building on macOS</title>
|
||||
|
||||
<para>
|
||||
There are two ways to build HarfBuzz on Mac systems: MacPorts
|
||||
and Homebrew. The process is similar to the process used on a
|
||||
Linux system.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(1)</emphasis> You must first install the
|
||||
development packages for FreeType, Cairo, and GLib. If you are
|
||||
using MacPorts, you should run:
|
||||
<programlisting><command>sudo port install</command> <package>freetype glib2 cairo</package></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
If you are using Homebrew, you should run:
|
||||
<programlisting><command>brew install</command> <package>freetype glib cairo</package></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)</emphasis> The next step depends on whether you are building from the
|
||||
source in a downloaded release tarball or from the source directly
|
||||
from the git repository.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(a)</emphasis> If you are installing HarfBuzz
|
||||
from a downloaded tarball release, extract the tarball and
|
||||
open a Terminal in the extracted source-code directory. Run:
|
||||
<programlisting><command>meson build</command></programlisting>
|
||||
followed by:
|
||||
<programlisting><command>meson compile -C build</command></programlisting>
|
||||
to build HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(2)(b)</emphasis> Alternatively, if you are building
|
||||
HarfBuzz from the source in the HarfBuzz git repository, then
|
||||
you must install several built-time dependencies before
|
||||
proceeding.
|
||||
</para>
|
||||
<para>If you are
|
||||
using MacPorts, you should run:
|
||||
<programlisting><command>sudo port install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
|
||||
to install the build dependencies.
|
||||
</para>
|
||||
<para>If you are using Homebrew, you should run:
|
||||
<programlisting><command>brew install</command> <package>meson pkgconfig gtk-doc</package></programlisting>
|
||||
Finally, you can run:
|
||||
<programlisting><command>meson build</command></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>(3)</emphasis> You can now build HarfBuzz (on either
|
||||
a MacPorts or a Homebrew system) by running:
|
||||
<programlisting><command>meson build</command></programlisting>
|
||||
followed by:
|
||||
<programlisting><command>meson compile -C build</command></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
This should leave you with a shared
|
||||
library in the <filename>src/</filename> directory, and a few
|
||||
utility programs including <command>hb-view</command> and
|
||||
<command>hb-shape</command> under the <filename>util/</filename>
|
||||
directory.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="configuration">
|
||||
<title>Configuration options</title>
|
||||
|
||||
<para>
|
||||
The instructions in the "Building HarfBuzz" section will build
|
||||
the source code under its default configuration. If needed,
|
||||
the following additional configuration options are available.
|
||||
</para>
|
||||
|
||||
<variablelist>
|
||||
<?dbfo list-presentation="blocks"?>
|
||||
<varlistentry>
|
||||
<term><command>-Dglib=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/glib/">GLib</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GLib
|
||||
library. The default setting is to check for the
|
||||
presence of GLib and, if it is found, build with
|
||||
GLib support. GLib is native to GNU/Linux systems but is
|
||||
available on other operating system as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dgobject=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://developer.gnome.org/gobject/stable/">GObject</ulink>. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the GObject
|
||||
library. The default setting is to check for the
|
||||
presence of GObject and, if it is found, build with
|
||||
GObject support. GObject is native to GNU/Linux systems but is
|
||||
available on other operating system as well.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dcairo=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://cairographics.org/">Cairo</ulink>. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Cairo
|
||||
graphics-rendering library. The default setting is to
|
||||
check for the presence of Cairo and, if it is found,
|
||||
build with Cairo support.
|
||||
</para>
|
||||
<para>
|
||||
Note: Cairo is used only by the HarfBuzz
|
||||
command-line utilities, and not by the HarfBuzz library.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dicu=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://site.icu-project.org/home">ICU</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the
|
||||
<emphasis>International Components for
|
||||
Unicode</emphasis> (ICU) library, which provides access
|
||||
to Unicode Character Database (UCD) properties as well
|
||||
as normalization and conversion functions. The default
|
||||
setting is to check for the presence of ICU and, if it
|
||||
is found, build with ICU support.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dgraphite=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="http://graphite.sil.org/">Graphite2</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Graphite2
|
||||
library, which provides support for the Graphite shaping
|
||||
model.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dfreetype=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://www.freetype.org/">FreeType</ulink> library. <emphasis>(Default = auto)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the FreeType
|
||||
font-rendering library. The default setting is to check for the
|
||||
presence of FreeType and, if it is found, build with
|
||||
FreeType support.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dgdi=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/intl/uniscribe">Uniscribe</ulink>
|
||||
library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the Uniscribe
|
||||
font-rendering library. Uniscribe is available on
|
||||
Windows systems. Uniscribe support is used only for
|
||||
testing purposes and does not need to be enabled for
|
||||
HarfBuzz to run on Windows systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Ddirectwrite=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://docs.microsoft.com/en-us/windows/desktop/directwrite/direct-write-portal">DirectWrite</ulink> library (experimental). <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the DirectWrite
|
||||
font-rendering library. DirectWrite is available on
|
||||
Windows systems. DirectWrite support is used only for
|
||||
testing purposes and does not need to be enabled for
|
||||
HarfBuzz to run on Windows systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Dcoretext=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the <ulink url="https://developer.apple.com/documentation/coretext">CoreText</ulink> library. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables or disables usage of the CoreText
|
||||
library. CoreText is available on macOS and iOS systems.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>-Ddocs=enabled</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use <ulink url="https://www.gtk.org/gtk-doc/">GTK-Doc</ulink>. <emphasis>(Default = no)</emphasis>
|
||||
</para>
|
||||
<para>
|
||||
This option enables the building of the documentation.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
</chapter>
|
@ -1,603 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="integration">
|
||||
<title>Platform Integration Guide</title>
|
||||
<para>
|
||||
HarfBuzz was first developed for use with the GNOME and GTK
|
||||
software stack commonly found in desktop Linux
|
||||
distributions. Nevertheless, it can be used on other operating
|
||||
systems and platforms, from iOS and macOS to Windows. It can also
|
||||
be used with other application frameworks and components, such as
|
||||
Android, Qt, or application-specific widget libraries.
|
||||
</para>
|
||||
<para>
|
||||
This chapter will look at how HarfBuzz fits into a typical
|
||||
text-rendering pipeline, and will discuss the APIs available to
|
||||
integrate HarfBuzz with contemporary Linux, Mac, and Windows
|
||||
software. It will also show how HarfBuzz integrates with popular
|
||||
external libraries like FreeType and International Components for
|
||||
Unicode (ICU) and describe the HarfBuzz language bindings for
|
||||
Python.
|
||||
</para>
|
||||
<para>
|
||||
On a GNOME system, HarfBuzz is designed to tie in with several
|
||||
other common system libraries. The most common architecture uses
|
||||
Pango at the layer directly "above" HarfBuzz; Pango is responsible
|
||||
for text segmentation and for ensuring that each input
|
||||
<type>hb_buffer_t</type> passed to HarfBuzz for shaping contains
|
||||
Unicode code points that share the same segment properties
|
||||
(namely, direction, language, and script, but also higher-level
|
||||
properties like the active font, font style, and so on).
|
||||
</para>
|
||||
<para>
|
||||
The layer directly "below" HarfBuzz is typically FreeType, which
|
||||
is used to rasterize glyph outlines at the necessary optical size,
|
||||
hinting settings, and pixel resolution. FreeType provides APIs for
|
||||
accessing font and face information, so HarfBuzz includes
|
||||
functions to create <type>hb_face_t</type> and
|
||||
<type>hb_font_t</type> objects directly from FreeType
|
||||
objects. HarfBuzz can use FreeType's built-in functions for
|
||||
<structfield>font_funcs</structfield> vtable in an <type>hb_font_t</type>.
|
||||
</para>
|
||||
<para>
|
||||
FreeType's output is bitmaps of the rasterized glyphs; on a
|
||||
typical Linux system these will then be drawn by a graphics
|
||||
library like Cairo, but those details are beyond HarfBuzz's
|
||||
control. On the other hand, at the top end of the stack, Pango is
|
||||
part of the larger GNOME framework, and HarfBuzz does include APIs
|
||||
for working with key components of GNOME's higher-level libraries
|
||||
— most notably GLib.
|
||||
</para>
|
||||
<para>
|
||||
For other operating systems or application frameworks, the
|
||||
critical integration points are where HarfBuzz gets font and face
|
||||
information about the font used for shaping and where HarfBuzz
|
||||
gets Unicode data about the input-buffer code points.
|
||||
</para>
|
||||
<para>
|
||||
The font and face information is necessary for text shaping
|
||||
because HarfBuzz needs to retrieve the glyph indices for
|
||||
particular code points, and to know the extents and advances of
|
||||
glyphs. Note that, in an OpenType variable font, both of those
|
||||
types of information can change with different variation-axis
|
||||
settings.
|
||||
</para>
|
||||
<para>
|
||||
The Unicode information is necessary for shaping because the
|
||||
properties of a code point (such as its General Category (gc),
|
||||
Canonical Combining Class (ccc), and decomposition) can directly
|
||||
impact the shaping moves that HarfBuzz performs.
|
||||
</para>
|
||||
|
||||
<section id="integration-glib">
|
||||
<title>GNOME integration, GLib, and GObject</title>
|
||||
<para>
|
||||
As mentioned in the preceding section, HarfBuzz offers
|
||||
integration APIs to help client programs using the
|
||||
GNOME and GTK framework commonly found in desktop Linux
|
||||
distributions.
|
||||
</para>
|
||||
<para>
|
||||
GLib is the main utility library for GNOME applications. It
|
||||
provides basic data types and conversions, file abstractions,
|
||||
string manipulation, and macros, as well as facilities like
|
||||
memory allocation and the main event loop.
|
||||
</para>
|
||||
<para>
|
||||
Where text shaping is concerned, GLib provides several utilities
|
||||
that HarfBuzz can take advantage of, including a set of
|
||||
Unicode-data functions and a data type for script
|
||||
information. Both are useful when working with HarfBuzz
|
||||
buffers. To make use of them, you will need to include the
|
||||
<filename>hb-glib.h</filename> header file.
|
||||
</para>
|
||||
<para>
|
||||
GLib's <ulink
|
||||
url="https://developer.gnome.org/glib/stable/glib-Unicode-Manipulation.html">Unicode
|
||||
manipulation API</ulink> includes all the functionality
|
||||
necessary to retrieve Unicode data for the
|
||||
<structfield>unicode_funcs</structfield> structure of a HarfBuzz
|
||||
<type>hb_buffer_t</type>.
|
||||
</para>
|
||||
<para>
|
||||
The function <function>hb_glib_get_unicode_funcs()</function>
|
||||
sets up a <type>hb_unicode_funcs_t</type> structure configured
|
||||
with the GLib Unicode functions and returns a pointer to it.
|
||||
</para>
|
||||
<para>
|
||||
You can attach this Unicode-functions structure to your buffer,
|
||||
and it will be ready for use with GLib:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
#include <hb-glib.h>
|
||||
...
|
||||
hb_unicode_funcs_t *glibufunctions;
|
||||
glibufunctions = hb_glib_get_unicode_funcs();
|
||||
hb_buffer_set_unicode_funcs(buf, glibufunctions);
|
||||
</programlisting>
|
||||
<para>
|
||||
For script information, GLib uses the
|
||||
<type>GUnicodeScript</type> type. Like HarfBuzz's own
|
||||
<type>hb_script_t</type>, this data type is an enumeration
|
||||
of Unicode scripts, but text segments passed in from GLib code
|
||||
will be tagged with a <type>GUnicodeScript</type>. Therefore,
|
||||
when setting the script property on a <type>hb_buffer_t</type>,
|
||||
you will need to convert between the <type>GUnicodeScript</type>
|
||||
of the input provided by GLib and HarfBuzz's
|
||||
<type>hb_script_t</type> type.
|
||||
</para>
|
||||
<para>
|
||||
The <function>hb_glib_script_to_script()</function> function
|
||||
takes an <type>GUnicodeScript</type> script identifier as its
|
||||
sole argument and returns the corresponding <type>hb_script_t</type>.
|
||||
The <function>hb_glib_script_from_script()</function> does the
|
||||
reverse, taking an <type>hb_script_t</type> and returning the
|
||||
<type>GUnicodeScript</type> identifier for GLib.
|
||||
</para>
|
||||
<para>
|
||||
Finally, GLib also provides a reference-counted object type called <ulink
|
||||
url="https://developer.gnome.org/glib/stable/glib-Byte-Arrays.html#GBytes"><type>GBytes</type></ulink>
|
||||
that is used for accessing raw memory segments with the benefits
|
||||
of GLib's lifecycle management. HarfBuzz provides a
|
||||
<function>hb_glib_blob_create()</function> function that lets
|
||||
you create an <type>hb_blob_t</type> directly from a
|
||||
<type>GBytes</type> object. This function takes only the
|
||||
<type>GBytes</type> object as its input; HarfBuzz registers the
|
||||
GLib <function>destroy</function> callback automatically.
|
||||
</para>
|
||||
<para>
|
||||
The GNOME platform also features an object system called
|
||||
GObject. For HarfBuzz, the main advantage of GObject is a
|
||||
feature called <ulink
|
||||
url="https://gi.readthedocs.io/en/latest/">GObject
|
||||
Introspection</ulink>. This is a middleware facility that can be
|
||||
used to generate language bindings for C libraries. HarfBuzz uses it
|
||||
to build its Python bindings, which we will look at in a separate section.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="integration-freetype">
|
||||
<title>FreeType integration</title>
|
||||
<para>
|
||||
FreeType is the free-software font-rendering engine included in
|
||||
desktop Linux distributions, Android, ChromeOS, iOS, and multiple Unix
|
||||
operating systems, and used by cross-platform programs like
|
||||
Chrome, Java, and GhostScript. Used together, HarfBuzz can
|
||||
perform shaping on Unicode text segments, outputting the glyph
|
||||
IDs that FreeType should rasterize from the active font as well
|
||||
as the positions at which those glyphs should be drawn.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz provides integration points with FreeType at the
|
||||
face-object and font-object level and for the font-functions
|
||||
virtual-method structure of a font object. To use the
|
||||
FreeType-integration API, include the
|
||||
<filename>hb-ft.h</filename> header.
|
||||
</para>
|
||||
<para>
|
||||
In a typical client program, you will create your
|
||||
<type>hb_face_t</type> face object and <type>hb_font_t</type>
|
||||
font object from a FreeType <type>FT_Face</type>. HarfBuzz
|
||||
provides a suite of functions for doing this.
|
||||
</para>
|
||||
<para>
|
||||
In the most common case, you will want to use
|
||||
<function>hb_ft_font_create_referenced()</function>, which
|
||||
creates both an <type>hb_face_t</type> face object and
|
||||
<type>hb_font_t</type> font object (linked to that face object),
|
||||
and provides lifecycle management.
|
||||
</para>
|
||||
<para>
|
||||
It is important to note,
|
||||
though, that while HarfBuzz makes a distinction between its face and
|
||||
font objects, FreeType's <type>FT_Face</type> does not. After
|
||||
you create your <type>FT_Face</type>, you must set its size
|
||||
parameter using <function>FT_Set_Char_Size()</function>, because
|
||||
an <type>hb_font_t</type> is defined as an instance of an
|
||||
<type>hb_face_t</type> with size specified.
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
#include <hb-ft.h>
|
||||
...
|
||||
FT_New_Face(ft_library, font_path, index, &face);
|
||||
FT_Set_Char_Size(face, 0, 1000, 0, 0);
|
||||
hb_font_t *font = hb_ft_font_create(face);
|
||||
</programlisting>
|
||||
<para>
|
||||
<function>hb_ft_font_create_referenced()</function> is
|
||||
the recommended function for creating an <type>hb_face_t</type> face
|
||||
object. This function calls <function>FT_Reference_Face()</function>
|
||||
before using the <type>FT_Face</type> and calls
|
||||
<function>FT_Done_Face()</function> when it is finished using the
|
||||
<type>FT_Face</type>. Consequently, your client program does not need
|
||||
to worry about destroying the <type>FT_Face</type> while HarfBuzz
|
||||
is still using it.
|
||||
</para>
|
||||
<para>
|
||||
Although <function>hb_ft_font_create_referenced()</function> is
|
||||
the recommended function, there is another variant for client code
|
||||
where special circumstances make it necessary. The simpler
|
||||
version of the function is <function>hb_ft_font_create()</function>,
|
||||
which takes an <type>FT_Face</type> and an optional destroy callback
|
||||
as its arguments. Because <function>hb_ft_font_create()</function>
|
||||
does not offer lifecycle management, however, your client code will
|
||||
be responsible for tracking references to the <type>FT_Face</type>
|
||||
objects and destroying them when they are no longer needed. If you
|
||||
do not have a valid reason for doing this, use
|
||||
<function>hb_ft_font_create_referenced()</function>.
|
||||
</para>
|
||||
<para>
|
||||
After you have created your font object from your
|
||||
<type>FT_Face</type>, you can set or retrieve the
|
||||
<structfield>load_flags</structfield> of the
|
||||
<type>FT_Face</type> through the <type>hb_font_t</type>
|
||||
object. HarfBuzz provides
|
||||
<function>hb_ft_font_set_load_flags()</function> and
|
||||
<function>hb_ft_font_get_load_flags()</function> for this
|
||||
purpose. The ability to set the
|
||||
<structfield>load_flags</structfield> through the font object
|
||||
could be useful for enabling or disabling hinting, for example,
|
||||
or to activate vertical layout.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides a utility function called
|
||||
<function>hb_ft_font_has_changed()</function> that you should
|
||||
call whenever you have altered the properties of your underlying
|
||||
<type>FT_Face</type>, as well as a
|
||||
<function>hb_ft_get_face()</function> that you can call on an
|
||||
<type>hb_font_t</type> font object to fetch its underlying <type>FT_Face</type>.
|
||||
</para>
|
||||
<para>
|
||||
With an <type>hb_face_t</type> and <type>hb_font_t</type> both linked
|
||||
to your <type>FT_Face</type>, you will typically also want to
|
||||
use FreeType for the <structfield>font_funcs</structfield>
|
||||
vtable of your <type>hb_font_t</type>. As a reminder, this
|
||||
font-functions structure is the set of methods that HarfBuzz
|
||||
will use to fetch important information from the font, such as
|
||||
the advances and extents of individual glyphs.
|
||||
</para>
|
||||
<para>
|
||||
All you need to do is call
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_ft_font_set_funcs(font);
|
||||
</programlisting>
|
||||
<para>
|
||||
and HarfBuzz will use FreeType for the font-functions in
|
||||
<literal>font</literal>.
|
||||
</para>
|
||||
<para>
|
||||
As we noted above, an <type>hb_font_t</type> is derived from an
|
||||
<type>hb_face_t</type> with size (and, perhaps, other
|
||||
parameters, such as variation-axis coordinates)
|
||||
specified. Consequently, you can reuse an <type>hb_face_t</type>
|
||||
with several <type>hb_font_t</type> objects, and HarfBuzz
|
||||
provides functions to simplify this.
|
||||
</para>
|
||||
<para>
|
||||
The <function>hb_ft_face_create_referenced()</function>
|
||||
function creates just an <type>hb_face_t</type> from a FreeType
|
||||
<type>FT_Face</type> and, as with
|
||||
<function>hb_ft_font_create_referenced()</function> above,
|
||||
provides lifecycle management for the <type>FT_Face</type>.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, there is an <function>hb_ft_face_create()</function>
|
||||
function variant that does not provide the lifecycle-management
|
||||
feature. As with the font-object case, if you use this version
|
||||
of the function, it will be your client code's respsonsibility
|
||||
to track usage of the <type>FT_Face</type> objects.
|
||||
</para>
|
||||
<para>
|
||||
A third variant of this function is
|
||||
<function>hb_ft_face_create_cached()</function>, which is the
|
||||
same as <function>hb_ft_face_create()</function> except that it
|
||||
also uses the <structfield>generic</structfield> field of the
|
||||
<type>FT_Face</type> structure to save a pointer to the newly
|
||||
created <type>hb_face_t</type>. Subsequently, function calls
|
||||
that pass the same <type>FT_Face</type> will get the same
|
||||
<type>hb_face_t</type> returned — and the
|
||||
<type>hb_face_t</type> will be correctly reference
|
||||
counted. Still, as with
|
||||
<function>hb_ft_face_create()</function>, your client code must
|
||||
track references to the <type>FT_Face</type> itself, and destroy
|
||||
it when it is unneeded.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="integration-uniscribe">
|
||||
<title>Uniscribe integration</title>
|
||||
<para>
|
||||
If your client program is running on Windows, HarfBuzz offers
|
||||
an additional API that can help integrate with Microsoft's
|
||||
Uniscribe engine and the Windows GDI.
|
||||
</para>
|
||||
<para>
|
||||
Overall, the Uniscribe API covers a broader set of typographic
|
||||
layout functions than HarfBuzz implements, but HarfBuzz's
|
||||
shaping API can serve as a drop-in replacement for Uniscribe's shaping
|
||||
functionality. In fact, one of HarfBuzz's design goals is to
|
||||
accurately reproduce the same output for shaping a given text
|
||||
segment that Uniscribe produces — even to the point of
|
||||
duplicating known shaping bugs or deviations from the
|
||||
specification — so you can be confident that your users'
|
||||
documents with their existing fonts will not be affected adversely by
|
||||
switching to HarfBuzz.
|
||||
</para>
|
||||
<para>
|
||||
At a basic level, HarfBuzz's <function>hb_shape()</function>
|
||||
function replaces both the <ulink url=""><function>ScriptShape()</function></ulink>
|
||||
and <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/api/Usp10/nf-usp10-scriptplace"><function>ScriptPlace()</function></ulink>
|
||||
functions from Uniscribe.
|
||||
</para>
|
||||
<para>
|
||||
However, whereas <function>ScriptShape()</function> returns the
|
||||
glyphs and clusters for a shaped sequence and
|
||||
<function>ScriptPlace()</function> returns the advances and
|
||||
offsets for those glyphs, <function>hb_shape()</function>
|
||||
handles both. After <function>hb_shape()</function> shapes a
|
||||
buffer, the output glyph IDs and cluster IDs are returned as
|
||||
an array of <structname>hb_glyph_info_t</structname> structures, and the
|
||||
glyph advances and offsets are returned as an array of
|
||||
<structname>hb_glyph_position_t</structname> structures.
|
||||
</para>
|
||||
<para>
|
||||
Your client program only needs to ensure that it coverts
|
||||
correctly between HarfBuzz's low-level data types (such as
|
||||
<type>hb_position_t</type>) and Windows's corresponding types
|
||||
(such as <type>GOFFSET</type> and <type>ABC</type>). Be sure you
|
||||
read the <xref linkend="buffers-language-script-and-direction"
|
||||
/>
|
||||
chapter for a full explanation of how HarfBuzz input buffers are
|
||||
used, and see <xref linkend="shaping-buffer-output" /> for the
|
||||
details of what <function>hb_shape()</function> returns in the
|
||||
output buffer when shaping is complete.
|
||||
</para>
|
||||
<para>
|
||||
Although <function>hb_shape()</function> itself is functionally
|
||||
equivalent to Uniscribe's shaping routines, there are two
|
||||
additional HarfBuzz functions you may want to use to integrate
|
||||
the libraries in your code. Both are used to link HarfBuzz font
|
||||
objects to the equivalent Windows structures.
|
||||
</para>
|
||||
<para>
|
||||
The <function>hb_uniscribe_font_get_logfontw()</function>
|
||||
function takes a <type>hb_font_t</type> font object and returns
|
||||
a pointer to the <ulink
|
||||
url="https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-logfontw"><type>LOGFONTW</type></ulink>
|
||||
"logical font" that corresponds to it. A <type>LOGFONTW</type>
|
||||
structure holds font-wide attributes, including metrics, size,
|
||||
and style information.
|
||||
</para>
|
||||
<!--
|
||||
<para>
|
||||
In Uniscribe's model, the <type>SCRIPT_CACHE</type> holds the
|
||||
device context, including the logical font that the shaping
|
||||
functions apply.
|
||||
https://docs.microsoft.com/en-us/windows/desktop/Intl/script-cache
|
||||
</para>
|
||||
-->
|
||||
<para>
|
||||
The <function>hb_uniscribe_font_get_hfont()</function> function
|
||||
also takes a <type>hb_font_t</type> font object, but it returns
|
||||
an <type>HFONT</type> — a handle to the underlying logical
|
||||
font — instead.
|
||||
</para>
|
||||
<para>
|
||||
<type>LOGFONTW</type>s and <type>HFONT</type>s are both needed
|
||||
by other Uniscribe functions.
|
||||
</para>
|
||||
<para>
|
||||
As a final note, you may notice a reference to an optional
|
||||
<literal>uniscribe</literal> shaper back-end in the <xref
|
||||
linkend="configuration" /> section of the HarfBuzz manual. This
|
||||
option is not a Uniscribe-integration facility.
|
||||
</para>
|
||||
<para>
|
||||
Instead, it is a internal code path used in the
|
||||
<command>hb-shape</command> command-line utility, which hands
|
||||
shaping functionality over to Uniscribe entirely, when run on a
|
||||
Windows system. That allows testing HarfBuzz's native output
|
||||
against the Uniscribe engine, for tracking compatibility and
|
||||
debugging.
|
||||
</para>
|
||||
<para>
|
||||
Because this back-end is only used when testing HarfBuzz
|
||||
functionality, it is disabled by default when building the
|
||||
HarfBuzz binaries.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="integration-coretext">
|
||||
<title>Core Text integration</title>
|
||||
<para>
|
||||
If your client program is running on macOS or iOS, HarfBuzz offers
|
||||
an additional API that can help integrate with Apple's
|
||||
Core Text engine and the underlying Core Graphics
|
||||
framework. HarfBuzz does not attempt to offer the same
|
||||
drop-in-replacement functionality for Core Text that it strives
|
||||
for with Uniscribe on Windows, but you can still use HarfBuzz
|
||||
to perform text shaping in native macOS and iOS applications.
|
||||
</para>
|
||||
<para>
|
||||
Note, though, that if your interest is just in using fonts that
|
||||
contain Apple Advanced Typography (AAT) features, then you do
|
||||
not need to add Core Text integration. HarfBuzz natively
|
||||
supports AAT features and will shape AAT fonts (on any platform)
|
||||
automatically, without requiring additional work on your
|
||||
part. This includes support for AAT-specific TrueType tables
|
||||
such as <literal>mort</literal>, <literal>morx</literal>, and
|
||||
<literal>kerx</literal>, which AAT fonts use instead of
|
||||
<literal>GSUB</literal> and <literal>GPOS</literal>.
|
||||
</para>
|
||||
<para>
|
||||
On a macOS or iOS system, the primary integration points offered
|
||||
by HarfBuzz are for face objects and font objects.
|
||||
</para>
|
||||
<para>
|
||||
The Apple APIs offer a pair of data structures that map well to
|
||||
HarfBuzz's face and font objects. The Core Graphics API, which
|
||||
is slightly lower-level than Core Text, provides
|
||||
<ulink url="https://developer.apple.com/documentation/coregraphics/cgfontref"><type>CGFontRef</type></ulink>, which enables access to typeface
|
||||
properties, but does not include size information. Core Text's
|
||||
<ulink url="https://developer.apple.com/documentation/coretext/ctfont-q6r"><type>CTFontRef</type></ulink> is analagous to a HarfBuzz font object,
|
||||
with all of the properties required to render text at a specific
|
||||
size and configuration.
|
||||
Consequently, a HarfBuzz <type>hb_font_t</type> font object can
|
||||
be hooked up to a Core Text <type>CTFontRef</type>, and a HarfBuzz
|
||||
<type>hb_face_t</type> face object can be hooked up to a
|
||||
<type>CGFontRef</type>.
|
||||
</para>
|
||||
<para>
|
||||
You can create a <type>hb_face_t</type> from a
|
||||
<type>CGFontRef</type> by using the
|
||||
<function>hb_coretext_face_create()</function>. Subsequently,
|
||||
you can retrieve the <type>CGFontRef</type> from a
|
||||
<type>hb_face_t</type> with <function>hb_coretext_face_get_cg_font()</function>.
|
||||
</para>
|
||||
<para>
|
||||
Likewise, you create a <type>hb_font_t</type> from a
|
||||
<type>CTFontRef</type> by calling
|
||||
<function>hb_coretext_font_create()</function>, and you can
|
||||
fetch the associated <type>CTFontRef</type> from a
|
||||
<type>hb_font_t</type> font object with
|
||||
<function>hb_coretext_face_get_ct_font()</function>.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also offers a <function>hb_font_set_ptem()</function>
|
||||
that you an use to set the nominal point size on any
|
||||
<type>hb_font_t</type> font object. Core Text uses this value to
|
||||
implement optical scaling.
|
||||
</para>
|
||||
<para>
|
||||
When integrating your client code with Core Text, it is
|
||||
important to recognize that Core Text <literal>points</literal>
|
||||
are not typographic points (standardized at 72 per inch) as the
|
||||
term is used elsewhere in OpenType. Instead, Core Text points
|
||||
are CSS points, which are standardized at 96 per inch.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz's font functions take this distinction into account,
|
||||
but it can be an easy detail to miss in cross-platform
|
||||
code.
|
||||
</para>
|
||||
<para>
|
||||
As a final note, you may notice a reference to an optional
|
||||
<literal>coretext</literal> shaper back-end in the <xref
|
||||
linkend="configuration" /> section of the HarfBuzz manual. This
|
||||
option is not a Core Text-integration facility.
|
||||
</para>
|
||||
<para>
|
||||
Instead, it is a internal code path used in the
|
||||
<command>hb-shape</command> command-line utility, which hands
|
||||
shaping functionality over to Core Text entirely, when run on a
|
||||
macOS system. That allows testing HarfBuzz's native output
|
||||
against the Core Text engine, for tracking compatibility and debugging.
|
||||
</para>
|
||||
<para>
|
||||
Because this back-end is only used when testing HarfBuzz
|
||||
functionality, it is disabled by default when building the
|
||||
HarfBuzz binaries.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="integration-icu">
|
||||
<title>ICU integration</title>
|
||||
<para>
|
||||
Although HarfBuzz includes its own Unicode-data functions, it
|
||||
also provides integration APIs for using the International
|
||||
Components for Unicode (ICU) library as a source of Unicode data
|
||||
on any supported platform.
|
||||
</para>
|
||||
<para>
|
||||
The principal integration point with ICU is the
|
||||
<type>hb_unicode_funcs_t</type> Unicode-functions structure
|
||||
attached to a buffer. This structure holds the virtual methods
|
||||
used for retrieving Unicode character properties, such as
|
||||
General Category, Script, Combining Class, decomposition
|
||||
mappings, and mirroring information.
|
||||
</para>
|
||||
<para>
|
||||
To use ICU in your client program, you need to call
|
||||
<function>hb_icu_get_unicode_funcs()</function>, which creates a
|
||||
Unicode-functions structure populated with the ICU function for
|
||||
each included method. Subsequently, you can attach the
|
||||
Unicode-functions structure to your buffer:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_unicode_funcs_t *icufunctions;
|
||||
icufunctions = hb_icu_get_unicode_funcs();
|
||||
hb_buffer_set_unicode_funcs(buf, icufunctions);
|
||||
</programlisting>
|
||||
<para>
|
||||
and ICU will be used for Unicode-data access.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also supplies a pair of functions
|
||||
(<function>hb_icu_script_from_script()</function> and
|
||||
<function>hb_icu_script_to_script()</function>) for converting
|
||||
between ICU's and HarfBuzz's internal enumerations of Unicode
|
||||
scripts. The <function>hb_icu_script_from_script()</function>
|
||||
function converts from a HarfBuzz <type>hb_script_t</type> to an
|
||||
ICU <type>UScriptCode</type>. The
|
||||
<function>hb_icu_script_to_script()</function> function does the
|
||||
reverse: converting from a <type>UScriptCode</type> identifier
|
||||
to a <type>hb_script_t</type>.
|
||||
</para>
|
||||
<para>
|
||||
By default, HarfBuzz's ICU support is built as a separate shared
|
||||
library (<filename class="libraryfile">libharfbuzz-icu.so</filename>)
|
||||
when compiling HarfBuzz from source. This allows client programs
|
||||
that do not need ICU to link against HarfBuzz without unnecessarily
|
||||
adding ICU as a dependency. You can also build HarfBuzz with ICU
|
||||
support built directly into the main HarfBuzz shared library
|
||||
(<filename class="libraryfile">libharfbuzz.so</filename>),
|
||||
by specifying the <literal>--with-icu=builtin</literal>
|
||||
compile-time option.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="integration-python">
|
||||
<title>Python bindings</title>
|
||||
<para>
|
||||
As noted in the <xref linkend="integration-glib" /> section,
|
||||
HarfBuzz uses a feature called <ulink
|
||||
url="https://wiki.gnome.org/Projects/GObjectIntrospection">GObject
|
||||
Introspection</ulink> (GI) to provide bindings for Python.
|
||||
</para>
|
||||
<para>
|
||||
At compile time, the GI scanner analyzes the HarfBuzz C source
|
||||
and builds metadata objects connecting the language bindings to
|
||||
the C library. Your Python code can then use the HarfBuzz binary
|
||||
through its Python interface.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz's Python bindings support Python 2 and Python 3. To use
|
||||
them, you will need to have the <literal>pygobject</literal>
|
||||
package installed. Then you should import
|
||||
<literal>HarfBuzz</literal> from
|
||||
<literal>gi.repository</literal>:
|
||||
</para>
|
||||
<programlisting language="Python">
|
||||
from gi.repository import HarfBuzz
|
||||
</programlisting>
|
||||
<para>
|
||||
and you can call HarfBuzz functions from Python. Sample code can
|
||||
be found in the <filename>sample.py</filename> script in the
|
||||
HarfBuzz <filename>src</filename> directory.
|
||||
</para>
|
||||
<para>
|
||||
Do note, however, that the Python API is subject to change
|
||||
without advance notice. GI allows the bindings to be
|
||||
automatically updated, which is one of its advantages, but you
|
||||
may need to update your Python code.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -1,258 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="object-model">
|
||||
<title>The HarfBuzz object model</title>
|
||||
<section id="object-model-intro">
|
||||
<title>An overview of data types in HarfBuzz</title>
|
||||
<para>
|
||||
HarfBuzz features two kinds of data types: non-opaque,
|
||||
pass-by-value types and opaque, heap-allocated types. This kind
|
||||
of separation is common in C libraries that have to provide
|
||||
API/ABI compatibility (almost) indefinitely.
|
||||
</para>
|
||||
<para>
|
||||
<emphasis>Value types:</emphasis> The non-opaque, pass-by-value
|
||||
types include integer types, enums, and small structs. Exposing
|
||||
a struct in the public API makes it impossible to expand the
|
||||
struct in the future. As such, exposing structs is reserved for
|
||||
cases where it’s extremely inefficient to do otherwise.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
|
||||
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
|
||||
category and are non-opaque.
|
||||
</para>
|
||||
<para>
|
||||
For all non-opaque structs where future extensibility may be
|
||||
necessary, reserved members are included to hold space for
|
||||
possible future members. As such, it’s important to provide
|
||||
<function>equal()</function>, and <function>hash()</function>
|
||||
methods for such structs, allowing users of the API do
|
||||
effectively deal with the type without having to
|
||||
adapt their code to future changes.
|
||||
</para>
|
||||
<para>
|
||||
Important value types provided by HarfBuzz include the structs
|
||||
for working with Unicode code points, glyphs, and tags for font
|
||||
tables and features, as well as the enums for many Unicode and
|
||||
OpenType properties.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="object-model-object-types">
|
||||
<title>Objects in HarfBuzz</title>
|
||||
<para>
|
||||
<emphasis>Object types:</emphasis> Opaque struct types are used
|
||||
for what HarfBuzz loosely calls "objects." This doesn’t have
|
||||
much to do with the terminology from object-oriented programming
|
||||
(OOP), although some of the concepts are similar.
|
||||
</para>
|
||||
<para>
|
||||
In HarfBuzz, all object types provide certain
|
||||
lifecycle-management APIs. Objects are reference-counted, and
|
||||
constructed with various <function>create()</function> methods, referenced via
|
||||
<function>reference()</function> and dereferenced using
|
||||
<function>destroy()</function>.
|
||||
</para>
|
||||
<para>
|
||||
For example,
|
||||
the <literal>hb_buffer_t</literal> object has
|
||||
<function>hb_buffer_create()</function> as its constructor,
|
||||
<function>hb_buffer_reference()</function> to reference, and
|
||||
<function>hb_buffer_destroy()</function> to dereference.
|
||||
</para>
|
||||
<para>
|
||||
After construction, each object's properties are accessible only
|
||||
through the setter and getter functions described in the API
|
||||
Reference manual.
|
||||
</para>
|
||||
<para>
|
||||
Key object types provided by HarfBuzz include:
|
||||
</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
|
||||
data. Blobs are typically used to hold the contents of a
|
||||
binary font file.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>faces</emphasis>, which represent typefaces from a
|
||||
font file, but without specific parameters (such as size) set.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>fonts</emphasis>, which represent instances of a
|
||||
face with all of their parameters specified.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>buffers</emphasis>, which hold Unicode code points
|
||||
for characters (before shaping) and the shaped glyph output
|
||||
(after shaping).
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis>shape plans</emphasis>, which store the settings
|
||||
that HarfBuzz will use when shaping a particular text
|
||||
segment. Shape plans are not generally used by client
|
||||
programs directly, but as we will see in a later chapter,
|
||||
they are still valuable to understand.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-lifecycle">
|
||||
<title>Object lifecycle management</title>
|
||||
<para>
|
||||
Each object type in HarfBuzz provides a
|
||||
<function>create()</function> method. Some object types provide
|
||||
additional variants of <function>create()</function> to handle
|
||||
special cases or to speed up common tasks; those variants are
|
||||
documented in the API reference. For example,
|
||||
<function>hb_blob_create_from_file()</function> constructs a new
|
||||
blob directly from the contents of a file.
|
||||
</para>
|
||||
<para>
|
||||
All objects are created with an initial reference count of
|
||||
<literal>1</literal>. Client programs can increase the reference
|
||||
count on an object by calling its
|
||||
<function>reference()</function> method. Whenever a client
|
||||
program is finished with an object, it should call its
|
||||
corresponding <function>destroy()</function> method. The destroy
|
||||
method will decrease the reference count on the object and,
|
||||
whenever the reference count reaches zero, it will also destroy
|
||||
the object and free all of the associated memory.
|
||||
</para>
|
||||
<para>
|
||||
All of HarfBuzz's object-lifecycle-management APIs are
|
||||
thread-safe (unless you compiled HarfBuzz from source with the
|
||||
<literal>HB_NO_MT</literal> configuration flag), even when the
|
||||
object as a whole is not thread-safe.
|
||||
It is also permissible to <function>reference()</function> or to
|
||||
<function>destroy()</function> the <literal>NULL</literal>
|
||||
value.
|
||||
</para>
|
||||
<para>
|
||||
Some objects are thread-safe after they have been constructed
|
||||
and set up. The general pattern is to
|
||||
<function>create()</function> the object, make a few
|
||||
<function>set_*()</function> calls to set up the
|
||||
object, and then use it without further modification.
|
||||
</para>
|
||||
<para>
|
||||
To ensure that such an object is not modified, client programs
|
||||
can explicitly mark an object as immutable. HarfBuzz provides
|
||||
<function>make_immutable()</function> methods to mark an object
|
||||
as immutable and <function>is_immutable()</function> methods to
|
||||
test whether or not an object is immutable. Attempts to use
|
||||
setter functions on immutable objects will fail silently; see the API
|
||||
Reference manual for specifics.
|
||||
</para>
|
||||
<para>
|
||||
Note also that there are no "make mutable" methods. If client
|
||||
programs need to alter an object previously marked as immutable,
|
||||
they will need to make a duplicate of the original.
|
||||
</para>
|
||||
<para>
|
||||
Finally, object constructors (and, indeed, as much of the
|
||||
shaping API as possible) will never return
|
||||
<literal>NULL</literal>. Instead, if there is an allocation
|
||||
error, each constructor will return an “empty” object
|
||||
singleton.
|
||||
</para>
|
||||
<para>
|
||||
These empty-object singletons are inert and safe (although
|
||||
typically useless) to pass around. This design choice avoids
|
||||
having to check for <literal>NULL</literal> pointers all
|
||||
throughout the code.
|
||||
</para>
|
||||
<para>
|
||||
In addition, this “empty” object singleton can also be accessed
|
||||
using the <function>get_empty()</function> method of the object
|
||||
type in question.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="object-model-user-data">
|
||||
<title>User data</title>
|
||||
<para>
|
||||
To better integrate with client programs, HarfBuzz's objects
|
||||
offer a "user data" mechanism that can be used to attach
|
||||
arbitrary data to the object. User-data attachment can be
|
||||
useful for tying the lifecycles of various pieces of data
|
||||
together, or for creating language bindings.
|
||||
</para>
|
||||
<para>
|
||||
Each object type has a <function>set_user_data()</function>
|
||||
method and a <function>get_user_data()</function> method. The
|
||||
<function>set_user_data()</function> methods take a client-provided
|
||||
<literal>key</literal> and a pointer,
|
||||
<literal>user_data</literal>, pointing to the data itself. Once
|
||||
the key-data pair has been attached to the object, the
|
||||
<function>get_user_data()</function> method can be called with
|
||||
the key, returning the <function>user_data</function> pointer.
|
||||
</para>
|
||||
<para>
|
||||
The <function>set_user_data()</function> methods also support an
|
||||
optional <function>destroy</function> callback. Client programs
|
||||
can set the <function>destroy</function> callback and receive
|
||||
notification from HarfBuzz whenever the object is destructed.
|
||||
</para>
|
||||
<para>
|
||||
Finally, each <function>set_user_data()</function> method allows
|
||||
the client program to set a <literal>replace</literal> Boolean
|
||||
indicating whether or not the function call should replace any
|
||||
existing <literal>user_data</literal>
|
||||
associated with the specified key.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="object-model-blobs">
|
||||
<title>Blobs</title>
|
||||
<para>
|
||||
While most of HarfBuzz's object types are specific to the
|
||||
shaping process, <emphasis>blobs</emphasis> are somewhat
|
||||
different.
|
||||
</para>
|
||||
<para>
|
||||
Blobs are an abstraction designed to negotiate lifecycle and
|
||||
permissions for raw pieces of data. For example, when you load
|
||||
the raw font data into memory and want to pass it to HarfBuzz,
|
||||
you do so in a <literal>hb_blob_t</literal> wrapper.
|
||||
</para>
|
||||
<para>
|
||||
This allows you to take advantage of HarffBuzz's
|
||||
reference-counting and <function>destroy</function>
|
||||
callbacks. If you allocated the memory for the data using
|
||||
<function>malloc()</function>, you would create the blob using
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_blob_create (data, length, HB_MEMORY_MODE_WRITABLE, data, free)
|
||||
</programlisting>
|
||||
<para>
|
||||
That way, HarfBuzz will call <function>free()</function> on the
|
||||
allocated memory whenever the blob drops its last reference and
|
||||
is deconstructed. Consequently, the user code can stop worrying
|
||||
about freeing memory and let the reference-counting machinery
|
||||
take care of that.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -1,336 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="shaping-and-shape-plans">
|
||||
<title>Shaping and shape plans</title>
|
||||
<para>
|
||||
Once you have your face and font objects configured as desired and
|
||||
your input buffer is filled with the characters you need to shape,
|
||||
all you need to do is call <function>hb_shape()</function>.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz will return the shaped version of the text in the same
|
||||
buffer that you provided, but it will be in output mode. At that
|
||||
point, you can iterate through the glyphs in the buffer, drawing
|
||||
each one at the specified position or handing them off to the
|
||||
appropriate graphics library.
|
||||
</para>
|
||||
<para>
|
||||
For the most part, HarfBuzz's shaping step is straightforward from
|
||||
the outside. But that doesn't mean there will never be cases where
|
||||
you want to look under the hood and see what is happening on the
|
||||
inside. HarfBuzz provides facilities for doing that, too.
|
||||
</para>
|
||||
|
||||
<section id="shaping-buffer-output">
|
||||
<title>Shaping and buffer output</title>
|
||||
<para>
|
||||
The <function>hb_shape()</function> function call takes four arguments: the font
|
||||
object to use, the buffer of characters to shape, an array of
|
||||
user-specified features to apply, and the length of that feature
|
||||
array. The feature array can be NULL, so for the sake of
|
||||
simplicity we will start with that case.
|
||||
</para>
|
||||
<para>
|
||||
Internally, HarfBuzz looks at the tables of the font file to
|
||||
determine where glyph classes, substitutions, and positioning
|
||||
are defined, using that information to decide which
|
||||
<emphasis>shaper</emphasis> to use (<literal>ot</literal> for
|
||||
OpenType fonts, <literal>aat</literal> for Apple Advanced
|
||||
Typography fonts, and so on). It also looks at the direction,
|
||||
script, and language properties of the segment to figure out
|
||||
which script-specific shaping model is needed (at least, in
|
||||
shapers that support multiple options).
|
||||
</para>
|
||||
<para>
|
||||
If a font has a GDEF table, then that is used for
|
||||
glyph classes; if not, HarfBuzz will fall back to Unicode
|
||||
categorization by code point. If a font has an AAT <literal>morx</literal> table,
|
||||
then it is used for substitutions; if not, but there is a GSUB
|
||||
table, then the GSUB table is used. If the font has an AAT
|
||||
<literal>kerx</literal> table, then it is used for positioning; if not, but
|
||||
there is a GPOS table, then the GPOS table is used. If neither
|
||||
table is found, but there is a <literal>kern</literal> table, then HarfBuzz will
|
||||
use the <literal>kern</literal> table. If there is no <literal>kerx</literal>, no GPOS, and no
|
||||
<literal>kern</literal>, HarfBuzz will fall back to positioning marks itself.
|
||||
</para>
|
||||
<para>
|
||||
With a well-behaved OpenType font, you expect GDEF, GSUB, and
|
||||
GPOS tables to all be applied. HarfBuzz implements the
|
||||
script-specific shaping models in internal functions, rather
|
||||
than in the public API.
|
||||
</para>
|
||||
<para>
|
||||
The algorithms
|
||||
used for complex scripts can be quite involved; HarfBuzz tries
|
||||
to be compatible with the OpenType Layout specification
|
||||
and, wherever there is any ambiguity, HarfBuzz attempts to replicate the
|
||||
output of Microsoft's Uniscribe engine. See the <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/script-development/standard">Microsoft
|
||||
Typography pages</ulink> for more detail.
|
||||
</para>
|
||||
<para>
|
||||
In general, though, all that you need to know is that
|
||||
<function>hb_shape()</function> returns the results of shaping
|
||||
in the same buffer that you provided. The buffer's content type
|
||||
will now be set to
|
||||
<literal>HB_BUFFER_CONTENT_TYPE_GLYPHS</literal>, indicating
|
||||
that it contains shaped output, rather than input text. You can
|
||||
now extract the glyph information and positioning arrays:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count);
|
||||
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count);
|
||||
</programlisting>
|
||||
<para>
|
||||
The glyph information array holds a <type>hb_glyph_info_t</type>
|
||||
for each output glyph, which has two fields:
|
||||
<parameter>codepoint</parameter> and
|
||||
<parameter>cluster</parameter>. Whereas, in the input buffer,
|
||||
the <parameter>codepoint</parameter> field contained the Unicode
|
||||
code point, it now contains the glyph ID of the corresponding
|
||||
glyph in the font. The <parameter>cluster</parameter> field is
|
||||
an integer that you can use to help identify when shaping has
|
||||
reordered, split, or combined code points; we will say more
|
||||
about that in the next chapter.
|
||||
</para>
|
||||
<para>
|
||||
The glyph positions array holds a corresponding
|
||||
<type>hb_glyph_position_t</type> for each output glyph,
|
||||
containing four fields: <parameter>x_advance</parameter>,
|
||||
<parameter>y_advance</parameter>,
|
||||
<parameter>x_offset</parameter>, and
|
||||
<parameter>y_offset</parameter>. The advances tell you how far
|
||||
you need to move the drawing point after drawing this glyph,
|
||||
depending on whether you are setting horizontal text (in which
|
||||
case you will have x advances) or vertical text (for which you
|
||||
will have y advances). The x and y offsets tell you where to
|
||||
move to start drawing the glyph; usually you will have both and
|
||||
x and a y offset, regardless of the text direction.
|
||||
</para>
|
||||
<para>
|
||||
Most of the time, you will rely on a font-rendering library or
|
||||
other graphics library to do the actual drawing of glyphs, so
|
||||
you will need to iterate through the glyphs in the buffer and
|
||||
pass the corresponding values off.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-opentype-features">
|
||||
<title>OpenType features</title>
|
||||
<para>
|
||||
OpenType features enable fonts to include smart behavior,
|
||||
implemented as "lookup" rules stored in the GSUB and GPOS
|
||||
tables. The OpenType specification defines a long list of
|
||||
standard features that fonts can use for these behaviors; each
|
||||
feature has a four-character reserved name and a well-defined
|
||||
semantic meaning.
|
||||
</para>
|
||||
<para>
|
||||
Some OpenType features are defined for the purpose of supporting
|
||||
complex-script shaping, and are automatically activated, but
|
||||
only when a buffer's script property is set to a script that the
|
||||
feature supports.
|
||||
</para>
|
||||
<para>
|
||||
Other features are more generic and can apply to several (or
|
||||
any) script, and shaping engines are expected to implement
|
||||
them. By default, HarfBuzz activates several of these features
|
||||
on every text run. They include <literal>abvm</literal>,
|
||||
<literal>blwm</literal>, <literal>ccmp</literal>,
|
||||
<literal>locl</literal>, <literal>mark</literal>,
|
||||
<literal>mkmk</literal>, and <literal>rlig</literal>.
|
||||
</para>
|
||||
<para>
|
||||
In addition, if the text direction is horizontal, HarfBuzz
|
||||
also applies the <literal>calt</literal>,
|
||||
<literal>clig</literal>, <literal>curs</literal>,
|
||||
<literal>dist</literal>, <literal>kern</literal>,
|
||||
<literal>liga</literal> and <literal>rclt</literal>, features.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, when HarfBuzz encounters a fraction slash
|
||||
(<literal>U+2044</literal>), it looks backward and forward for decimal
|
||||
digits (Unicode General Category = Nd), and enables features
|
||||
<literal>numr</literal> on the sequence before the fraction slash,
|
||||
<literal>dnom</literal> on the sequence after the fraction slash,
|
||||
and <literal>frac</literal> on the whole sequence including the fraction
|
||||
slash.
|
||||
</para>
|
||||
<para>
|
||||
Some script-specific shaping models
|
||||
(see <xref linkend="opentype-shaping-models" />) disable some of the
|
||||
features listed above:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Hangul: <literal>calt</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Indic: <literal>liga</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Khmer: <literal>liga</literal>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If the text direction is vertical, HarfBuzz applies
|
||||
the <literal>vert</literal> feature by default.
|
||||
</para>
|
||||
<para>
|
||||
Still other features are designed to be purely optional and left
|
||||
up to the application or the end user to enable or disable as desired.
|
||||
</para>
|
||||
<para>
|
||||
You can adjust the set of features that HarfBuzz applies to a
|
||||
buffer by supplying an array of <type>hb_feature_t</type>
|
||||
features as the third argument to
|
||||
<function>hb_shape()</function>. For a simple case, let's just
|
||||
enable the <literal>dlig</literal> feature, which turns on any
|
||||
"discretionary" ligatures in the font:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_feature_t userfeatures[1];
|
||||
userfeatures[0].tag = HB_TAG('d','l','i','g');
|
||||
userfeatures[0].value = 1;
|
||||
userfeatures[0].start = HB_FEATURE_GLOBAL_START;
|
||||
userfeatures[0].end = HB_FEATURE_GLOBAL_END;
|
||||
</programlisting>
|
||||
<para>
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> and
|
||||
<literal>HB_FEATURE_GLOBAL_END</literal> are macros we can use
|
||||
to indicate that the features will be applied to the entire
|
||||
buffer. We could also have used a literal <literal>0</literal>
|
||||
for the start and a <literal>-1</literal> to indicate the end of
|
||||
the buffer (or have selected other start and end positions, if needed).
|
||||
</para>
|
||||
<para>
|
||||
When we pass the <varname>userfeatures</varname> array to
|
||||
<function>hb_shape()</function>, any discretionary ligature
|
||||
substitutions from our font that match the text in our buffer
|
||||
will get performed:
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
hb_shape(font, buf, userfeatures, num_features);
|
||||
</programlisting>
|
||||
<para>
|
||||
Just like we enabled the <literal>dlig</literal> feature by
|
||||
setting its <parameter>value</parameter> to
|
||||
<literal>1</literal>, you would disable a feature by setting its
|
||||
<parameter>value</parameter> to <literal>0</literal>. Some
|
||||
features can take other <parameter>value</parameter> settings;
|
||||
be sure you read the full specification of each feature tag to
|
||||
understand what it does and how to control it.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-shaper-selection">
|
||||
<title>Shaper selection</title>
|
||||
<para>
|
||||
The basic version of <function>hb_shape()</function> determines
|
||||
its shaping strategy based on examining the capabilities of the
|
||||
font file. OpenType font tables cause HarfBuzz to try the
|
||||
<literal>ot</literal> shaper, while AAT font tables cause HarfBuzz to try the
|
||||
<literal>aat</literal> shaper.
|
||||
</para>
|
||||
<para>
|
||||
In the real world, however, a font might include some unusual
|
||||
mix of tables, or one of the tables might simply be broken for
|
||||
the script you need to shape. So, sometimes, you might not
|
||||
want to rely on HarfBuzz's process for deciding what to do, and
|
||||
just tell <function>hb_shape()</function> what you want it to try.
|
||||
</para>
|
||||
<para>
|
||||
<function>hb_shape_full()</function> is an alternate shaping
|
||||
function that lets you supply a list of shapers for HarfBuzz to
|
||||
try, in order, when shaping your buffer. For example, if you
|
||||
have determined that HarfBuzz's attempts to work around broken
|
||||
tables gives you better results than the AAT shaper itself does,
|
||||
you might move the AAT shaper to the end of your list of
|
||||
preferences and call <function>hb_shape_full()</function>
|
||||
</para>
|
||||
<programlisting language="C">
|
||||
char *shaperprefs[3] = {"ot", "default", "aat"};
|
||||
...
|
||||
hb_shape_full(font, buf, userfeatures, num_features, shaperprefs);
|
||||
</programlisting>
|
||||
<para>
|
||||
to get results you are happier with.
|
||||
</para>
|
||||
<para>
|
||||
You may also want to call
|
||||
<function>hb_shape_list_shapers()</function> to get a list of
|
||||
the shapers that were built at compile time in your copy of HarfBuzz.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-plans-and-caching">
|
||||
<title>Plans and caching</title>
|
||||
<para>
|
||||
Internally, HarfBuzz uses a structure called a shape plan to
|
||||
track its decisions about how to shape the contents of a
|
||||
buffer. The <function>hb_shape()</function> function builds up the shape plan by
|
||||
examining segment properties and by inspecting the contents of
|
||||
the font.
|
||||
</para>
|
||||
<para>
|
||||
This process can involve some decision-making and
|
||||
trade-offs — for example, HarfBuzz inspects the GSUB and GPOS
|
||||
lookups for the script and language tags set on the segment
|
||||
properties, but it falls back on the lookups under the
|
||||
<literal>DFLT</literal> tag (and sometimes other common tags)
|
||||
if there are actually no lookups for the tag requested.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also includes some work-arounds for
|
||||
handling well-known older font conventions that do not follow
|
||||
OpenType or Unicode specifications, for buggy system fonts, and for
|
||||
peculiarities of Microsoft Uniscribe. All of that means that a
|
||||
shape plan, while not something that you should edit directly in
|
||||
client code, still might be an object that you want to
|
||||
inspect. Furthermore, if resources are tight, you might want to
|
||||
cache the shape plan that HarfBuzz builds for your buffer and
|
||||
font, so that you do not have to rebuild it for every shaping call.
|
||||
</para>
|
||||
<para>
|
||||
You can create a cacheable shape plan with
|
||||
<function>hb_shape_plan_create_cached(face, props,
|
||||
user_features, num_user_features, shaper_list)</function>, where
|
||||
<parameter>face</parameter> is a face object (not a font object,
|
||||
notably), <parameter>props</parameter> is an
|
||||
<type>hb_segment_properties_t</type>,
|
||||
<parameter>user_features</parameter> is an array of
|
||||
<type>hb_feature_t</type>s (with length
|
||||
<parameter>num_user_features</parameter>), and
|
||||
<parameter>shaper_list</parameter> is a list of shapers to try.
|
||||
</para>
|
||||
<para>
|
||||
Shape plans are objects in HarfBuzz, so there are
|
||||
reference-counting functions and user-data attachment functions
|
||||
you can
|
||||
use. <function>hb_shape_plan_reference(shape_plan)</function>
|
||||
increases the reference count on a shape plan, while
|
||||
<function>hb_shape_plan_destroy(shape_plan)</function> decreases
|
||||
the reference count, destroying the shape plan when the last
|
||||
reference is dropped.
|
||||
</para>
|
||||
<para>
|
||||
You can attach user data to a shaper (with a key) using the
|
||||
<function>hb_shape_plan_set_user_data(shape_plan,key,data,destroy,replace)</function>
|
||||
function, optionally supplying a <function>destroy</function>
|
||||
callback to use. You can then fetch the user data attached to a
|
||||
shape plan with
|
||||
<function>hb_shape_plan_get_user_data(shape_plan, key)</function>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -1,375 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="shaping-concepts">
|
||||
<title>Shaping concepts</title>
|
||||
<section id="text-shaping-concepts">
|
||||
<title>Text shaping</title>
|
||||
<para>
|
||||
Text shaping is the process of transforming a sequence of Unicode
|
||||
codepoints that represent individual characters (letters,
|
||||
diacritics, tone marks, numbers, symbols, etc.) into the
|
||||
orthographically and linguistically correct two-dimensional layout
|
||||
of glyph shapes taken from a specified font.
|
||||
</para>
|
||||
<para>
|
||||
For some writing systems (or <emphasis>scripts</emphasis>) and
|
||||
languages, the process is simple, requiring the shaper to do
|
||||
little more than advance the horizontal position forward by the
|
||||
correct amount for each successive glyph.
|
||||
</para>
|
||||
<para>
|
||||
But, for <emphasis>complex scripts</emphasis>, any combination of
|
||||
several shaping operations may be required, and the rules for how
|
||||
and when they are applied vary from script to script. HarfBuzz and
|
||||
other shaping engines implement these rules.
|
||||
</para>
|
||||
<para>
|
||||
The exact rules and necessary operations for a particular script
|
||||
constitute a shaping <emphasis>model</emphasis>. OpenType
|
||||
specifies a set of shaping models that covers all of
|
||||
Unicode. Other shaping models are available, however, including
|
||||
Graphite and Apple Advanced Typography (AAT).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="complex-scripts">
|
||||
<title>Complex scripts</title>
|
||||
<para>
|
||||
In text-shaping terminology, scripts are generally classified as
|
||||
either <emphasis>complex</emphasis> or <emphasis>non-complex</emphasis>.
|
||||
</para>
|
||||
<para>
|
||||
Complex scripts are those for which transforming the input
|
||||
sequence into the final layout requires some combination of
|
||||
operations—such as context-dependent substitutions,
|
||||
context-dependent mark positioning, glyph-to-glyph joining,
|
||||
glyph reordering, or glyph stacking.
|
||||
</para>
|
||||
<para>
|
||||
In some complex scripts, the shaping rules require that a text
|
||||
run be divided into syllables before the operations can be
|
||||
applied. Other complex scripts may apply shaping operations over
|
||||
entire words or over the entire text run, with no subdivision
|
||||
required.
|
||||
</para>
|
||||
<para>
|
||||
Non-complex scripts, by definition, do not require these
|
||||
operations. However, correctly shaping a text run in a
|
||||
non-complex script may still involve Unicode normalization,
|
||||
ligature substitutions, mark positioning, kerning, and applying
|
||||
other font features. The key difference is that a text run in a
|
||||
non-complex script can be processed sequentially and in the same
|
||||
order as the input sequence of Unicode codepoints, without
|
||||
requiring an analysis stage.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="shaping-operations">
|
||||
<title>Shaping operations</title>
|
||||
<para>
|
||||
Shaping a complex-script text run involves transforming the
|
||||
input sequence of Unicode codepoints with some combination of
|
||||
operations that is specified in the shaping model for the
|
||||
script.
|
||||
</para>
|
||||
<para>
|
||||
The specific conditions that trigger a given operation for a
|
||||
text run varies from script to script, as do the order that the
|
||||
operations are performed in and which codepoints are
|
||||
affected. However, the same general set of shaping operations is
|
||||
common to all of the complex-script shaping models.
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
A <emphasis>reordering</emphasis> operation moves a glyph
|
||||
from its original ("logical") position in the sequence to
|
||||
some other ("visual") position.
|
||||
</para>
|
||||
<para>
|
||||
The shaping model for a given complex script might involve
|
||||
more than one reordering step.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A <emphasis>joining</emphasis> operation replaces a glyph
|
||||
with an alternate form that is designed to connect with one
|
||||
or more of the adjacent glyphs in the sequence.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A contextual <emphasis>substitution</emphasis> operation
|
||||
replaces either a single glyph or a subsequence of several
|
||||
glyphs with an alternate glyph. This substitution is
|
||||
performed when the original glyph or subsequence of glyphs
|
||||
occurs in a specified position with respect to the
|
||||
surrounding sequence. For example, one substitution might be
|
||||
performed only when the target glyph is the first glyph in
|
||||
the sequence, while another substitution is performed only
|
||||
when a different target glyph occurs immediately after a
|
||||
particular string pattern.
|
||||
</para>
|
||||
<para>
|
||||
The shaping model for a given complex script might involve
|
||||
multiple contextual-substitution operations, each applying
|
||||
to different target glyphs and patterns, and which are
|
||||
performed in separate steps.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A contextual <emphasis>positioning</emphasis> operation
|
||||
moves the horizontal and/or vertical position of a
|
||||
glyph. This positioning move is performed when the glyph
|
||||
occurs in a specified position with respect to the
|
||||
surrounding sequence.
|
||||
</para>
|
||||
<para>
|
||||
Many contextual positioning operations are used to place
|
||||
<emphasis>mark</emphasis> glyphs (such as diacritics, vowel
|
||||
signs, and tone markers) with respect to
|
||||
<emphasis>base</emphasis> glyphs. However, some complex
|
||||
scripts may use contextual positioning operations to
|
||||
correctly place base glyphs as well, such as
|
||||
when the script uses <emphasis>stacking</emphasis> characters.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="unicode-character-categories">
|
||||
<title>Unicode character categories</title>
|
||||
<para>
|
||||
Shaping models are typically specified with respect to how
|
||||
scripts are defined in the Unicode standard.
|
||||
</para>
|
||||
<para>
|
||||
Every codepoint in the Unicode Character Database (UCD) is
|
||||
assigned a <emphasis>Unicode General Category</emphasis> (UGC),
|
||||
which provides the most fundamental information about the
|
||||
codepoint: whether the codepoint represents a
|
||||
<emphasis>Letter</emphasis>, a <emphasis>Mark</emphasis>, a
|
||||
<emphasis>Number</emphasis>, <emphasis>Punctuation</emphasis>, a
|
||||
<emphasis>Symbol</emphasis>, a <emphasis>Separator</emphasis>,
|
||||
or something else (<emphasis>Other</emphasis>).
|
||||
</para>
|
||||
<para>
|
||||
These UGC properties are "Major" categories. Each codepoint is
|
||||
further assigned to a "minor" category within its Major
|
||||
category, such as "Letter, uppercase" (<literal>Lu</literal>) or
|
||||
"Letter, modifier" (<literal>Lm</literal>).
|
||||
</para>
|
||||
<para>
|
||||
Shaping models are concerned primarily with Letter and Mark
|
||||
codepoints. The minor categories of Mark codepoints are
|
||||
particularly important for shaping. Marks can be nonspacing
|
||||
(<literal>Mn</literal>), spacing combining
|
||||
(<literal>Mc</literal>), or enclosing (<literal>Me</literal>).
|
||||
</para>
|
||||
<para>
|
||||
In addition to the UGC property, codepoints in the Indic and
|
||||
Southeast Asian scripts are also assigned
|
||||
<emphasis>Unicode Indic Syllabic Category</emphasis> (UISC) and
|
||||
<emphasis>Unicode Indic Positional Category</emphasis> (UIPC)
|
||||
properties that provide more detailed information needed for
|
||||
shaping.
|
||||
</para>
|
||||
<para>
|
||||
The UISC property sub-categorizes Letters and Marks according to
|
||||
common script-shaping behaviors. For example, UISC distinguishes
|
||||
between consonant letters, vowel letters, and vowel marks. The
|
||||
UIPC property sub-categorizes Mark codepoints by the relative visual
|
||||
position that they occupy (above, below, right, left, or in
|
||||
multiple positions).
|
||||
</para>
|
||||
<para>
|
||||
Some complex scripts require that the text run be split into
|
||||
syllables. What constitutes a valid syllable in these
|
||||
scripts is specified in regular expressions, formed from the
|
||||
Letter and Mark codepoints, that take the UISC and UIPC
|
||||
properties into account.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="text-runs">
|
||||
<title>Text runs</title>
|
||||
<para>
|
||||
Real-world text usually contains codepoints from a mixture of
|
||||
different Unicode scripts (including punctuation, numbers, symbols,
|
||||
white-space characters, and other codepoints that do not belong
|
||||
to any script). Real-world text may also be marked up with
|
||||
formatting that changes font properties (including the font,
|
||||
font style, and font size).
|
||||
</para>
|
||||
<para>
|
||||
For shaping purposes, all real-world text streams must be first
|
||||
segmented into runs that have a uniform set of properties.
|
||||
</para>
|
||||
<para>
|
||||
In particular, shaping models always assume that every codepoint
|
||||
in a text run has the same <emphasis>direction</emphasis>,
|
||||
<emphasis>script</emphasis> tag, and
|
||||
<emphasis>language</emphasis> tag.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="opentype-shaping-models">
|
||||
<title>OpenType shaping models</title>
|
||||
<para>
|
||||
OpenType provides shaping models for the following scripts:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>default</emphasis> shaping model handles all
|
||||
non-complex scripts, and may also be used as a fallback for
|
||||
handling unrecognized scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Indic</emphasis> shaping model handles the Indic
|
||||
scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
|
||||
Malayalam, Oriya, Tamil, Telugu, and Sinhala.
|
||||
</para>
|
||||
<para>
|
||||
The Indic shaping model was revised significantly in
|
||||
2005. To denote the change, a new set of <emphasis>script
|
||||
tags</emphasis> was assigned for Bengali, Devanagari,
|
||||
Gujarati, Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and
|
||||
Telugu. For the sake of clarity, the term "Indic2" is
|
||||
sometimes used to refer to the current, revised shaping
|
||||
model.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Arabic</emphasis> shaping model supports
|
||||
Arabic, Mongolian, N'Ko, Syriac, and several other connected
|
||||
or cursive scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Thai/Lao</emphasis> shaping model supports
|
||||
the Thai and Lao scripts.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Khmer</emphasis> shaping model supports the
|
||||
Khmer script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Myanmar</emphasis> shaping model supports the
|
||||
Myanmar (or Burmese) script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Tibetan</emphasis> shaping model supports the
|
||||
Tibetan script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Hangul</emphasis> shaping model supports the
|
||||
Hangul script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Hebrew</emphasis> shaping model supports the
|
||||
Hebrew script.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The <emphasis>Universal Shaping Engine</emphasis> (USE)
|
||||
shaping model supports complex scripts not covered by one of
|
||||
the above, script-specific shaping models, including
|
||||
Javanese, Balinese, Buginese, Batak, Chakma, Lepcha, Modi,
|
||||
Phags-pa, Tagalog, Siddham, Sundanese, Tai Le, Tai Tham, Tai
|
||||
Viet, and many others.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Text runs that do not fall under one of the above shaping
|
||||
models may still require processing by a shaping engine. Of
|
||||
particular note is <emphasis>Emoji</emphasis> shaping, which
|
||||
may involve variation-selector sequences and glyph
|
||||
substitution. Emoji shaping is handled by the default
|
||||
shaping model.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="graphite-shaping">
|
||||
<title>Graphite shaping</title>
|
||||
<para>
|
||||
In contrast to OpenType shaping, Graphite shaping does not
|
||||
specify a predefined set of shaping models or a set of supported
|
||||
scripts.
|
||||
</para>
|
||||
<para>
|
||||
Instead, each Graphite font contains a complete set of rules that
|
||||
implement the required shaping model for the intended
|
||||
script. These rules include finite-state machines to match
|
||||
sequences of codepoints to the shaping operations to perform.
|
||||
</para>
|
||||
<para>
|
||||
Graphite shaping can perform the same shaping operations used in
|
||||
OpenType shaping, as well as other functions that have not been
|
||||
defined for OpenType shaping.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="aat-shaping">
|
||||
<title>AAT shaping</title>
|
||||
<para>
|
||||
In contrast to OpenType shaping, AAT shaping does not specify a
|
||||
predefined set of shaping models or a set of supported scripts.
|
||||
</para>
|
||||
<para>
|
||||
Instead, each AAT font includes a complete set of rules that
|
||||
implement the desired shaping model for the intended
|
||||
script. These rules include finite-state machines to match glyph
|
||||
sequences and the shaping operations to perform.
|
||||
</para>
|
||||
<para>
|
||||
Notably, AAT shaping rules are expressed for glyphs in the font,
|
||||
not for Unicode codepoints. AAT shaping can perform the same
|
||||
shaping operations used in OpenType shaping, as well as other
|
||||
functions that have not been defined for OpenType shaping.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -1,218 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="utilities">
|
||||
<title>Utilities</title>
|
||||
<para>
|
||||
HarfBuzz includes several auxiliary components in addition to the
|
||||
main APIs. These include a set of command-line tools, a set of
|
||||
lower-level APIs for common data types that may be of interest to
|
||||
client programs.
|
||||
</para>
|
||||
|
||||
<section id="utilities-command-line-tools">
|
||||
<title>Command-line tools</title>
|
||||
<para>
|
||||
HarfBuzz include three command-line tools:
|
||||
<command>hb-shape</command>, <command>hb-view</command>, and
|
||||
<command>hb-subset</command>. They can be used to examine
|
||||
HarfBuzz's functionality, debug font binaries, or explore the
|
||||
various shaping models and features from a terminal.
|
||||
</para>
|
||||
|
||||
<section id="utilities-command-line-hbshape">
|
||||
<title>hb-shape</title>
|
||||
<para>
|
||||
<emphasis><command>hb-shape</command></emphasis> allows you to run HarfBuzz's
|
||||
<function>hb_shape()</function> function on an input string and
|
||||
to examine the outcome, in human-readable form, as terminal
|
||||
output. <command>hb-shape</command> does
|
||||
<emphasis>not</emphasis> render the results of the shaping call
|
||||
into rendered text (you can use <command>hb-view</command>, below, for
|
||||
that). Instead, it prints out the final glyph indices and
|
||||
positions, taking all shaping operations into account, as if the
|
||||
input string were a HarfBuzz input buffer.
|
||||
</para>
|
||||
<para>
|
||||
You can specify the font to be used for shaping and, with
|
||||
command-line options, you can add various aspects of the
|
||||
internal state to the output that is sent to the terminal. The
|
||||
general format is
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-shape</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
The default output format is plain text (although JSON output
|
||||
can be selected instead by specifying the option
|
||||
<optional>--output-format=json</optional>). The default output
|
||||
syntax reports each glyph name (or glyph index if there is no
|
||||
name) followed by its cluster value, its horizontal and vertical
|
||||
position displacement, and its horizontal and vertical advances.
|
||||
</para>
|
||||
<para>
|
||||
Output options exist to skip any of these elements in the
|
||||
output, and to include additional data, such as Unicode
|
||||
code-point values, glyph extents, glyph flags, or interim
|
||||
shaping results.
|
||||
</para>
|
||||
<para>
|
||||
Output can also be redirected to a file, or input read from a
|
||||
file. Additional options enable you to enable or disable
|
||||
specific font features, to set variation-font axis values, to
|
||||
alter the language, script, direction, and clustering settings
|
||||
used, to enable sanity checks, or to change which shaping engine is used.
|
||||
</para>
|
||||
<para>
|
||||
For a complete explanation of the options available, run
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-shape</command> <parameter>--help</parameter>
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="utilities-command-line-hbview">
|
||||
<title>hb-view</title>
|
||||
<para>
|
||||
<emphasis><command>hb-view</command></emphasis> allows you to
|
||||
see the shaped output of an input string in rendered
|
||||
form. Like <command>hb-shape</command>,
|
||||
<command>hb-view</command> takes a font file and a text string
|
||||
as its arguments:
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-view</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
By default, <command>hb-view</command> renders the shaped
|
||||
text in ASCII block-character images as terminal output. By
|
||||
appending the
|
||||
<command>--output-file=<optional>filename</optional></command>
|
||||
switch, you can write the output to a PNG, SVG, or PDF file
|
||||
(among other formats).
|
||||
</para>
|
||||
<para>
|
||||
As with <command>hb-shape</command>, a lengthy set of options
|
||||
is available, with which you can enable or disable
|
||||
specific font features, set variation-font axis values,
|
||||
alter the language, script, direction, and clustering settings
|
||||
used, enable sanity checks, or change which shaping engine is
|
||||
used.
|
||||
</para>
|
||||
<para>
|
||||
You can also set the foreground and background colors used for
|
||||
the output, independently control the width of all four
|
||||
margins, alter the line spacing, and annotate the output image
|
||||
with
|
||||
</para>
|
||||
<para>
|
||||
In general, <command>hb-view</command> is a quick way to
|
||||
verify that the output of HarfBuzz's shaping operation looks
|
||||
correct for a given text-and-font combination, but you may
|
||||
want to use <command>hb-shape</command> to figure out exactly
|
||||
why something does not appear as expected.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="utilities-command-line-hbsubset">
|
||||
<title>hb-subset</title>
|
||||
<para>
|
||||
<emphasis><command>hb-subset</command></emphasis> allows you
|
||||
to generate a subset of a given font, with a limited set of
|
||||
supported characters, features, and variation settings.
|
||||
</para>
|
||||
<para>
|
||||
By default, you provide an input font and an input text string
|
||||
as the arguments to <command>hb-subset</command>, and it will
|
||||
generate a font that covers the input text exactly like the
|
||||
input font does, but includes no other characters or features.
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-subset</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>path/to/font/file.ttf</parameter>
|
||||
<parameter>yourinputtext</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
For example, to create a subset of Noto Serif that just includes the
|
||||
numerals and the lowercase Latin alphabet, you could run
|
||||
</para>
|
||||
<programlisting>
|
||||
<command>hb-subset</command> <optional>[OPTIONS]</optional>
|
||||
<parameter>NotoSerif-Regular.ttf</parameter>
|
||||
<parameter>0123456789abcdefghijklmnopqrstuvwxyz</parameter>
|
||||
</programlisting>
|
||||
<para>
|
||||
There are options available to remove hinting from the
|
||||
subsetted font and to specify a list of variation-axis settings.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="utilities-common-types-apis">
|
||||
<title>Common data types and APIs</title>
|
||||
<para>
|
||||
HarfBuzz includes several APIs for working with general-purpose
|
||||
data that you may find convenient to leverage in your own
|
||||
software. They include set operations and integer-to-integer
|
||||
mapping operations.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz uses set operations for internal bookkeeping, such as
|
||||
when it collects all of the glyph IDs covered by a particular
|
||||
font feature. You can also use the set API to build sets, add
|
||||
and remove elements, test whether or not sets contain particular
|
||||
elements, or compute the unions, intersections, or differences
|
||||
between sets.
|
||||
</para>
|
||||
<para>
|
||||
All set elements are integers (specifically,
|
||||
<type>hb_codepoint_t</type> 32-bit unsigned ints), and there are
|
||||
functions for fetching the minimum and maximum element from a
|
||||
set. The set API also includes some functions that might not
|
||||
be part of a generic set facility, such as the ability to add a
|
||||
contiguous range of integer elements to a set in bulk, and the
|
||||
ability to fetch the next-smallest or next-largest element.
|
||||
</para>
|
||||
<para>
|
||||
The HarfBuzz set API includes some conveniences as well. All
|
||||
sets are lifecycle-managed, just like other HarfBuzz
|
||||
objects. You increase the reference count on a set with
|
||||
<function>hb_set_reference()</function> and decrease it with
|
||||
<function>hb_set_destroy()</function>. You can also attach
|
||||
user data to a set, just like you can to blobs, buffers, faces,
|
||||
fonts, and other objects, and set destroy callbacks.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz also provides an API for keeping track of
|
||||
integer-to-integer mappings. As with the set API, each integer is
|
||||
stored as an unsigned 32-bit <type>hb_codepoint_t</type>
|
||||
element. Maps, like other objects, are reference counted with
|
||||
reference and destroy functions, and you can attach user data to
|
||||
them. The mapping operations include adding and deleting
|
||||
integer-to-integer key:value pairs to the map, testing for the
|
||||
presence of a key, fetching the population of the map, and so on.
|
||||
</para>
|
||||
<para>
|
||||
There are several other internal HarfBuzz facilities that are
|
||||
exposed publicly and which you may want to take advantage of
|
||||
while processing text. HarfBuzz uses a common
|
||||
<type>hb_tag_t</type> for a variety of OpenType tag identifiers (for
|
||||
scripts, languages, font features, table names, variation-axis
|
||||
names, and more), and provides functions for converting strings
|
||||
to tags and vice-versa.
|
||||
</para>
|
||||
<para>
|
||||
Finally, HarfBuzz also includes data type for Booleans, bit
|
||||
masks, and other simple types.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
@ -1,442 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter id="what-is-harfbuzz">
|
||||
<title>What is HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz is a <emphasis>text-shaping engine</emphasis>. If you
|
||||
give HarfBuzz a font and a string containing a sequence of Unicode
|
||||
codepoints, HarfBuzz selects and positions the corresponding
|
||||
glyphs from the font, applying all of the necessary layout rules
|
||||
and font features. HarfBuzz then returns the string to you in the
|
||||
form that is correctly arranged for the language and writing
|
||||
system.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can properly shape all of the world's major writing
|
||||
systems. It runs on all major operating systems and software
|
||||
platforms and it supports the major font formats in use
|
||||
today.
|
||||
</para>
|
||||
<section id="what-is-text-shaping">
|
||||
<title>What is text shaping?</title>
|
||||
<para>
|
||||
Text shaping is the process of translating a string of character
|
||||
codes (such as Unicode codepoints) into a properly arranged
|
||||
sequence of glyphs that can be rendered onto a screen or into
|
||||
final output form for inclusion in a document.
|
||||
</para>
|
||||
<para>
|
||||
The shaping process is dependent on the input string, the active
|
||||
font, the script (or writing system) that the string is in, and
|
||||
the language that the string is in.
|
||||
</para>
|
||||
<para>
|
||||
Modern software systems generally only deal with strings in the
|
||||
Unicode encoding scheme (although legacy systems and documents may
|
||||
involve other encodings).
|
||||
</para>
|
||||
<para>
|
||||
There are several font formats that a program might
|
||||
encounter, each of which has a set of standard text-shaping
|
||||
rules.
|
||||
</para>
|
||||
<para>The dominant format is <ulink
|
||||
url="http://www.microsoft.com/typography/otspec/">OpenType</ulink>. The
|
||||
OpenType specification defines a series of <ulink url="https://github.com/n8willis/opentype-shaping-documents">shaping models</ulink> for
|
||||
various scripts from around the world. These shaping models depend on
|
||||
the font incorporating certain features as
|
||||
<emphasis>lookups</emphasis> in its <literal>GSUB</literal>
|
||||
and <literal>GPOS</literal> tables.
|
||||
</para>
|
||||
<para>
|
||||
Alternatively, OpenType fonts can include shaping features for
|
||||
the <ulink url="https://graphite.sil.org/">Graphite</ulink> shaping model.
|
||||
</para>
|
||||
<para>
|
||||
TrueType fonts can also include OpenType shaping
|
||||
features. Alternatively, TrueType fonts can also include <ulink url="https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html">Apple
|
||||
Advanced Typography</ulink> (AAT) tables to implement shaping
|
||||
support. AAT fonts are generally only found on macOS and iOS systems.
|
||||
</para>
|
||||
<para>
|
||||
Text strings will usually be tagged with a script and language
|
||||
tag that provide the context needed to perform text shaping
|
||||
correctly. The necessary <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags">script</ulink>
|
||||
and <ulink
|
||||
url="https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags">language</ulink>
|
||||
tags are defined by OpenType.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-do-i-need-a-shaping-engine">
|
||||
<title>Why do I need a shaping engine?</title>
|
||||
<para>
|
||||
Text shaping is an integral part of preparing text for
|
||||
display. Before a Unicode sequence can be rendered, the
|
||||
codepoints in the sequence must be mapped to the corresponding
|
||||
glyphs provided in the font, and those glyphs must be positioned
|
||||
correctly relative to each other. For many of the scripts
|
||||
supported in Unicode, these steps involve script-specific layout
|
||||
rules, including complex joining, reordering, and positioning
|
||||
behavior. Implementing these rules is the job of the shaping engine.
|
||||
</para>
|
||||
<para>
|
||||
Text shaping is a fairly low-level operation. HarfBuzz is
|
||||
used directly by text-handling libraries like <ulink
|
||||
url="https://www.pango.org/">Pango</ulink>, as well as by the layout
|
||||
engines in Firefox, LibreOffice, and Chromium. Unless you are
|
||||
<emphasis>writing</emphasis> one of these layout engines
|
||||
yourself, you will probably not need to use HarfBuzz: normally,
|
||||
a layout engine, toolkit, or other library will turn text into
|
||||
glyphs for you.
|
||||
</para>
|
||||
<para>
|
||||
However, if you <emphasis>are</emphasis> writing a layout engine
|
||||
or graphics library yourself, then you will need to perform text
|
||||
shaping, and this is where HarfBuzz can help you.
|
||||
</para>
|
||||
<para>
|
||||
Here are some specific scenarios where a text-shaping engine
|
||||
like HarfBuzz helps you:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
OpenType fonts contain a set of glyphs (that is, shapes
|
||||
to represent the letters, numbers, punctuation marks, and
|
||||
all other symbols), which are indexed by a <literal>glyph ID</literal>.
|
||||
</para>
|
||||
<para>
|
||||
A particular glyph ID within the font does not necessarily
|
||||
correlate to a predictable Unicode codepoint. For instance,
|
||||
some fonts have the letter "a" as glyph ID 1, but
|
||||
many others do not. In order to retrieve the right glyph
|
||||
from the font to display "a", you need to consult
|
||||
the table inside the font (the <literal>cmap</literal>
|
||||
table) that maps Unicode codepoints to glyph IDs. In other
|
||||
words, <emphasis>text shaping turns codepoints into glyph
|
||||
IDs</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Many OpenType fonts contain ligatures: combinations of
|
||||
characters that are rendered as a single unit. For instance,
|
||||
it is common for the "f, i" letter
|
||||
sequence to appear in print as the single ligature glyph
|
||||
"fi".
|
||||
</para>
|
||||
<para>
|
||||
Whether you should render an "f, i" sequence
|
||||
as <literal>fi</literal> or as "fi" does not
|
||||
depend on the input text. Instead, it depends on the whether
|
||||
or not the font includes an "fi" glyph and on the
|
||||
level of ligature application you wish to perform. The font
|
||||
and the amount of ligature application used are under your
|
||||
control. In other words, <emphasis>text shaping involves
|
||||
querying the font's ligature tables and determining what
|
||||
substitutions should be made</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
While ligatures like "fi" are optional typographic
|
||||
refinements, some languages <emphasis>require</emphasis> certain
|
||||
substitutions to be made in order to display text correctly.
|
||||
</para>
|
||||
<para>
|
||||
For example, in Tamil, when the letter "TTA" (ட)
|
||||
letter is followed by the vowel sign "U" (ு), the pair
|
||||
must be replaced by the single glyph "டு". The
|
||||
sequence of Unicode characters "ட,ு" needs to be
|
||||
substituted with a single "டு" glyph from the
|
||||
font.
|
||||
</para>
|
||||
<para>
|
||||
But "டு" does not have a Unicode codepoint. To
|
||||
find this glyph, you need to consult the table inside
|
||||
the font (the <literal>GSUB</literal> table) that contains
|
||||
substitution information. In other words, <emphasis>text shaping
|
||||
chooses the correct glyph for a sequence of characters
|
||||
provided</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Similarly, each Arabic character has four different variants
|
||||
corresponding to the different positions it might appear in
|
||||
within a sequence. Inside a font, there will be separate
|
||||
glyphs for the initial, medial, final, and isolated forms of
|
||||
each letter, each at a different glyph ID.
|
||||
</para>
|
||||
<para>
|
||||
Unicode only assigns one codepoint per character, so a
|
||||
Unicode string will not tell you which glyph variant to use
|
||||
for each character. To decide, you need to analyze the whole
|
||||
string and determine the appropriate glyph for each character
|
||||
based on its position. In other words, <emphasis>text
|
||||
shaping chooses the correct form of the letter by its
|
||||
position and returns the correct glyph from the font</emphasis>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Other languages involve marks and accents that need to be
|
||||
rendered in specific positions relative a base character. For
|
||||
instance, the Moldovan language includes the Cyrillic letter
|
||||
"zhe" (ж) with a breve accent, like so: "ӂ".
|
||||
</para>
|
||||
<para>
|
||||
Some fonts will provide this character as a single
|
||||
zhe-with-breve glyph, but other fonts will not and, instead,
|
||||
will expect the rendering engine to form the character by
|
||||
superimposing the separate "ж" and "˘"
|
||||
glyphs.
|
||||
</para>
|
||||
<para>
|
||||
But exactly where you should draw the breve depends on the
|
||||
height and width of the preceding zhe glyph. To find the
|
||||
right position, you need to consult the table inside
|
||||
the font (the <literal>GPOS</literal> table) that contains
|
||||
positioning information.
|
||||
In other words, <emphasis>text shaping tells you whether you
|
||||
have a precomposed glyph within your font or if you need to
|
||||
compose a glyph yourself out of combining marks—and,
|
||||
if so, where to position those marks.</emphasis>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
If tasks like these are something that you need to do, then you
|
||||
need a text shaping engine. You could use Uniscribe if you are
|
||||
writing Windows software; you could use CoreText on macOS; or
|
||||
you could use HarfBuzz.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
In the rest of this manual, the text will assume that the reader
|
||||
is that implementor of a text-layout engine.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="what-does-harfbuzz-do">
|
||||
<title>What does HarfBuzz do?</title>
|
||||
<para>
|
||||
HarfBuzz provides text shaping through a cross-platform
|
||||
C API that accepts sequences of Unicode codepoints as input. Currently,
|
||||
the following OpenType shaping models are supported:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Indic (covering Devanagari, Bengali, Gujarati,
|
||||
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
|
||||
Sinhala)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Arabic (covering Arabic, N'Ko, Syriac, and Mongolian)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Thai and Lao
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Khmer
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Myanmar
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Tibetan
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Hangul
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Hebrew
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The Universal Shaping Engine or <emphasis>USE</emphasis>
|
||||
(covering complex scripts not covered by the above shaping
|
||||
models)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
A default shaping model for non-complex scripts
|
||||
(covering Latin, Cyrillic, Greek, Armenian, Georgian, Tifinagh,
|
||||
and many others)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Emoji (including emoji modifier sequences, flag sequences,
|
||||
and ZWJ sequences)
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
In addition to OpenType shaping, HarfBuzz supports the latest
|
||||
version of Graphite shaping (the "Graphite 2" model) and AAT
|
||||
shaping.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz can read and understand TrueType fonts (.ttf), TrueType
|
||||
collections (.ttc), and OpenType fonts (.otf, including those
|
||||
fonts that contain TrueType-style outlines and those that
|
||||
contain PostScript CFF or CFF2 outlines).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
HarfBuzz is designed and tested to run on top of the FreeType
|
||||
font renderer. It can run on Linux, Android, Windows, macOS, and
|
||||
iOS systems.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In addition to its core shaping functionality, HarfBuzz provides
|
||||
functions for accessing other font features, including optional
|
||||
GSUB and GPOS OpenType features, as well as
|
||||
all color-font formats (<literal>CBDT</literal>,
|
||||
<literal>sbix</literal>, <literal>COLR/CPAL</literal>, and
|
||||
<literal>SVG-OT</literal>) and OpenType variable fonts. HarfBuzz
|
||||
also includes a font-subsetting feature. HarfBuzz can perform
|
||||
some low-level math-shaping operations, although it does not
|
||||
currently perform full shaping for mathematical typesetting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A suite of command-line utilities is also provided in the
|
||||
source-code tree, designed to help users test and debug
|
||||
HarfBuzz's features on real-world fonts and input.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="what-harfbuzz-doesnt-do">
|
||||
<title>What HarfBuzz doesn't do</title>
|
||||
<para>
|
||||
HarfBuzz will take a Unicode string, shape it, and give you the
|
||||
information required to lay it out correctly on a single
|
||||
horizontal (or vertical) line using the font provided. That is the
|
||||
extent of HarfBuzz's responsibility.
|
||||
</para>
|
||||
<para>
|
||||
It is important to note that if you are implementing a complete
|
||||
text-layout engine you may have other responsibilities that
|
||||
HarfBuzz will <emphasis>not</emphasis> help you with. For example:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with bidirectionality. If you want to
|
||||
lay out text that includes a mix of Hebrew and English, you
|
||||
will need to ensure that each buffer provided to HarfBuzz
|
||||
has all of its characters in the same order and that the
|
||||
directionality of the buffer is set correctly. This may mean
|
||||
segmenting the text before it is placed into HarfBuzz buffers. In
|
||||
other words, the user will hit the keys in the following
|
||||
sequence:
|
||||
</para>
|
||||
<programlisting>
|
||||
A B C [space] ג ב א [space] D E F
|
||||
</programlisting>
|
||||
<para>
|
||||
but will expect to see in the output:
|
||||
</para>
|
||||
<programlisting>
|
||||
ABC אבג DEF
|
||||
</programlisting>
|
||||
<para>
|
||||
This reordering is called <emphasis>bidi processing</emphasis>
|
||||
("bidi" is short for bidirectional), and there's an
|
||||
algorithm as an annex to the Unicode Standard which tells you how
|
||||
to process a string of mixed directionality.
|
||||
Before sending your string to HarfBuzz, you may need to apply the
|
||||
bidi algorithm to it. Libraries such as <ulink
|
||||
url="http://icu-project.org/">ICU</ulink> and <ulink
|
||||
url="http://fribidi.org/">fribidi</ulink> can do this for you.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with text that contains different font
|
||||
properties. For instance, if you have the string "a
|
||||
<emphasis>huge</emphasis> breakfast", and you expect
|
||||
"huge" to be italic, then you will need to send three
|
||||
strings to HarfBuzz: <literal>a</literal>, in your Roman font;
|
||||
<literal>huge</literal> using your italic font; and
|
||||
<literal>breakfast</literal> using your Roman font again.
|
||||
</para>
|
||||
<para>
|
||||
Similarly, if you change the font, font size, script,
|
||||
language, or direction within your string, then you will
|
||||
need to shape each run independently and output them
|
||||
independently. HarfBuzz expects to shape a run of characters
|
||||
that all share the same properties.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
HarfBuzz won't help you with line breaking, hyphenation, or
|
||||
justification. As mentioned above, HarfBuzz lays out the string
|
||||
along a <emphasis>single line</emphasis> of, notionally,
|
||||
infinite length. If you want to find out where the potential
|
||||
word, sentence and line break points are in your text, you
|
||||
could use the ICU library's break iterator functions.
|
||||
</para>
|
||||
<para>
|
||||
HarfBuzz can tell you how wide a shaped piece of text is, which is
|
||||
useful input to a justification algorithm, but it knows nothing
|
||||
about paragraphs, lines or line lengths. Nor will it adjust the
|
||||
space between words to fit them proportionally into a line.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
As a layout-engine implementor, HarfBuzz will help you with the
|
||||
interface between your text and your font, and that's something
|
||||
that you'll need—what you then do with the glyphs that your font
|
||||
returns is up to you.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="why-is-it-called-harfbuzz">
|
||||
<title>Why is it called HarfBuzz?</title>
|
||||
<para>
|
||||
HarfBuzz began its life as text-shaping code within the FreeType
|
||||
project (and you will see references to the FreeType authors
|
||||
within the source code copyright declarations), but was then
|
||||
extracted out to its own project. This project is maintained by
|
||||
Behdad Esfahbod, who named it HarfBuzz. Originally, it was a
|
||||
shaping engine for OpenType fonts—"HarfBuzz" is
|
||||
the Persian for "open type".
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
@ -1 +0,0 @@
|
||||
@HB_VERSION@
|
400
git.mk
400
git.mk
@ -1,400 +0,0 @@
|
||||
# git.mk, a small Makefile to autogenerate .gitignore files
|
||||
# for autotools-based projects.
|
||||
#
|
||||
# Copyright 2009, Red Hat, Inc.
|
||||
# Copyright 2010,2011,2012,2013 Behdad Esfahbod
|
||||
# Written by Behdad Esfahbod
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# is permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved.
|
||||
#
|
||||
# The latest version of this file can be downloaded from:
|
||||
GIT_MK_URL = https://raw.githubusercontent.com/behdad/git.mk/master/git.mk
|
||||
#
|
||||
# Bugs, etc, should be reported upstream at:
|
||||
# https://github.com/behdad/git.mk
|
||||
#
|
||||
# To use in your project, import this file in your git repo's toplevel,
|
||||
# then do "make -f git.mk". This modifies all Makefile.am files in
|
||||
# your project to -include git.mk. Remember to add that line to new
|
||||
# Makefile.am files you create in your project, or just rerun the
|
||||
# "make -f git.mk".
|
||||
#
|
||||
# This enables automatic .gitignore generation. If you need to ignore
|
||||
# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
|
||||
# But think twice before doing that. If a file has to be in .gitignore,
|
||||
# chances are very high that it's a generated file and should be in one
|
||||
# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
|
||||
#
|
||||
# The only case that you need to manually add a file to GITIGNOREFILES is
|
||||
# when remove files in one of mostlyclean-local, clean-local, distclean-local,
|
||||
# or maintainer-clean-local make targets.
|
||||
#
|
||||
# Note that for files like editor backup, etc, there are better places to
|
||||
# ignore them. See "man gitignore".
|
||||
#
|
||||
# If "make maintainer-clean" removes the files but they are not recognized
|
||||
# by this script (that is, if "git status" shows untracked files still), send
|
||||
# me the output of "git status" as well as your Makefile.am and Makefile for
|
||||
# the directories involved and I'll diagnose.
|
||||
#
|
||||
# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
|
||||
# Makefile.am.sample in the git.mk git repo.
|
||||
#
|
||||
# Don't EXTRA_DIST this file. It is supposed to only live in git clones,
|
||||
# not tarballs. It serves no useful purpose in tarballs and clutters the
|
||||
# build dir.
|
||||
#
|
||||
# This file knows how to handle autoconf, automake, libtool, gtk-doc,
|
||||
# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu, appdata,
|
||||
# appstream, hotdoc.
|
||||
#
|
||||
# This makefile provides the following targets:
|
||||
#
|
||||
# - all: "make all" will build all gitignore files.
|
||||
# - gitignore: makes all gitignore files in the current dir and subdirs.
|
||||
# - .gitignore: make gitignore file for the current dir.
|
||||
# - gitignore-recurse: makes all gitignore files in the subdirs.
|
||||
#
|
||||
# KNOWN ISSUES:
|
||||
#
|
||||
# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
|
||||
# submodule doesn't find us. If you have configure.{in,ac} files in
|
||||
# subdirs, add a proxy git.mk file in those dirs that simply does:
|
||||
# "include $(top_srcdir)/../git.mk". Add more ..'s to your taste.
|
||||
# And add those files to git. See vte/gnome-pty-helper/git.mk for
|
||||
# example.
|
||||
#
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Variables user modules may want to add to toplevel MAINTAINERCLEANFILES:
|
||||
###############################################################################
|
||||
|
||||
#
|
||||
# Most autotools-using modules should be fine including this variable in their
|
||||
# toplevel MAINTAINERCLEANFILES:
|
||||
GITIGNORE_MAINTAINERCLEANFILES_TOPLEVEL = \
|
||||
$(srcdir)/aclocal.m4 \
|
||||
$(srcdir)/autoscan.log \
|
||||
$(srcdir)/configure.scan \
|
||||
`AUX_DIR=$(srcdir)/$$(cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_AUX_DIR:$$1' ./configure.ac); \
|
||||
test "x$$AUX_DIR" = "x$(srcdir)/" && AUX_DIR=$(srcdir); \
|
||||
for x in \
|
||||
ar-lib \
|
||||
compile \
|
||||
config.guess \
|
||||
config.rpath \
|
||||
config.sub \
|
||||
depcomp \
|
||||
install-sh \
|
||||
ltmain.sh \
|
||||
missing \
|
||||
mkinstalldirs \
|
||||
test-driver \
|
||||
ylwrap \
|
||||
; do echo "$$AUX_DIR/$$x"; done` \
|
||||
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_HEADERS:$$1' ./configure.ac | \
|
||||
head -n 1 | while read f; do echo "$(srcdir)/$$f.in"; done`
|
||||
#
|
||||
# All modules should also be fine including the following variable, which
|
||||
# removes automake-generated Makefile.in files:
|
||||
GITIGNORE_MAINTAINERCLEANFILES_MAKEFILE_IN = \
|
||||
`cd $(top_srcdir); $(AUTOCONF) --trace 'AC_CONFIG_FILES:$$1' ./configure.ac | \
|
||||
while read f; do \
|
||||
case $$f in Makefile|*/Makefile) \
|
||||
test -f "$(srcdir)/$$f.am" && echo "$(srcdir)/$$f.in";; esac; \
|
||||
done`
|
||||
#
|
||||
# Modules that use libtool and use AC_CONFIG_MACRO_DIR() may also include this,
|
||||
# though it's harmless to include regardless.
|
||||
GITIGNORE_MAINTAINERCLEANFILES_M4_LIBTOOL = \
|
||||
`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 \
|
||||
libtool.m4 \
|
||||
ltoptions.m4 \
|
||||
ltsugar.m4 \
|
||||
ltversion.m4 \
|
||||
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`
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Default rule is to install ourselves in all Makefile.am files:
|
||||
###############################################################################
|
||||
|
||||
git-all: git-mk-install
|
||||
|
||||
git-mk-install:
|
||||
@echo "Installing git makefile"
|
||||
@any_failed=; \
|
||||
find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while read x; do \
|
||||
if grep 'include .*/git.mk' $$x >/dev/null; then \
|
||||
echo "$$x already includes git.mk"; \
|
||||
else \
|
||||
failed=; \
|
||||
echo "Updating $$x"; \
|
||||
{ cat $$x; \
|
||||
echo ''; \
|
||||
echo '-include $$(top_srcdir)/git.mk'; \
|
||||
} > $$x.tmp || failed=1; \
|
||||
if test x$$failed = x; then \
|
||||
mv $$x.tmp $$x || failed=1; \
|
||||
fi; \
|
||||
if test x$$failed = x; then : else \
|
||||
echo "Failed updating $$x"; >&2 \
|
||||
any_failed=1; \
|
||||
fi; \
|
||||
fi; done; test -z "$$any_failed"
|
||||
|
||||
git-mk-update:
|
||||
wget $(GIT_MK_URL) -O $(top_srcdir)/git.mk
|
||||
|
||||
.PHONY: git-all git-mk-install git-mk-update
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Actual .gitignore generation:
|
||||
###############################################################################
|
||||
|
||||
$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
|
||||
@echo "git.mk: Generating $@"
|
||||
@{ \
|
||||
if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
|
||||
for x in \
|
||||
$(DOC_MODULE)-decl-list.txt \
|
||||
$(DOC_MODULE)-decl.txt \
|
||||
tmpl/$(DOC_MODULE)-unused.sgml \
|
||||
"tmpl/*.bak" \
|
||||
$(REPORT_FILES) \
|
||||
$(DOC_MODULE).pdf \
|
||||
xml html \
|
||||
; do echo "/$$x"; done; \
|
||||
FLAVOR=$$(cd $(top_srcdir); $(AUTOCONF) --trace 'GTK_DOC_CHECK:$$2' ./configure.ac); \
|
||||
case $$FLAVOR in *no-tmpl*) echo /tmpl;; esac; \
|
||||
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-types"; then \
|
||||
echo "/$(DOC_MODULE).types"; \
|
||||
fi; \
|
||||
if echo "$(SCAN_OPTIONS)" | grep -q "\-\-rebuild-sections"; then \
|
||||
echo "/$(DOC_MODULE)-sections.txt"; \
|
||||
fi; \
|
||||
if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
|
||||
for x in \
|
||||
$(SETUP_FILES) \
|
||||
$(DOC_MODULE).types \
|
||||
; do echo "/$$x"; done; \
|
||||
fi; \
|
||||
fi; \
|
||||
if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
|
||||
for lc in $(DOC_LINGUAS); do \
|
||||
for x in \
|
||||
$(if $(DOC_MODULE),$(DOC_MODULE).xml) \
|
||||
$(DOC_PAGES) \
|
||||
$(DOC_INCLUDES) \
|
||||
; do echo "/$$lc/$$x"; done; \
|
||||
done; \
|
||||
for x in \
|
||||
$(_DOC_OMF_ALL) \
|
||||
$(_DOC_DSK_ALL) \
|
||||
$(_DOC_HTML_ALL) \
|
||||
$(_DOC_MOFILES) \
|
||||
$(DOC_H_FILE) \
|
||||
"*/.xml2po.mo" \
|
||||
"*/*.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 \
|
||||
$(HELP_FILES) \
|
||||
"$$lc.stamp" \
|
||||
"$$lc.mo" \
|
||||
; do echo "/$$lc/$$x"; done; \
|
||||
done; \
|
||||
fi; \
|
||||
if test "x$(gsettings_SCHEMAS)" = x; then :; else \
|
||||
for x in \
|
||||
$(gsettings_SCHEMAS:.xml=.valid) \
|
||||
$(gsettings__enum_file) \
|
||||
; do echo "/$$x"; done; \
|
||||
fi; \
|
||||
if test "x$(appdata_XML)" = x; then :; else \
|
||||
for x in \
|
||||
$(appdata_XML:.xml=.valid) \
|
||||
; do echo "/$$x"; done; \
|
||||
fi; \
|
||||
if test "x$(appstream_XML)" = x; then :; else \
|
||||
for x in \
|
||||
$(appstream_XML:.xml=.valid) \
|
||||
; do echo "/$$x"; done; \
|
||||
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 \
|
||||
po/Makefile \
|
||||
po/Makevars.template \
|
||||
po/POTFILES \
|
||||
po/Rules-quot \
|
||||
po/stamp-it \
|
||||
po/stamp-po \
|
||||
po/.intltool-merge-cache \
|
||||
"po/*.gmo" \
|
||||
"po/*.header" \
|
||||
"po/*.mo" \
|
||||
"po/*.sed" \
|
||||
"po/*.sin" \
|
||||
po/$(GETTEXT_PACKAGE).pot \
|
||||
intltool-extract.in \
|
||||
intltool-merge.in \
|
||||
intltool-update.in \
|
||||
; do echo "/$$x"; done; \
|
||||
fi; \
|
||||
if test -f $(srcdir)/configure; then \
|
||||
for x in \
|
||||
autom4te.cache \
|
||||
configure \
|
||||
config.h \
|
||||
stamp-h1 \
|
||||
libtool \
|
||||
config.lt \
|
||||
; do echo "/$$x"; done; \
|
||||
fi; \
|
||||
if test "x$(DEJATOOL)" = x; then :; else \
|
||||
for x in \
|
||||
$(DEJATOOL) \
|
||||
; do echo "/$$x.sum"; echo "/$$x.log"; done; \
|
||||
echo /site.exp; \
|
||||
fi; \
|
||||
if test "x$(am__dirstamp)" = x; then :; else \
|
||||
echo "$(am__dirstamp)"; \
|
||||
fi; \
|
||||
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" \
|
||||
; do echo "$$x"; done; \
|
||||
fi; \
|
||||
for x in \
|
||||
.gitignore \
|
||||
$(GITIGNOREFILES) \
|
||||
$(CLEANFILES) \
|
||||
$(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \
|
||||
$(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \
|
||||
$(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \
|
||||
so_locations \
|
||||
$(MOSTLYCLEANFILES) \
|
||||
$(TEST_LOGS) \
|
||||
$(TEST_LOGS:.log=.trs) \
|
||||
$(TEST_SUITE_LOG) \
|
||||
$(TESTS:=.test) \
|
||||
"*.gcda" \
|
||||
"*.gcno" \
|
||||
$(DISTCLEANFILES) \
|
||||
$(am__CONFIG_DISTCLEAN_FILES) \
|
||||
$(CONFIG_CLEAN_FILES) \
|
||||
TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
|
||||
"*.tab.c" \
|
||||
$(MAINTAINERCLEANFILES) \
|
||||
$(BUILT_SOURCES) \
|
||||
$(patsubst %.vala,%.c,$(filter %.vala,$(SOURCES))) \
|
||||
$(filter %_vala.stamp,$(DIST_COMMON)) \
|
||||
$(filter %.vapi,$(DIST_COMMON)) \
|
||||
$(filter $(addprefix %,$(notdir $(patsubst %.vapi,%.h,$(filter %.vapi,$(DIST_COMMON))))),$(DIST_COMMON)) \
|
||||
Makefile \
|
||||
Makefile.in \
|
||||
"*.orig" \
|
||||
"*.rej" \
|
||||
"*.bak" \
|
||||
"*~" \
|
||||
".*.sw[nop]" \
|
||||
".dirstamp" \
|
||||
; do echo "/$$x"; done; \
|
||||
for x in \
|
||||
"*.$(OBJEXT)" \
|
||||
$(DEPDIR) \
|
||||
; do echo "$$x"; done; \
|
||||
} | \
|
||||
sed "s@^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
|
||||
sed 's@/[.]/@/@g' | \
|
||||
LC_ALL=C sort | uniq > $@.tmp && \
|
||||
mv $@.tmp $@;
|
||||
|
||||
all: $(srcdir)/.gitignore gitignore-recurse-maybe
|
||||
gitignore: $(srcdir)/.gitignore gitignore-recurse
|
||||
|
||||
gitignore-recurse-maybe:
|
||||
@for subdir in $(DIST_SUBDIRS); do \
|
||||
case " $(SUBDIRS) " in \
|
||||
*" $$subdir "*) :;; \
|
||||
*) test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir");; \
|
||||
esac; \
|
||||
done
|
||||
gitignore-recurse:
|
||||
@for subdir in $(DIST_SUBDIRS); do \
|
||||
test "$$subdir" = . -o -e "$$subdir/.git" || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) gitignore || echo "Skipping $$subdir"); \
|
||||
done
|
||||
|
||||
maintainer-clean: gitignore-clean
|
||||
gitignore-clean:
|
||||
-rm -f $(srcdir)/.gitignore
|
||||
|
||||
.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe
|
BIN
harfbuzz-2.8.2.tar.xz
Normal file
BIN
harfbuzz-2.8.2.tar.xz
Normal file
Binary file not shown.
@ -1,24 +0,0 @@
|
||||
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||
xmlns="http://usefulinc.com/ns/doap#">
|
||||
|
||||
<name xml:lang="en">harfbuzz</name>
|
||||
<shortdesc xml:lang="en">Text shaping library</shortdesc>
|
||||
|
||||
<homepage
|
||||
rdf:resource="http://harfbuzz.org/" />
|
||||
<mailing-list
|
||||
rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
|
||||
<!--download-page
|
||||
rdf:resource=""/-->
|
||||
<bug-database
|
||||
rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />
|
||||
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Behdad Esfahbod</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:harfbuzz@behdad.org" />
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
</Project>
|
113
harfbuzz.spec
Normal file
113
harfbuzz.spec
Normal file
@ -0,0 +1,113 @@
|
||||
Name: harfbuzz
|
||||
Version: 2.8.2
|
||||
Release: 4
|
||||
Summary: A text shaping engine
|
||||
|
||||
License: MIT
|
||||
URL: https://harfbuzz.github.io/what-is-harfbuzz.html
|
||||
Source0: https://github.com/harfbuzz/harfbuzz/releases/download/2.8.2/%{name}-%{version}.tar.xz
|
||||
|
||||
Patch0001: backport-CVE-2022-33068.patch
|
||||
Patch0002: backport-0001-CVE-2023-25193.patch
|
||||
Patch0003: backport-0002-CVE-2023-25193.patch
|
||||
|
||||
BuildRequires: gcc-c++ freetype-devel cairo-devel glib2-devel graphite2-devel
|
||||
BuildRequires: gtk-doc libicu-devel gobject-introspection-devel
|
||||
Provides: harfbuzz-icu
|
||||
Obsoletes: harfbuzz-icu
|
||||
|
||||
%description
|
||||
HarfBuzz is a text-shaping engine. If you give HarfBuzz a font and a string
|
||||
containing a sequence of Unicode codepoints, HarfBuzz selects and positions
|
||||
the corresponding glyphs from the font, applying all of the necessary layout
|
||||
rules and font features. HarfBuzz then returns the string to you in the form
|
||||
that is correctly arranged for the language and writing system.
|
||||
|
||||
%package devel
|
||||
Summary: The development environment for %{name}
|
||||
Requires: %{name} = %{version}-%{release}
|
||||
|
||||
%description devel
|
||||
Header files and libraries for building a extension library for %{name}.
|
||||
|
||||
%package_help
|
||||
|
||||
%prep
|
||||
%autosetup -n %{name}-%{version} -p1
|
||||
|
||||
%build
|
||||
%configure --disable-static --with-graphite2 --with-gobject --enable-introspection
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%check
|
||||
make check
|
||||
|
||||
%install
|
||||
make install DESTDIR=$RPM_BUILD_ROOT INSTALL="install -p"
|
||||
%delete_la
|
||||
|
||||
%ldconfig_scriptlets
|
||||
|
||||
%files
|
||||
%doc AUTHORS NEWS
|
||||
%license COPYING
|
||||
%{_libdir}/libharfbuzz.so.*
|
||||
%{_libdir}/libharfbuzz-subset.so.*
|
||||
%{_libdir}/libharfbuzz-gobject.so.0*
|
||||
%{_libdir}/libharfbuzz-icu.so.*
|
||||
%dir %{_libdir}/girepository-1.0
|
||||
%{_libdir}/girepository-1.0/HarfBuzz-0.0.typelib
|
||||
|
||||
%files devel
|
||||
%{_bindir}/*
|
||||
%{_libdir}/*.so
|
||||
%{_libdir}/pkgconfig/*.pc
|
||||
%{_libdir}/cmake/harfbuzz/
|
||||
%{_includedir}/harfbuzz/
|
||||
%dir %{_datadir}/gir-1.0
|
||||
%{_datadir}/gir-1.0/HarfBuzz-0.0.gir
|
||||
|
||||
%files help
|
||||
%doc README
|
||||
%{_datadir}/gtk-doc/html/harfbuzz/*
|
||||
|
||||
%changelog
|
||||
* Wed Feb 15 2023 zhouwenpei <zhouwenpei1@h-partners.com> - 2.8.2-4
|
||||
- fix CVE-2023-25193
|
||||
|
||||
* Thu Jul 14 2022 zhouwenpei <zhouwenpei1@h-partners.com> - 2.8.2-3
|
||||
- fix CVE-2022-33068
|
||||
|
||||
* Tue May 24 2022 loong_C <loong_c@yeah.net> - 2.8.2-2
|
||||
- fix spec changelog date
|
||||
|
||||
* Fri Dec 03 2021 liuyumeng <liuyumeng5@huawei.com> - 2.8.2-1
|
||||
- update to harfbuzz-2.8.2-1
|
||||
|
||||
* Mon Jul 05 2021 wangkerong <wangkerong@huawei.com> - 2.8.1-2
|
||||
- enable make check
|
||||
|
||||
* Fri Jun 25 2021 wangkerong <wangkerong@huawei.com> - 2.8.1-1
|
||||
- update to 2.8.1
|
||||
|
||||
* Thu Jan 28 2021 zhanzhimin <zhanzhimin@huawei.com> - 2.7.4-1
|
||||
- update to 2.7.4
|
||||
|
||||
* Thu Sep 10 2020 chengguipeng <chengguipeng1@huawei.com> - 2.6.8-3
|
||||
- Type:bugfix
|
||||
- ID:NA
|
||||
- SUG:NA
|
||||
- DESC:modify source0 url
|
||||
|
||||
* Wed Jul 29 2020 hanhui <hanhui15@huawei.com> - 2.6.8-2
|
||||
- modify HarfBuzz-0.0.gir patch
|
||||
|
||||
* Tue Jul 21 2020 hanhui <hanhui15@huawei.com> - 2.6.8-1
|
||||
- Update to 2.6.8
|
||||
|
||||
* Mon Jun 15 2020 hanhui <hanhui15@huawei.com> - 2.6.1-1
|
||||
- Update to 2.6.1
|
||||
|
||||
* Mon Aug 26 2019 openEuler Buildteam <buildteam@openeuler.org> - 1.8.7-2
|
||||
- Package Init
|
4
harfbuzz.yaml
Normal file
4
harfbuzz.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
version_control: github
|
||||
src_repo: harfbuzz/harfbuzz
|
||||
tag_prefix: "^"
|
||||
seperator: "."
|
476
huawei_harfbuzz.patch
Normal file
476
huawei_harfbuzz.patch
Normal file
@ -0,0 +1,476 @@
|
||||
diff --git a/harfbuzz-2.8.2/src/hb-buffer.h b/harfbuzz-2.8.2/src/hb-buffer.h
|
||||
index 865ccb2..88f1f4c 100644
|
||||
--- a/harfbuzz-2.8.2/src/hb-buffer.h
|
||||
+++ b/harfbuzz-2.8.2/src/hb-buffer.h
|
||||
@@ -307,7 +307,8 @@ typedef enum { /*< flags >*/
|
||||
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
|
||||
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
|
||||
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
|
||||
- HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
|
||||
+ HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
|
||||
+ HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u
|
||||
} hb_buffer_flags_t;
|
||||
|
||||
HB_EXTERN void
|
||||
diff --git a/harfbuzz-2.8.2/src/hb-open-type.hh b/harfbuzz-2.8.2/src/hb-open-type.hh
|
||||
index 406771f..b8ac4c5 100644
|
||||
--- a/harfbuzz-2.8.2/src/hb-open-type.hh
|
||||
+++ b/harfbuzz-2.8.2/src/hb-open-type.hh
|
||||
@@ -575,8 +575,13 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
|
||||
{ return hb_sorted_array (this->arrayZ, len); }
|
||||
hb_sorted_array_t<const Type> as_array (unsigned int len) const
|
||||
{ return hb_sorted_array (this->arrayZ, len); }
|
||||
+#ifdef ENABLE_ICCARM
|
||||
+ operator hb_sorted_array_t<Type> () { return as_array (0); }
|
||||
+ operator hb_sorted_array_t<const Type> () const { return as_array (0); }
|
||||
+#else
|
||||
operator hb_sorted_array_t<Type> () { return as_array (); }
|
||||
operator hb_sorted_array_t<const Type> () const { return as_array (); }
|
||||
+#endif
|
||||
|
||||
template <typename T>
|
||||
Type &bsearch (unsigned int len, const T &x, Type ¬_found = Crap (Type))
|
||||
diff --git a/harfbuzz-2.8.2/src/hb-ot-color-sbix-table.hh b/harfbuzz-2.8.2/src/hb-ot-color-sbix-table.hh
|
||||
index af1e4a5..e085ee0 100644
|
||||
--- a/harfbuzz-2.8.2/src/hb-ot-color-sbix-table.hh
|
||||
+++ b/harfbuzz-2.8.2/src/hb-ot-color-sbix-table.hh
|
||||
@@ -298,6 +298,12 @@ struct sbix
|
||||
|
||||
const PNGHeader &png = *blob->as<PNGHeader>();
|
||||
|
||||
+ if ((png.IHDR.height >= 65536) | (png.IHDR.width >= 65536))
|
||||
+ {
|
||||
+ hb_blob_destroy (blob);
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
extents->x_bearing = x_offset;
|
||||
extents->y_bearing = png.IHDR.height + y_offset;
|
||||
extents->width = png.IHDR.width;
|
||||
diff --git a/harfbuzz-2.8.2/src/hb-ot-layout-common.hh b/harfbuzz-2.8.2/src/hb-ot-layout-common.hh
|
||||
index c78f820..c9d93a7 100644
|
||||
--- a/harfbuzz-2.8.2/src/hb-ot-layout-common.hh
|
||||
+++ b/harfbuzz-2.8.2/src/hb-ot-layout-common.hh
|
||||
@@ -445,6 +445,7 @@ struct RecordListOf : RecordArrayOf<Type>
|
||||
}
|
||||
};
|
||||
|
||||
+#ifndef ENABLE_ICCARM // Adaptive compilation, only changes the order of the code, does not affect the function
|
||||
struct Feature;
|
||||
|
||||
struct RecordListOfFeature : RecordListOf<Feature>
|
||||
@@ -797,7 +798,7 @@ struct Script
|
||||
};
|
||||
|
||||
typedef RecordListOfScript ScriptList;
|
||||
-
|
||||
+#endif // ENABLE_ICCARM
|
||||
|
||||
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
|
||||
struct FeatureParamsSize
|
||||
@@ -1081,6 +1082,52 @@ struct FeatureParams
|
||||
DEFINE_SIZE_MIN (0);
|
||||
};
|
||||
|
||||
+#ifdef ENABLE_ICCARM // Adaptive compilation, only changes the order of the code, does not affect the function
|
||||
+struct IndexArray : Array16Of<Index>
|
||||
+{
|
||||
+ bool intersects (const hb_map_t *indexes) const
|
||||
+ { return hb_any (*this, indexes); }
|
||||
+
|
||||
+ template <typename Iterator,
|
||||
+ hb_requires (hb_is_iterator (Iterator))>
|
||||
+ void serialize (hb_serialize_context_t *c,
|
||||
+ hb_subset_layout_context_t *l,
|
||||
+ Iterator it)
|
||||
+ {
|
||||
+ if (!it) return;
|
||||
+ if (unlikely (!c->extend_min ((*this)))) return;
|
||||
+
|
||||
+ for (const auto _ : it)
|
||||
+ {
|
||||
+ if (!l->visitLookupIndex()) break;
|
||||
+
|
||||
+ Index i;
|
||||
+ i = _;
|
||||
+ c->copy (i);
|
||||
+ this->len++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ unsigned int get_indexes (unsigned int start_offset,
|
||||
+ unsigned int *_count /* IN/OUT */,
|
||||
+ unsigned int *_indexes /* OUT */) const
|
||||
+ {
|
||||
+ if (_count)
|
||||
+ {
|
||||
+ + this->sub_array (start_offset, _count)
|
||||
+ | hb_sink (hb_array (_indexes, *_count))
|
||||
+ ;
|
||||
+ }
|
||||
+ return this->len;
|
||||
+ }
|
||||
+
|
||||
+ void add_indexes_to (hb_set_t* output /* OUT */) const
|
||||
+ {
|
||||
+ output->add_array (as_array ());
|
||||
+ }
|
||||
+};
|
||||
+#endif // ENABLE_ICCARM
|
||||
+
|
||||
struct Feature
|
||||
{
|
||||
unsigned int get_lookup_count () const
|
||||
@@ -1176,6 +1223,311 @@ struct Feature
|
||||
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
|
||||
};
|
||||
|
||||
+#ifdef ENABLE_ICCARM // Adaptive compilation, only changes the order of the code, does not affect the function
|
||||
+struct RecordListOfFeature : RecordListOf<Feature>
|
||||
+{
|
||||
+ bool subset (hb_subset_context_t *c,
|
||||
+ hb_subset_layout_context_t *l) const
|
||||
+ {
|
||||
+ TRACE_SUBSET (this);
|
||||
+ auto *out = c->serializer->start_embed (*this);
|
||||
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
+
|
||||
+ unsigned count = this->len;
|
||||
+ + hb_zip (*this, hb_range (count))
|
||||
+ | hb_filter (l->feature_index_map, hb_second)
|
||||
+ | hb_map (hb_first)
|
||||
+ | hb_apply (subset_record_array (l, out, this))
|
||||
+ ;
|
||||
+ return_trace (true);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+struct LangSys
|
||||
+{
|
||||
+ unsigned int get_feature_count () const
|
||||
+ { return featureIndex.len; }
|
||||
+ hb_tag_t get_feature_index (unsigned int i) const
|
||||
+ { return featureIndex[i]; }
|
||||
+ unsigned int get_feature_indexes (unsigned int start_offset,
|
||||
+ unsigned int *feature_count /* IN/OUT */,
|
||||
+ unsigned int *feature_indexes /* OUT */) const
|
||||
+ { return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
|
||||
+ void add_feature_indexes_to (hb_set_t *feature_indexes) const
|
||||
+ { featureIndex.add_indexes_to (feature_indexes); }
|
||||
+
|
||||
+ bool has_required_feature () const { return reqFeatureIndex != 0xFFFFu; }
|
||||
+ unsigned int get_required_feature_index () const
|
||||
+ {
|
||||
+ if (reqFeatureIndex == 0xFFFFu)
|
||||
+ return Index::NOT_FOUND_INDEX;
|
||||
+ return reqFeatureIndex;
|
||||
+ }
|
||||
+
|
||||
+ LangSys* copy (hb_serialize_context_t *c) const
|
||||
+ {
|
||||
+ TRACE_SERIALIZE (this);
|
||||
+ return_trace (c->embed (*this));
|
||||
+ }
|
||||
+
|
||||
+ bool compare (const LangSys& o, const hb_map_t *feature_index_map) const
|
||||
+ {
|
||||
+ if (reqFeatureIndex != o.reqFeatureIndex)
|
||||
+ return false;
|
||||
+
|
||||
+ auto iter =
|
||||
+ + hb_iter (featureIndex)
|
||||
+ | hb_filter (feature_index_map)
|
||||
+ | hb_map (feature_index_map)
|
||||
+ ;
|
||||
+
|
||||
+ auto o_iter =
|
||||
+ + hb_iter (o.featureIndex)
|
||||
+ | hb_filter (feature_index_map)
|
||||
+ | hb_map (feature_index_map)
|
||||
+ ;
|
||||
+
|
||||
+ if (iter.len () != o_iter.len ())
|
||||
+ return false;
|
||||
+
|
||||
+ for (const auto _ : + hb_zip (iter, o_iter))
|
||||
+ if (_.first != _.second) return false;
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ void collect_features (hb_prune_langsys_context_t *c) const
|
||||
+ {
|
||||
+ if (!has_required_feature () && !get_feature_count ()) return;
|
||||
+ if (c->visitedLangsys (this)) return;
|
||||
+ if (has_required_feature () &&
|
||||
+ c->duplicate_feature_map->has (reqFeatureIndex))
|
||||
+ c->new_feature_indexes->add (get_required_feature_index ());
|
||||
+
|
||||
+ + hb_iter (featureIndex)
|
||||
+ | hb_filter (c->duplicate_feature_map)
|
||||
+ | hb_sink (c->new_feature_indexes)
|
||||
+ ;
|
||||
+ }
|
||||
+
|
||||
+ bool subset (hb_subset_context_t *c,
|
||||
+ hb_subset_layout_context_t *l,
|
||||
+ const Tag *tag = nullptr) const
|
||||
+ {
|
||||
+ TRACE_SUBSET (this);
|
||||
+ auto *out = c->serializer->start_embed (*this);
|
||||
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
+
|
||||
+ out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu;
|
||||
+
|
||||
+ if (!l->visitFeatureIndex (featureIndex.len))
|
||||
+ return_trace (false);
|
||||
+
|
||||
+ auto it =
|
||||
+ + hb_iter (featureIndex)
|
||||
+ | hb_filter (l->feature_index_map)
|
||||
+ | hb_map (l->feature_index_map)
|
||||
+ ;
|
||||
+
|
||||
+ bool ret = bool (it);
|
||||
+ out->featureIndex.serialize (c->serializer, l, it);
|
||||
+ return_trace (ret);
|
||||
+ }
|
||||
+
|
||||
+ bool sanitize (hb_sanitize_context_t *c,
|
||||
+ const Record_sanitize_closure_t * = nullptr) const
|
||||
+ {
|
||||
+ TRACE_SANITIZE (this);
|
||||
+ return_trace (c->check_struct (this) && featureIndex.sanitize (c));
|
||||
+ }
|
||||
+
|
||||
+ Offset16 lookupOrderZ; /* = Null (reserved for an offset to a
|
||||
+ * reordering table) */
|
||||
+ HBUINT16 reqFeatureIndex;/* Index of a feature required for this
|
||||
+ * language system--if no required features
|
||||
+ * = 0xFFFFu */
|
||||
+ IndexArray featureIndex; /* Array of indices into the FeatureList */
|
||||
+ public:
|
||||
+ DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
|
||||
+};
|
||||
+DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
|
||||
+
|
||||
+struct Script
|
||||
+{
|
||||
+ unsigned int get_lang_sys_count () const
|
||||
+ { return langSys.len; }
|
||||
+ const Tag& get_lang_sys_tag (unsigned int i) const
|
||||
+ { return langSys.get_tag (i); }
|
||||
+ unsigned int get_lang_sys_tags (unsigned int start_offset,
|
||||
+ unsigned int *lang_sys_count /* IN/OUT */,
|
||||
+ hb_tag_t *lang_sys_tags /* OUT */) const
|
||||
+ { return langSys.get_tags (start_offset, lang_sys_count, lang_sys_tags); }
|
||||
+ const LangSys& get_lang_sys (unsigned int i) const
|
||||
+ {
|
||||
+ if (i == Index::NOT_FOUND_INDEX) return get_default_lang_sys ();
|
||||
+ return this+langSys[i].offset;
|
||||
+ }
|
||||
+ bool find_lang_sys_index (hb_tag_t tag, unsigned int *index) const
|
||||
+ { return langSys.find_index (tag, index); }
|
||||
+
|
||||
+ bool has_default_lang_sys () const { return defaultLangSys != 0; }
|
||||
+ const LangSys& get_default_lang_sys () const { return this+defaultLangSys; }
|
||||
+
|
||||
+ void prune_langsys (hb_prune_langsys_context_t *c,
|
||||
+ unsigned script_index) const
|
||||
+ {
|
||||
+ if (!has_default_lang_sys () && !get_lang_sys_count ()) return;
|
||||
+ if (c->visitedScript (this)) return;
|
||||
+
|
||||
+ if (!c->script_langsys_map->has (script_index))
|
||||
+ {
|
||||
+ hb_set_t* empty_set = hb_set_create ();
|
||||
+ if (unlikely (!c->script_langsys_map->set (script_index, empty_set)))
|
||||
+ {
|
||||
+ hb_set_destroy (empty_set);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ unsigned langsys_count = get_lang_sys_count ();
|
||||
+ if (has_default_lang_sys ())
|
||||
+ {
|
||||
+ //only collect features from non-redundant langsys
|
||||
+ const LangSys& d = get_default_lang_sys ();
|
||||
+ d.collect_features (c);
|
||||
+
|
||||
+ for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
|
||||
+ {
|
||||
+ const LangSys& l = this+_.first.offset;
|
||||
+ if (l.compare (d, c->duplicate_feature_map)) continue;
|
||||
+
|
||||
+ l.collect_features (c);
|
||||
+ c->script_langsys_map->get (script_index)->add (_.second);
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ for (auto _ : + hb_zip (langSys, hb_range (langsys_count)))
|
||||
+ {
|
||||
+ const LangSys& l = this+_.first.offset;
|
||||
+ l.collect_features (c);
|
||||
+ c->script_langsys_map->get (script_index)->add (_.second);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ bool subset (hb_subset_context_t *c,
|
||||
+ hb_subset_layout_context_t *l,
|
||||
+ const Tag *tag) const
|
||||
+ {
|
||||
+ TRACE_SUBSET (this);
|
||||
+ if (!l->visitScript ()) return_trace (false);
|
||||
+
|
||||
+ auto *out = c->serializer->start_embed (*this);
|
||||
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
+
|
||||
+ bool defaultLang = false;
|
||||
+ if (has_default_lang_sys ())
|
||||
+ {
|
||||
+ c->serializer->push ();
|
||||
+ const LangSys& ls = this+defaultLangSys;
|
||||
+ bool ret = ls.subset (c, l);
|
||||
+ if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T'))
|
||||
+ {
|
||||
+ c->serializer->pop_discard ();
|
||||
+ out->defaultLangSys = 0;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ());
|
||||
+ defaultLang = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index);
|
||||
+ if (active_langsys)
|
||||
+ {
|
||||
+ unsigned count = langSys.len;
|
||||
+ + hb_zip (langSys, hb_range (count))
|
||||
+ | hb_filter (active_langsys, hb_second)
|
||||
+ | hb_map (hb_first)
|
||||
+ | hb_filter ([=] (const Record<LangSys>& record) {return l->visitLangSys (); })
|
||||
+ | hb_apply (subset_record_array (l, &(out->langSys), this))
|
||||
+ ;
|
||||
+ }
|
||||
+
|
||||
+ return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB);
|
||||
+ }
|
||||
+
|
||||
+ bool sanitize (hb_sanitize_context_t *c,
|
||||
+ const Record_sanitize_closure_t * = nullptr) const
|
||||
+ {
|
||||
+ TRACE_SANITIZE (this);
|
||||
+ return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
|
||||
+ }
|
||||
+
|
||||
+ protected:
|
||||
+ Offset16To<LangSys>
|
||||
+ defaultLangSys; /* Offset to DefaultLangSys table--from
|
||||
+ * beginning of Script table--may be Null */
|
||||
+ RecordArrayOf<LangSys>
|
||||
+ langSys; /* Array of LangSysRecords--listed
|
||||
+ * alphabetically by LangSysTag */
|
||||
+ public:
|
||||
+ DEFINE_SIZE_ARRAY_SIZED (4, langSys);
|
||||
+};
|
||||
+struct RecordListOfScript : RecordListOf<Script>
|
||||
+{
|
||||
+ bool subset (hb_subset_context_t *c,
|
||||
+ hb_subset_layout_context_t *l) const
|
||||
+ {
|
||||
+ TRACE_SUBSET (this);
|
||||
+ auto *out = c->serializer->start_embed (*this);
|
||||
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||
+
|
||||
+ unsigned count = this->len;
|
||||
+ for (auto _ : + hb_zip (*this, hb_range (count)))
|
||||
+ {
|
||||
+ auto snap = c->serializer->snapshot ();
|
||||
+ l->cur_script_index = _.second;
|
||||
+ bool ret = _.first.subset (l, this);
|
||||
+ if (!ret) c->serializer->revert (snap);
|
||||
+ else out->len++;
|
||||
+ }
|
||||
+
|
||||
+ return_trace (true);
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+struct RangeRecord
|
||||
+{
|
||||
+ int cmp (hb_codepoint_t g) const
|
||||
+ { return g < first ? -1 : g <= last ? 0 : +1; }
|
||||
+
|
||||
+ bool sanitize (hb_sanitize_context_t *c) const
|
||||
+ {
|
||||
+ TRACE_SANITIZE (this);
|
||||
+ return_trace (c->check_struct (this));
|
||||
+ }
|
||||
+
|
||||
+ bool intersects (const hb_set_t *glyphs) const
|
||||
+ { return glyphs->intersects (first, last); }
|
||||
+
|
||||
+ template <typename set_t>
|
||||
+ bool collect_coverage (set_t *glyphs) const
|
||||
+ { return glyphs->add_range (first, last); }
|
||||
+
|
||||
+ HBGlyphID first; /* First GlyphID in the range */
|
||||
+ HBGlyphID last; /* Last GlyphID in the range */
|
||||
+ HBUINT16 value; /* Value */
|
||||
+ public:
|
||||
+ DEFINE_SIZE_STATIC (6);
|
||||
+};
|
||||
+DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
|
||||
+
|
||||
+typedef RecordListOfScript ScriptList;
|
||||
+#endif // ENABLE_ICCARM
|
||||
+
|
||||
typedef RecordListOf<Feature> FeatureList;
|
||||
|
||||
|
||||
diff --git a/harfbuzz-2.8.2/src/hb-ot-layout-gsubgpos.hh b/harfbuzz-2.8.2/src/hb-ot-layout-gsubgpos.hh
|
||||
index c17bf92..f046c08 100644
|
||||
--- a/harfbuzz-2.8.2/src/hb-ot-layout-gsubgpos.hh
|
||||
+++ b/harfbuzz-2.8.2/src/hb-ot-layout-gsubgpos.hh
|
||||
@@ -535,7 +535,17 @@ struct hb_ot_apply_context_t :
|
||||
bool prev ()
|
||||
{
|
||||
assert (num_items > 0);
|
||||
- while (idx > num_items - 1)
|
||||
+ /* The alternate condition below is faster at string boundaries,
|
||||
+ * but produces subpar "unsafe-to-concat" values. */
|
||||
+ unsigned stop = num_items - 1;
|
||||
+ if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
|
||||
+ stop = 1 - 1;
|
||||
+ /*When looking back, limit how far we search; this function is mostly
|
||||
+ * used for looking back for base glyphs when attaching marks. If we
|
||||
+ * don't limit, we can get O(n^2) behavior where n is the number of
|
||||
+ * consecutive marks. */
|
||||
+ stop = (unsigned) hb_max ((int) stop, (int) idx - HB_MAX_CONTEXT_LENGTH);
|
||||
+ while (idx > stop)
|
||||
{
|
||||
idx--;
|
||||
const hb_glyph_info_t &info = c->buffer->out_info[idx];
|
||||
diff --git a/harfbuzz-2.8.2/src/hb-static.cc b/harfbuzz-2.8.2/src/hb-static.cc
|
||||
index ec4b241..bef2ce9 100644
|
||||
--- a/harfbuzz-2.8.2/src/hb-static.cc
|
||||
+++ b/harfbuzz-2.8.2/src/hb-static.cc
|
||||
@@ -39,8 +39,13 @@
|
||||
#ifndef HB_NO_VISIBILITY
|
||||
#include "hb-ot-name-language-static.hh"
|
||||
|
||||
+#ifndef ENABLE_ICCARM
|
||||
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
|
||||
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
|
||||
+#else
|
||||
+uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {0};
|
||||
+/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {0};
|
||||
+#endif
|
||||
|
||||
DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF};
|
||||
DEFINE_NULL_NAMESPACE_BYTES (OT, VarIdx) = {0xFF,0xFF,0xFF,0xFF};
|
83
install.py
Executable file
83
install.py
Executable file
@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
# 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.
|
||||
|
||||
import tarfile
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
|
||||
def untar_file(tar_file_path, extract_path):
|
||||
try:
|
||||
tar_cmd = ['tar', '-xf', tar_file_path, '-C', extract_path]
|
||||
subprocess.run(tar_cmd, check=True)
|
||||
except Exception as e:
|
||||
print("tar error!")
|
||||
return
|
||||
|
||||
|
||||
def move_file(src_path, dst_path):
|
||||
files = [
|
||||
"backport-CVE-2022-33068.patch",
|
||||
"backport-0001-CVE-2023-25193.patch",
|
||||
"backport-0002-CVE-2023-25193.patch",
|
||||
"huawei_harfbuzz.patch"
|
||||
]
|
||||
for file in files:
|
||||
src_file = os.path.join(src_path, file)
|
||||
dst_file = os.path.join(dst_path, file)
|
||||
shutil.copy(src_file, dst_file)
|
||||
|
||||
|
||||
def apply_patch(patch_file, target_dir):
|
||||
try:
|
||||
if not os.path.exists(target_dir):
|
||||
return
|
||||
patch_cmd = ['patch', '-p1', "--fuzz=0", "--no-backup-if-mismatch", '-i', patch_file, '-d', target_dir]
|
||||
subprocess.run(patch_cmd, check=True)
|
||||
except Exception as e:
|
||||
print("apply_patch error!")
|
||||
return
|
||||
|
||||
|
||||
def do_patch(target_dir):
|
||||
patch_file = [
|
||||
"backport-CVE-2022-33068.patch",
|
||||
"backport-0001-CVE-2023-25193.patch",
|
||||
"backport-0002-CVE-2023-25193.patch",
|
||||
"huawei_harfbuzz.patch"
|
||||
]
|
||||
|
||||
for patch in patch_file:
|
||||
apply_patch(patch, target_dir)
|
||||
|
||||
|
||||
def main():
|
||||
harfbuzz_path = argparse.ArgumentParser()
|
||||
harfbuzz_path.add_argument('--gen-dir', help='generate path of log', required=True)
|
||||
harfbuzz_path.add_argument('--source-dir', help='generate path of log', required=True)
|
||||
args = harfbuzz_path.parse_args()
|
||||
tar_file_path = os.path.join(args.source_dir, "harfbuzz-2.8.2.tar.xz")
|
||||
target_dir = os.path.join(args.gen_dir, "harfbuzz-2.8.2")
|
||||
|
||||
untar_file(tar_file_path, args.gen_dir)
|
||||
move_file(args.source_dir, target_dir)
|
||||
do_patch(target_dir)
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -1,74 +0,0 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check whether the given FLAG works with the linker or gives an error.
|
||||
# (Warnings, however, are ignored)
|
||||
#
|
||||
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
|
||||
# success/failure.
|
||||
#
|
||||
# If EXTRA-FLAGS is defined, it is added to the linker's default flags
|
||||
# when the check is done. The check is thus made with the flags: "LDFLAGS
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_LINK_IFELSE.
|
||||
#
|
||||
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
|
||||
# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
|
||||
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# 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
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 5
|
||||
|
||||
AC_DEFUN([AX_CHECK_LINK_FLAG],
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS $4 $1"
|
||||
AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
LDFLAGS=$ax_check_save_flags])
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
])dnl AX_CHECK_LINK_FLAGS
|
@ -1,264 +0,0 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_code_coverage.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CODE_COVERAGE()
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Defines CODE_COVERAGE_CPPFLAGS, CODE_COVERAGE_CFLAGS,
|
||||
# CODE_COVERAGE_CXXFLAGS and CODE_COVERAGE_LIBS which should be included
|
||||
# in the CPPFLAGS, CFLAGS CXXFLAGS and LIBS/LIBADD variables of every
|
||||
# build target (program or library) which should be built with code
|
||||
# coverage support. Also defines CODE_COVERAGE_RULES which should be
|
||||
# substituted in your Makefile; and $enable_code_coverage which can be
|
||||
# used in subsequent configure output. CODE_COVERAGE_ENABLED is defined
|
||||
# and substituted, and corresponds to the value of the
|
||||
# --enable-code-coverage option, which defaults to being disabled.
|
||||
#
|
||||
# Test also for gcov program and create GCOV variable that could be
|
||||
# substituted.
|
||||
#
|
||||
# Note that all optimization flags in CFLAGS must be disabled when code
|
||||
# coverage is enabled.
|
||||
#
|
||||
# Usage example:
|
||||
#
|
||||
# configure.ac:
|
||||
#
|
||||
# AX_CODE_COVERAGE
|
||||
#
|
||||
# Makefile.am:
|
||||
#
|
||||
# @CODE_COVERAGE_RULES@
|
||||
# my_program_LIBS = ... $(CODE_COVERAGE_LIBS) ...
|
||||
# my_program_CPPFLAGS = ... $(CODE_COVERAGE_CPPFLAGS) ...
|
||||
# my_program_CFLAGS = ... $(CODE_COVERAGE_CFLAGS) ...
|
||||
# my_program_CXXFLAGS = ... $(CODE_COVERAGE_CXXFLAGS) ...
|
||||
#
|
||||
# This results in a "check-code-coverage" rule being added to any
|
||||
# Makefile.am which includes "@CODE_COVERAGE_RULES@" (assuming the module
|
||||
# has been configured with --enable-code-coverage). Running `make
|
||||
# check-code-coverage` in that directory will run the module's test suite
|
||||
# (`make check`) and build a code coverage report detailing the code which
|
||||
# was touched, then print the URI for the report.
|
||||
#
|
||||
# In earlier versions of this macro, CODE_COVERAGE_LDFLAGS was defined
|
||||
# instead of CODE_COVERAGE_LIBS. They are both still defined, but use of
|
||||
# CODE_COVERAGE_LIBS is preferred for clarity; CODE_COVERAGE_LDFLAGS is
|
||||
# deprecated. They have the same value.
|
||||
#
|
||||
# This code was derived from Makefile.decl in GLib, originally licenced
|
||||
# under LGPLv2.1+.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2012, 2016 Philip Withnall
|
||||
# Copyright (c) 2012 Xan Lopez
|
||||
# Copyright (c) 2012 Christian Persch
|
||||
# Copyright (c) 2012 Paolo Borelli
|
||||
# Copyright (c) 2012 Dan Winship
|
||||
# Copyright (c) 2015 Bastien ROUCARIES
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2.1 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#serial 25
|
||||
|
||||
AC_DEFUN([AX_CODE_COVERAGE],[
|
||||
dnl Check for --enable-code-coverage
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
|
||||
# allow to override gcov location
|
||||
AC_ARG_WITH([gcov],
|
||||
[AS_HELP_STRING([--with-gcov[=GCOV]], [use given GCOV for coverage (GCOV=gcov).])],
|
||||
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=$with_gcov],
|
||||
[_AX_CODE_COVERAGE_GCOV_PROG_WITH=gcov])
|
||||
|
||||
AC_MSG_CHECKING([whether to build with code coverage support])
|
||||
AC_ARG_ENABLE([code-coverage],
|
||||
AS_HELP_STRING([--enable-code-coverage],
|
||||
[Whether to enable code coverage support]),,
|
||||
enable_code_coverage=no)
|
||||
|
||||
AM_CONDITIONAL([CODE_COVERAGE_ENABLED], [test x$enable_code_coverage = xyes])
|
||||
AC_SUBST([CODE_COVERAGE_ENABLED], [$enable_code_coverage])
|
||||
AC_MSG_RESULT($enable_code_coverage)
|
||||
|
||||
AS_IF([ test "$enable_code_coverage" = "yes" ], [
|
||||
# check for gcov
|
||||
AC_CHECK_TOOL([GCOV],
|
||||
[$_AX_CODE_COVERAGE_GCOV_PROG_WITH],
|
||||
[:])
|
||||
AS_IF([test "X$GCOV" = "X:"],
|
||||
[AC_MSG_ERROR([gcov is needed to do coverage])])
|
||||
AC_SUBST([GCOV])
|
||||
|
||||
dnl Check if gcc is being used
|
||||
AS_IF([ test "$GCC" = "no" ], [
|
||||
AC_MSG_ERROR([not compiling with gcc, which is required for gcov code coverage])
|
||||
])
|
||||
|
||||
AC_CHECK_PROG([LCOV], [lcov], [lcov])
|
||||
AC_CHECK_PROG([GENHTML], [genhtml], [genhtml])
|
||||
|
||||
AS_IF([ test -z "$LCOV" ], [
|
||||
AC_MSG_ERROR([To enable code coverage reporting you must have lcov installed])
|
||||
])
|
||||
|
||||
AS_IF([ test -z "$GENHTML" ], [
|
||||
AC_MSG_ERROR([Could not find genhtml from the lcov package])
|
||||
])
|
||||
|
||||
dnl Build the code coverage flags
|
||||
dnl Define CODE_COVERAGE_LDFLAGS for backwards compatibility
|
||||
CODE_COVERAGE_CPPFLAGS="-DNDEBUG"
|
||||
CODE_COVERAGE_CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
CODE_COVERAGE_CXXFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
CODE_COVERAGE_LIBS="-lgcov"
|
||||
CODE_COVERAGE_LDFLAGS="$CODE_COVERAGE_LIBS"
|
||||
|
||||
AC_SUBST([CODE_COVERAGE_CPPFLAGS])
|
||||
AC_SUBST([CODE_COVERAGE_CFLAGS])
|
||||
AC_SUBST([CODE_COVERAGE_CXXFLAGS])
|
||||
AC_SUBST([CODE_COVERAGE_LIBS])
|
||||
AC_SUBST([CODE_COVERAGE_LDFLAGS])
|
||||
|
||||
[CODE_COVERAGE_RULES_CHECK='
|
||||
-$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) -k check
|
||||
$(A''M_V_at)$(MAKE) $(AM_MAKEFLAGS) code-coverage-capture
|
||||
']
|
||||
[CODE_COVERAGE_RULES_CAPTURE='
|
||||
$(code_coverage_v_lcov_cap)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --capture --output-file "$(CODE_COVERAGE_OUTPUT_FILE).tmp" --test-name "$(call code_coverage_sanitize,$(PACKAGE_NAME)-$(PACKAGE_VERSION))" --no-checksum --compat-libtool $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_OPTIONS)
|
||||
$(code_coverage_v_lcov_ign)$(LCOV) $(code_coverage_quiet) $(addprefix --directory ,$(CODE_COVERAGE_DIRECTORY)) --remove "$(CODE_COVERAGE_OUTPUT_FILE).tmp" "/tmp/*" $(CODE_COVERAGE_IGNORE_PATTERN) --output-file "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_LCOV_SHOPTS) $(CODE_COVERAGE_LCOV_RMOPTS)
|
||||
-@rm -f $(CODE_COVERAGE_OUTPUT_FILE).tmp
|
||||
$(code_coverage_v_genhtml)LANG=C $(GENHTML) $(code_coverage_quiet) $(addprefix --prefix ,$(CODE_COVERAGE_DIRECTORY)) --output-directory "$(CODE_COVERAGE_OUTPUT_DIRECTORY)" --title "$(PACKAGE_NAME)-$(PACKAGE_VERSION) Code Coverage" --legend --show-details "$(CODE_COVERAGE_OUTPUT_FILE)" $(CODE_COVERAGE_GENHTML_OPTIONS)
|
||||
@echo "file://$(abs_builddir)/$(CODE_COVERAGE_OUTPUT_DIRECTORY)/index.html"
|
||||
']
|
||||
[CODE_COVERAGE_RULES_CLEAN='
|
||||
clean: code-coverage-clean
|
||||
distclean: code-coverage-clean
|
||||
code-coverage-clean:
|
||||
-$(LCOV) --directory $(top_builddir) -z
|
||||
-rm -rf $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_FILE).tmp $(CODE_COVERAGE_OUTPUT_DIRECTORY)
|
||||
-find . \( -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" \) -delete
|
||||
']
|
||||
], [
|
||||
[CODE_COVERAGE_RULES_CHECK='
|
||||
@echo "Need to reconfigure with --enable-code-coverage"
|
||||
']
|
||||
CODE_COVERAGE_RULES_CAPTURE="$CODE_COVERAGE_RULES_CHECK"
|
||||
CODE_COVERAGE_RULES_CLEAN=''
|
||||
])
|
||||
|
||||
[CODE_COVERAGE_RULES='
|
||||
# Code coverage
|
||||
#
|
||||
# Optional:
|
||||
# - CODE_COVERAGE_DIRECTORY: Top-level directory for code coverage reporting.
|
||||
# Multiple directories may be specified, separated by whitespace.
|
||||
# (Default: $(top_builddir))
|
||||
# - CODE_COVERAGE_OUTPUT_FILE: Filename and path for the .info file generated
|
||||
# by lcov for code coverage. (Default:
|
||||
# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info)
|
||||
# - CODE_COVERAGE_OUTPUT_DIRECTORY: Directory for generated code coverage
|
||||
# reports to be created. (Default:
|
||||
# $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage)
|
||||
# - CODE_COVERAGE_BRANCH_COVERAGE: Set to 1 to enforce branch coverage,
|
||||
# set to 0 to disable it and leave empty to stay with the default.
|
||||
# (Default: empty)
|
||||
# - CODE_COVERAGE_LCOV_SHOPTS_DEFAULT: Extra options shared between both lcov
|
||||
# instances. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
|
||||
# - CODE_COVERAGE_LCOV_SHOPTS: Extra options to shared between both lcov
|
||||
# instances. (Default: $CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
|
||||
# - CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH: --gcov-tool pathtogcov
|
||||
# - CODE_COVERAGE_LCOV_OPTIONS_DEFAULT: Extra options to pass to the
|
||||
# collecting lcov instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
|
||||
# - CODE_COVERAGE_LCOV_OPTIONS: Extra options to pass to the collecting lcov
|
||||
# instance. (Default: $CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
|
||||
# - CODE_COVERAGE_LCOV_RMOPTS_DEFAULT: Extra options to pass to the filtering
|
||||
# lcov instance. (Default: empty)
|
||||
# - CODE_COVERAGE_LCOV_RMOPTS: Extra options to pass to the filtering lcov
|
||||
# instance. (Default: $CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
|
||||
# - CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT: Extra options to pass to the
|
||||
# genhtml instance. (Default: based on $CODE_COVERAGE_BRANCH_COVERAGE)
|
||||
# - CODE_COVERAGE_GENHTML_OPTIONS: Extra options to pass to the genhtml
|
||||
# instance. (Default: $CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
|
||||
# - CODE_COVERAGE_IGNORE_PATTERN: Extra glob pattern of files to ignore
|
||||
#
|
||||
# The generated report will be titled using the $(PACKAGE_NAME) and
|
||||
# $(PACKAGE_VERSION). In order to add the current git hash to the title,
|
||||
# use the git-version-gen script, available online.
|
||||
|
||||
# Optional variables
|
||||
CODE_COVERAGE_DIRECTORY ?= $(top_builddir)
|
||||
CODE_COVERAGE_OUTPUT_FILE ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage.info
|
||||
CODE_COVERAGE_OUTPUT_DIRECTORY ?= $(PACKAGE_NAME)-$(PACKAGE_VERSION)-coverage
|
||||
CODE_COVERAGE_BRANCH_COVERAGE ?=
|
||||
CODE_COVERAGE_LCOV_SHOPTS_DEFAULT ?= $(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
|
||||
--rc lcov_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
|
||||
CODE_COVERAGE_LCOV_SHOPTS ?= $(CODE_COVERAGE_LCOV_SHOPTS_DEFAULT)
|
||||
CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH ?= --gcov-tool "$(GCOV)"
|
||||
CODE_COVERAGE_LCOV_OPTIONS_DEFAULT ?= $(CODE_COVERAGE_LCOV_OPTIONS_GCOVPATH)
|
||||
CODE_COVERAGE_LCOV_OPTIONS ?= $(CODE_COVERAGE_LCOV_OPTIONS_DEFAULT)
|
||||
CODE_COVERAGE_LCOV_RMOPTS_DEFAULT ?=
|
||||
CODE_COVERAGE_LCOV_RMOPTS ?= $(CODE_COVERAGE_LCOV_RMOPTS_DEFAULT)
|
||||
CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT ?=\
|
||||
$(if $(CODE_COVERAGE_BRANCH_COVERAGE),\
|
||||
--rc genhtml_branch_coverage=$(CODE_COVERAGE_BRANCH_COVERAGE))
|
||||
CODE_COVERAGE_GENHTML_OPTIONS ?= $(CODE_COVERAGE_GENHTML_OPTIONS_DEFAULT)
|
||||
CODE_COVERAGE_IGNORE_PATTERN ?=
|
||||
|
||||
GITIGNOREFILES ?=
|
||||
GITIGNOREFILES += $(CODE_COVERAGE_OUTPUT_FILE) $(CODE_COVERAGE_OUTPUT_DIRECTORY)
|
||||
|
||||
code_coverage_v_lcov_cap = $(code_coverage_v_lcov_cap_$(V))
|
||||
code_coverage_v_lcov_cap_ = $(code_coverage_v_lcov_cap_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_v_lcov_cap_0 = @echo " LCOV --capture"\
|
||||
$(CODE_COVERAGE_OUTPUT_FILE);
|
||||
code_coverage_v_lcov_ign = $(code_coverage_v_lcov_ign_$(V))
|
||||
code_coverage_v_lcov_ign_ = $(code_coverage_v_lcov_ign_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_v_lcov_ign_0 = @echo " LCOV --remove /tmp/*"\
|
||||
$(CODE_COVERAGE_IGNORE_PATTERN);
|
||||
code_coverage_v_genhtml = $(code_coverage_v_genhtml_$(V))
|
||||
code_coverage_v_genhtml_ = $(code_coverage_v_genhtml_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_v_genhtml_0 = @echo " GEN " $(CODE_COVERAGE_OUTPUT_DIRECTORY);
|
||||
code_coverage_quiet = $(code_coverage_quiet_$(V))
|
||||
code_coverage_quiet_ = $(code_coverage_quiet_$(AM_DEFAULT_VERBOSITY))
|
||||
code_coverage_quiet_0 = --quiet
|
||||
|
||||
# sanitizes the test-name: replaces with underscores: dashes and dots
|
||||
code_coverage_sanitize = $(subst -,_,$(subst .,_,$(1)))
|
||||
|
||||
# Use recursive makes in order to ignore errors during check
|
||||
check-code-coverage:'"$CODE_COVERAGE_RULES_CHECK"'
|
||||
|
||||
# Capture code coverage data
|
||||
code-coverage-capture: code-coverage-capture-hook'"$CODE_COVERAGE_RULES_CAPTURE"'
|
||||
|
||||
# Hook rule executed before code-coverage-capture, overridable by the user
|
||||
code-coverage-capture-hook:
|
||||
|
||||
'"$CODE_COVERAGE_RULES_CLEAN"'
|
||||
|
||||
A''M_DISTCHECK_CONFIGURE_FLAGS ?=
|
||||
A''M_DISTCHECK_CONFIGURE_FLAGS += --disable-code-coverage
|
||||
|
||||
.PHONY: check-code-coverage code-coverage-capture code-coverage-capture-hook code-coverage-clean
|
||||
']
|
||||
|
||||
AC_SUBST([CODE_COVERAGE_RULES])
|
||||
m4_ifdef([_AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE([CODE_COVERAGE_RULES])])
|
||||
])
|
@ -1,982 +0,0 @@
|
||||
# ===========================================================================
|
||||
# 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, "");
|
||||
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||
// because of this.
|
||||
namespace test_template_alias_sfinae
|
||||
{
|
||||
|
||||
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
|
||||
|
||||
]])
|
485
m4/ax_pthread.m4
485
m4/ax_pthread.m4
@ -1,485 +0,0 @@
|
||||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# This macro figures out how to build C programs using POSIX threads. It
|
||||
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||
# flags that are needed. (The user can also force certain compiler
|
||||
# flags/libs to be tested by setting these environment variables.)
|
||||
#
|
||||
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||
# 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 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 threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# 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
|
||||
# PTHREAD_CFLAGS.
|
||||
#
|
||||
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||
# will define HAVE_PTHREAD.
|
||||
#
|
||||
# Please let the authors know if this macro fails on any platform, or if
|
||||
# you have any other suggestions or comments. This macro was based on work
|
||||
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||
# grateful for the helpful feedback of numerous users.
|
||||
#
|
||||
# Updated for Autoconf 2.68 by Daniel Richard G.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation, either version 3 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
# Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# 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
|
||||
# scripts that are the output of Autoconf when processing the Macro. You
|
||||
# need not follow the terms of the GNU General Public License when using
|
||||
# or distributing such scripts, even though portions of the text of the
|
||||
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||
# all other use of the material that constitutes the Autoconf Macro.
|
||||
#
|
||||
# This special exception to the GPL applies to versions of the Autoconf
|
||||
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#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 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_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"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
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
|
||||
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
|
||||
# names; the ordering is very important because some systems
|
||||
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||
# libraries is broken (non-POSIX).
|
||||
|
||||
# Create a list of thread flags to try. Items starting with a "-" are
|
||||
# C compiler flags, and other items are library names, except for "none"
|
||||
# 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 -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
|
||||
# pthreads: AIX (must check this before -lpthread)
|
||||
# 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)
|
||||
# -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 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
|
||||
|
||||
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. (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="-mt,pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
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 $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
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$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
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
|
||||
# need a special flag -Kthread to make this header compile.)
|
||||
# We check for pthread_join because it is in -lpthread on IRIX
|
||||
# while pthread_create is in libc. We check for pthread_attr_init
|
||||
# due to DEC craziness with -lpthreads. We check for
|
||||
# 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;
|
||||
pthread_create(&th, 0, start_routine, 0);
|
||||
pthread_join(th, 0);
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
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_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_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])
|
||||
])
|
||||
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
|
||||
])
|
||||
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
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])
|
||||
:
|
||||
else
|
||||
ax_pthread_ok=no
|
||||
$2
|
||||
fi
|
||||
AC_LANG_POP
|
||||
])dnl AX_PTHREAD
|
408
meson.build
408
meson.build
@ -1,408 +0,0 @@
|
||||
project('harfbuzz', 'c', 'cpp',
|
||||
meson_version: '>= 0.47.0',
|
||||
version: '2.8.1',
|
||||
default_options: [
|
||||
'cpp_eh=none', # Just to support msvc, we are passing -fno-rtti also anyway
|
||||
'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway
|
||||
'cpp_std=c++11',
|
||||
'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
|
||||
],
|
||||
)
|
||||
|
||||
hb_version_arr = meson.project_version().split('.')
|
||||
hb_version_major = hb_version_arr[0].to_int()
|
||||
hb_version_minor = hb_version_arr[1].to_int()
|
||||
hb_version_micro = hb_version_arr[2].to_int()
|
||||
|
||||
# libtool versioning
|
||||
hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro
|
||||
hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int)
|
||||
|
||||
pkgmod = import('pkgconfig')
|
||||
cpp = meson.get_compiler('cpp')
|
||||
null_dep = dependency('', required: false)
|
||||
|
||||
if cpp.get_id() == 'msvc'
|
||||
# Ignore several spurious warnings for things HarfBuzz does very commonly.
|
||||
# If a warning is completely useless and spammy, use '/wdXXXX' to suppress it
|
||||
# If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once
|
||||
# NOTE: Only add warnings here if you are sure they're spurious
|
||||
msvc_args = [
|
||||
'/wd4018', # implicit signed/unsigned conversion
|
||||
'/wd4146', # unary minus on unsigned (beware INT_MIN)
|
||||
'/wd4244', # lossy type conversion (e.g. double -> int)
|
||||
'/wd4305', # truncating type conversion (e.g. double -> float)
|
||||
cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8
|
||||
]
|
||||
add_project_arguments(msvc_args, language: ['c', 'cpp'])
|
||||
# Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW
|
||||
# noseh_link_args = ['/SAFESEH:NO']
|
||||
endif
|
||||
|
||||
add_project_link_arguments(cpp.get_supported_link_arguments([
|
||||
'-Bsymbolic-functions'
|
||||
]), language: 'c')
|
||||
|
||||
add_project_arguments(cpp.get_supported_arguments([
|
||||
'-fno-exceptions',
|
||||
'-fno-rtti',
|
||||
'-fno-threadsafe-statics',
|
||||
'-fvisibility-inlines-hidden',
|
||||
]), language: 'cpp')
|
||||
|
||||
if host_machine.cpu_family() == 'arm' and cpp.alignment('struct { char c; }') != 1
|
||||
if cpp.has_argument('-mstructure-size-boundary=8')
|
||||
add_project_arguments('-mstructure-size-boundary=8', language: 'cpp')
|
||||
endif
|
||||
endif
|
||||
|
||||
check_headers = [
|
||||
['unistd.h'],
|
||||
['sys/mman.h'],
|
||||
['stdbool.h'],
|
||||
]
|
||||
|
||||
check_funcs = [
|
||||
['atexit'],
|
||||
['mprotect'],
|
||||
['sysconf'],
|
||||
['getpagesize'],
|
||||
['mmap'],
|
||||
['isatty'],
|
||||
]
|
||||
|
||||
m_dep = cpp.find_library('m', required: false)
|
||||
|
||||
freetype_dep = null_dep
|
||||
if not get_option('freetype').disabled()
|
||||
freetype_dep = dependency('freetype2', required: false)
|
||||
|
||||
if (not freetype_dep.found() and
|
||||
cpp.get_id() == 'msvc' and
|
||||
cpp.has_header('ft2build.h'))
|
||||
freetype_dep = cpp.find_library('freetype', required: false)
|
||||
endif
|
||||
|
||||
if not freetype_dep.found()
|
||||
# https://github.com/harfbuzz/harfbuzz/pull/2498
|
||||
freetype_dep = dependency('freetype2', required: get_option('freetype'),
|
||||
fallback: ['freetype2', 'freetype_dep'],
|
||||
default_options: ['harfbuzz=disabled'])
|
||||
endif
|
||||
endif
|
||||
|
||||
glib_dep = dependency('glib-2.0', required: get_option('glib'),
|
||||
fallback: ['glib', 'libglib_dep'])
|
||||
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'),
|
||||
fallback: ['glib', 'libgobject_dep'])
|
||||
graphite2_dep = dependency('graphite2', required: get_option('graphite'))
|
||||
|
||||
icu_dep = null_dep
|
||||
if not get_option('icu').disabled()
|
||||
icu_dep = dependency('icu-uc', required: false)
|
||||
|
||||
if (not icu_dep.found() and
|
||||
cpp.get_id() == 'msvc' and
|
||||
cpp.has_header('unicode/uchar.h') and
|
||||
cpp.has_header('unicode/unorm2.h') and
|
||||
cpp.has_header('unicode/ustring.h') and
|
||||
cpp.has_header('unicode/utf16.h') and
|
||||
cpp.has_header('unicode/uversion.h') and
|
||||
cpp.has_header('unicode/uscript.h'))
|
||||
if get_option('buildtype') == 'debug'
|
||||
icu_dep = cpp.find_library('icuucd', required: false)
|
||||
else
|
||||
icu_dep = cpp.find_library('icuuc', required: false)
|
||||
endif
|
||||
endif
|
||||
|
||||
if not icu_dep.found()
|
||||
icu_dep = dependency('icu-uc', required: get_option('icu'))
|
||||
endif
|
||||
endif
|
||||
|
||||
cairo_dep = null_dep
|
||||
cairo_ft_dep = null_dep
|
||||
if not get_option('cairo').disabled()
|
||||
cairo_dep = dependency('cairo', required: false)
|
||||
cairo_ft_dep = dependency('cairo-ft', required: false)
|
||||
|
||||
if (not cairo_dep.found() and
|
||||
cpp.get_id() == 'msvc' and
|
||||
cpp.has_header('cairo.h'))
|
||||
cairo_dep = cpp.find_library('cairo', required: false)
|
||||
if cairo_dep.found() and cpp.has_function('cairo_ft_font_face_create_for_ft_face',
|
||||
prefix: '#include <cairo-ft.h>',
|
||||
dependencies: cairo_dep)
|
||||
cairo_ft_dep = cairo_dep
|
||||
endif
|
||||
endif
|
||||
|
||||
if not cairo_dep.found()
|
||||
# Requires Meson 0.54.0 to use cairo subproject
|
||||
if meson.version().version_compare('>=0.54.0')
|
||||
# Note that we don't have harfbuzz -> cairo -> freetype2 -> harfbuzz fallback
|
||||
# dependency cycle here because we have configured freetype2 above with
|
||||
# harfbuzz support disabled, so when cairo will lookup freetype2 dependency
|
||||
# it will be forced to use that one.
|
||||
cairo_dep = dependency('cairo', fallback: 'cairo', required: get_option('cairo'))
|
||||
cairo_ft_dep = dependency('cairo-ft', fallback: 'cairo', required: get_option('cairo'))
|
||||
elif get_option('cairo').enabled()
|
||||
error('cairo feature is enabled but it cannot be found on the system and ' +
|
||||
'meson>=0.54.0 is required to build it as subproject')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
chafa_dep = dependency('chafa', version: '>= 1.6.0', required: get_option('chafa'))
|
||||
|
||||
conf = configuration_data()
|
||||
incconfig = include_directories('.')
|
||||
|
||||
add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
|
||||
|
||||
warn_cflags = [
|
||||
'-Wno-non-virtual-dtor',
|
||||
]
|
||||
|
||||
cpp_args = cpp.get_supported_arguments(warn_cflags)
|
||||
|
||||
if glib_dep.found()
|
||||
conf.set('HAVE_GLIB', 1)
|
||||
endif
|
||||
|
||||
if gobject_dep.found()
|
||||
conf.set('HAVE_GOBJECT', 1)
|
||||
endif
|
||||
|
||||
if cairo_dep.found()
|
||||
conf.set('HAVE_CAIRO', 1)
|
||||
endif
|
||||
|
||||
if cairo_ft_dep.found()
|
||||
conf.set('HAVE_CAIRO_FT', 1)
|
||||
endif
|
||||
|
||||
if chafa_dep.found()
|
||||
conf.set('HAVE_CHAFA', 1)
|
||||
endif
|
||||
|
||||
if graphite2_dep.found()
|
||||
conf.set('HAVE_GRAPHITE2', 1)
|
||||
endif
|
||||
|
||||
if icu_dep.found()
|
||||
conf.set('HAVE_ICU', 1)
|
||||
endif
|
||||
|
||||
if get_option('icu_builtin')
|
||||
conf.set('HAVE_ICU_BUILTIN', 1)
|
||||
endif
|
||||
|
||||
if get_option('experimental_api')
|
||||
conf.set('HB_EXPERIMENTAL_API', 1)
|
||||
endif
|
||||
|
||||
if freetype_dep.found()
|
||||
conf.set('HAVE_FREETYPE', 1)
|
||||
check_freetype_funcs = [
|
||||
['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
|
||||
['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
|
||||
['FT_Done_MM_Var', {'deps': freetype_dep}],
|
||||
]
|
||||
|
||||
if freetype_dep.type_name() == 'internal'
|
||||
foreach func: check_freetype_funcs
|
||||
name = func[0]
|
||||
conf.set('HAVE_@0@'.format(name.to_upper()), 1)
|
||||
endforeach
|
||||
else
|
||||
check_funcs += check_freetype_funcs
|
||||
endif
|
||||
endif
|
||||
|
||||
gdi_uniscribe_deps = []
|
||||
# GDI (Uniscribe) (Windows)
|
||||
if host_machine.system() == 'windows' and not get_option('gdi').disabled()
|
||||
if (get_option('directwrite').enabled() and
|
||||
not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
|
||||
error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
|
||||
endif
|
||||
|
||||
gdi_deps_found = true
|
||||
foreach usplib : ['usp10', 'gdi32', 'rpcrt4']
|
||||
dep = cpp.find_library(usplib, required: get_option('gdi'))
|
||||
gdi_deps_found = gdi_deps_found and dep.found()
|
||||
gdi_uniscribe_deps += dep
|
||||
endforeach
|
||||
|
||||
if gdi_deps_found
|
||||
conf.set('HAVE_UNISCRIBE', 1)
|
||||
conf.set('HAVE_GDI', 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
# DirectWrite (Windows)
|
||||
directwrite_dep = null_dep
|
||||
if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
|
||||
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
|
||||
error('DirectWrite was enabled explicitly, but required header is missing.')
|
||||
endif
|
||||
|
||||
directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
|
||||
|
||||
if directwrite_dep.found()
|
||||
conf.set('HAVE_DIRECTWRITE', 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
# CoreText (macOS)
|
||||
coretext_deps = []
|
||||
if host_machine.system() == 'darwin' and not get_option('coretext').disabled()
|
||||
app_services_dep = dependency('appleframeworks', modules: ['ApplicationServices'], required: false)
|
||||
if cpp.has_type('CTFontRef', prefix: '#include <ApplicationServices/ApplicationServices.h>', dependencies: app_services_dep)
|
||||
coretext_deps += [app_services_dep]
|
||||
conf.set('HAVE_CORETEXT', 1)
|
||||
# On iOS CoreText and CoreGraphics are stand-alone frameworks
|
||||
# Check for a different symbol to avoid getting cached result
|
||||
else
|
||||
coretext_dep = dependency('appleframeworks', modules: ['CoreText'], required: false)
|
||||
coregraphics_dep = dependency('appleframeworks', modules: ['CoreGraphics'], required: false)
|
||||
corefoundation_dep = dependency('appleframeworks', modules: ['CoreFoundation'], required: false)
|
||||
if cpp.has_type('CTRunRef', prefix: '#include <CoreText/CoreText.h>', dependencies: [coretext_dep, coregraphics_dep, corefoundation_dep])
|
||||
coretext_deps += [coretext_dep, coregraphics_dep, corefoundation_dep]
|
||||
conf.set('HAVE_CORETEXT', 1)
|
||||
elif get_option('coretext').enabled()
|
||||
error('CoreText was enabled explicitly, but required headers or frameworks are missing.')
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# threads
|
||||
thread_dep = null_dep
|
||||
if host_machine.system() != 'windows'
|
||||
thread_dep = dependency('threads', required: false)
|
||||
|
||||
if thread_dep.found()
|
||||
conf.set('HAVE_PTHREAD', 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
conf.set_quoted('PACKAGE_NAME', 'HarfBuzz')
|
||||
conf.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
|
||||
foreach check : check_headers
|
||||
name = check[0]
|
||||
|
||||
if cpp.has_header(name)
|
||||
conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
harfbuzz_extra_deps = []
|
||||
foreach check : check_funcs
|
||||
name = check[0]
|
||||
opts = check.get(1, {})
|
||||
link_withs = opts.get('link_with', [])
|
||||
check_deps = opts.get('deps', [])
|
||||
extra_deps = []
|
||||
found = true
|
||||
|
||||
# First try without linking
|
||||
found = cpp.has_function(name, dependencies: check_deps)
|
||||
|
||||
if not found and link_withs.length() > 0
|
||||
found = true
|
||||
|
||||
foreach link_with : link_withs
|
||||
dep = cpp.find_library(link_with, required: false)
|
||||
if dep.found()
|
||||
extra_deps += dep
|
||||
else
|
||||
found = false
|
||||
endif
|
||||
endforeach
|
||||
|
||||
if found
|
||||
found = cpp.has_function(name, dependencies: check_deps + extra_deps)
|
||||
endif
|
||||
endif
|
||||
|
||||
if found
|
||||
harfbuzz_extra_deps += extra_deps
|
||||
conf.set('HAVE_@0@'.format(name.to_upper()), 1)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
subdir('src')
|
||||
subdir('util')
|
||||
|
||||
if not get_option('tests').disabled()
|
||||
subdir('test')
|
||||
endif
|
||||
|
||||
if not get_option('benchmark').disabled()
|
||||
subdir('perf')
|
||||
endif
|
||||
|
||||
if not get_option('docs').disabled()
|
||||
subdir('docs')
|
||||
endif
|
||||
|
||||
configure_file(output: 'config.h', configuration: conf)
|
||||
|
||||
build_summary = {
|
||||
'Directories':
|
||||
{'prefix': get_option('prefix'),
|
||||
'bindir': get_option('bindir'),
|
||||
'libdir': get_option('libdir'),
|
||||
'includedir': get_option('includedir'),
|
||||
'datadir': get_option('datadir'),
|
||||
},
|
||||
'Unicode callbacks (you want at least one)':
|
||||
{'Builtin': true,
|
||||
'Glib': conf.get('HAVE_GLIB', 0) == 1,
|
||||
'ICU': conf.get('HAVE_ICU', 0) == 1,
|
||||
},
|
||||
'Font callbacks (the more the merrier)':
|
||||
{'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
|
||||
},
|
||||
'Dependencies used for command-line utilities':
|
||||
{'Cairo': conf.get('HAVE_CAIRO', 0) == 1,
|
||||
'Chafa': conf.get('HAVE_CHAFA', 0) == 1,
|
||||
},
|
||||
'Additional shapers':
|
||||
{'Graphite2': conf.get('HAVE_GRAPHITE2', 0) == 1,
|
||||
},
|
||||
'Platform shapers (not normally needed)':
|
||||
{'CoreText': conf.get('HAVE_CORETEXT', 0) == 1,
|
||||
'DirectWrite': conf.get('HAVE_DIRECTWRITE', 0) == 1,
|
||||
'GDI/Uniscribe': (conf.get('HAVE_GDI', 0) == 1) and (conf.get('HAVE_UNISCRIBE', 0) == 1),
|
||||
},
|
||||
'Other features':
|
||||
{'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1,
|
||||
'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1,
|
||||
'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1,
|
||||
'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1,
|
||||
},
|
||||
'Testing':
|
||||
{'Tests': get_option('tests').enabled(),
|
||||
'Benchmark': get_option('benchmark').enabled(),
|
||||
},
|
||||
}
|
||||
if meson.version().version_compare('>=0.53')
|
||||
foreach section_title, section : build_summary
|
||||
summary(section, bool_yn: true, section: section_title)
|
||||
endforeach
|
||||
else
|
||||
summary = ['']
|
||||
foreach section_title, section : build_summary
|
||||
summary += ' @0@:'.format(section_title)
|
||||
foreach feature, value : section
|
||||
summary += ' @0@:'.format(feature)
|
||||
summary += ' @0@'.format(value)
|
||||
endforeach
|
||||
summary += ''
|
||||
endforeach
|
||||
message('\n'.join(summary))
|
||||
endif
|
@ -1,38 +0,0 @@
|
||||
# HarfBuzz feature options
|
||||
option('glib', type: 'feature', value: 'auto',
|
||||
description: 'Enable GLib unicode functions')
|
||||
option('gobject', type: 'feature', value: 'auto',
|
||||
description: 'Enable GObject bindings')
|
||||
option('cairo', type: 'feature', value: 'auto',
|
||||
description: 'Use Cairo graphics library')
|
||||
option('chafa', type: 'feature', value: 'auto',
|
||||
description: 'Use Chafa terminal graphics library')
|
||||
option('icu', type: 'feature', value: 'auto',
|
||||
description: 'Enable ICU library unicode functions')
|
||||
option('graphite', type: 'feature', value: 'disabled',
|
||||
description: 'Enable Graphite2 complementary shaper')
|
||||
option('freetype', type: 'feature', value: 'auto',
|
||||
description: 'Enable freetype interop helpers')
|
||||
option('gdi', type: 'feature', value: 'disabled',
|
||||
description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
|
||||
option('directwrite', type: 'feature', value: 'disabled',
|
||||
description: 'Enable DirectWrite shaper backend on Windows (experimental)')
|
||||
option('coretext', type: 'feature', value: 'disabled',
|
||||
description: 'Enable CoreText shaper backend on macOS')
|
||||
|
||||
# Common feature options
|
||||
option('tests', type: 'feature', value: 'enabled', yield: true,
|
||||
description: 'Enable or disable unit tests')
|
||||
option('introspection', type: 'feature', value: 'auto', yield: true,
|
||||
description: 'Generate gobject-introspection bindings (.gir/.typelib files)')
|
||||
option('docs', type: 'feature', value: 'auto', yield: true,
|
||||
description: 'Generate documentation with gtk-doc')
|
||||
|
||||
option('benchmark', type: 'feature', value: 'disabled',
|
||||
description: 'Enable benchmark tests')
|
||||
option('icu_builtin', type: 'boolean', value: false,
|
||||
description: 'Don\'t separate ICU support as harfbuzz-icu module')
|
||||
option('experimental_api', type: 'boolean', value: false,
|
||||
description: 'Enable experimental APIs')
|
||||
option('fuzzer_ldflags', type: 'string',
|
||||
description: 'Extra LDFLAGS used during linking of fuzzing binaries')
|
@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
case $1 in
|
||||
i686 | x86_64) ;;
|
||||
*) echo "Usage: $0 i686|x86_64" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
target=$1-w64-mingw32
|
||||
shift
|
||||
|
||||
exec "$(dirname "$0")"/configure \
|
||||
--build=`../config.guess` \
|
||||
--host=$target \
|
||||
--prefix=$HOME/.local/$target \
|
||||
CC= \
|
||||
CXX= \
|
||||
CPP= \
|
||||
LD= \
|
||||
CFLAGS="-static-libgcc" \
|
||||
CXXFLAGS="-static-libgcc -static-libstdc++" \
|
||||
CPPFLAGS="-I$HOME/.local/$target/include" \
|
||||
LDFLAGS=-L$HOME/.local/$target/lib \
|
||||
PKG_CONFIG_LIBDIR=$HOME/.local/$target/lib/pkgconfig:/usr/$target/sys-root/mingw/lib/pkgconfig/ \
|
||||
PKG_CONFIG_PATH=$HOME/.local/$target/share/pkgconfig:/usr/$target/sys-root/mingw/share/pkgconfig/ \
|
||||
PATH=$HOME/.local/$target/bin:/usr/$target/sys-root/mingw/bin:/usr/$target/bin:$PATH \
|
||||
--without-icu \
|
||||
--with-uniscribe \
|
||||
"$@"
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,27 +0,0 @@
|
||||
google_benchmark = subproject('google-benchmark')
|
||||
google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep')
|
||||
|
||||
ttf_parser_dep = null_dep
|
||||
if get_option('experimental_api') and add_languages('rust', required: false, native: true)
|
||||
ttf_parser_dep = subproject('ttf-parser').get_variable('ttf_parser_dep')
|
||||
endif
|
||||
|
||||
if ttf_parser_dep.found()
|
||||
benchmark_cpp_args = ['-DHAVE_TTFPARSER']
|
||||
else
|
||||
benchmark_cpp_args = []
|
||||
endif
|
||||
|
||||
benchmark('perf', executable('perf', 'perf.cc',
|
||||
dependencies: [
|
||||
google_benchmark_dep, freetype_dep,
|
||||
|
||||
# the last two, thread and dl, aren't nice as ttf-parser isn't no_std yet
|
||||
# https://github.com/RazrFalcon/ttf-parser/issues/29
|
||||
ttf_parser_dep, thread_dep, cpp.find_library('dl'),
|
||||
],
|
||||
cpp_args: benchmark_cpp_args,
|
||||
include_directories: [incconfig, incsrc],
|
||||
link_with: [libharfbuzz],
|
||||
install: false,
|
||||
), workdir: join_paths(meson.current_source_dir(), '..'), timeout: 100)
|
@ -1,177 +0,0 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "hb.h"
|
||||
#include "hb-ot.h"
|
||||
#include "hb-ft.h"
|
||||
#include FT_OUTLINE_H
|
||||
|
||||
#ifdef HAVE_TTFPARSER
|
||||
#include "ttfparser.h"
|
||||
#endif
|
||||
|
||||
#define HB_UNUSED __attribute__((unused))
|
||||
|
||||
static void
|
||||
_hb_move_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_hb_line_to (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_hb_quadratic_to (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_hb_cubic_to (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
|
||||
hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_hb_close_path (void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_ft_move_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_ft_line_to (const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_ft_conic_to (const FT_Vector* control HB_UNUSED, const FT_Vector* to HB_UNUSED,
|
||||
void* user HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_ft_cubic_to (const FT_Vector* control1 HB_UNUSED, const FT_Vector* control2 HB_UNUSED,
|
||||
const FT_Vector* to HB_UNUSED, void* user HB_UNUSED) {}
|
||||
|
||||
#ifdef HAVE_TTFPARSER
|
||||
static void _tp_move_to (float x HB_UNUSED, float y HB_UNUSED, void *data HB_UNUSED) {}
|
||||
static void _tp_line_to (float x, float y, void *data) {}
|
||||
static void _tp_quad_to (float x1, float y1, float x, float y, void *data) {}
|
||||
static void _tp_curve_to (float x1, float y1, float x2, float y2, float x, float y, void *data) {}
|
||||
static void _tp_close_path (void *data) {}
|
||||
#endif
|
||||
|
||||
static void draw (benchmark::State &state, const char *font_path, bool is_var, backend_t backend)
|
||||
{
|
||||
hb_font_t *font;
|
||||
unsigned num_glyphs;
|
||||
{
|
||||
hb_blob_t *blob = hb_blob_create_from_file (font_path);
|
||||
assert (hb_blob_get_length (blob));
|
||||
hb_face_t *face = hb_face_create (blob, 0);
|
||||
hb_blob_destroy (blob);
|
||||
num_glyphs = hb_face_get_glyph_count (face);
|
||||
font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
if (backend == HARFBUZZ)
|
||||
{
|
||||
if (is_var)
|
||||
{
|
||||
hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
|
||||
hb_font_set_variations (font, &wght, 1);
|
||||
}
|
||||
hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
|
||||
hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to);
|
||||
hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to);
|
||||
hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to);
|
||||
hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to);
|
||||
hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path);
|
||||
|
||||
for (auto _ : state)
|
||||
for (unsigned gid = 0; gid < num_glyphs; ++gid)
|
||||
hb_font_draw_glyph (font, gid, draw_funcs, nullptr);
|
||||
|
||||
hb_draw_funcs_destroy (draw_funcs);
|
||||
}
|
||||
else if (backend == FREETYPE)
|
||||
{
|
||||
if (is_var)
|
||||
{
|
||||
hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
|
||||
hb_font_set_variations (font, &wght, 1);
|
||||
}
|
||||
hb_ft_font_set_funcs (font);
|
||||
FT_Face ft_face = hb_ft_font_get_face (font);
|
||||
hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
|
||||
|
||||
FT_Outline_Funcs draw_funcs;
|
||||
draw_funcs.move_to = (FT_Outline_MoveToFunc) _ft_move_to;
|
||||
draw_funcs.line_to = (FT_Outline_LineToFunc) _ft_line_to;
|
||||
draw_funcs.conic_to = (FT_Outline_ConicToFunc) _ft_conic_to;
|
||||
draw_funcs.cubic_to = (FT_Outline_CubicToFunc) _ft_cubic_to;
|
||||
draw_funcs.shift = 0;
|
||||
draw_funcs.delta = 0;
|
||||
|
||||
for (auto _ : state)
|
||||
for (unsigned gid = 0; gid < num_glyphs; ++gid)
|
||||
{
|
||||
FT_Load_Glyph (ft_face, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
|
||||
FT_Outline_Decompose (&ft_face->glyph->outline, &draw_funcs, nullptr);
|
||||
}
|
||||
}
|
||||
else if (backend == TTF_PARSER)
|
||||
{
|
||||
#ifdef HAVE_TTFPARSER
|
||||
ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ());
|
||||
hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font));
|
||||
assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font));
|
||||
if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500);
|
||||
|
||||
ttfp_outline_builder builder;
|
||||
builder.move_to = _tp_move_to;
|
||||
builder.line_to = _tp_line_to;
|
||||
builder.quad_to = _tp_quad_to;
|
||||
builder.curve_to = _tp_curve_to;
|
||||
builder.close_path = _tp_close_path;
|
||||
|
||||
ttfp_rect bbox;
|
||||
for (auto _ : state)
|
||||
for (unsigned gid = 0; gid < num_glyphs; ++gid)
|
||||
ttfp_outline_glyph (tp_font, builder, &builder, gid, &bbox);
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
free (tp_font);
|
||||
#endif
|
||||
}
|
||||
else abort ();
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
#define FONT_BASE_PATH "test/subset/data/fonts/"
|
||||
|
||||
BENCHMARK_CAPTURE (draw, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (draw, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (draw, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (draw, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER);
|
@ -1,98 +0,0 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "hb.h"
|
||||
#include "hb-ft.h"
|
||||
#include "hb-ot.h"
|
||||
|
||||
#ifdef HAVE_TTFPARSER
|
||||
#include "ttfparser.h"
|
||||
#endif
|
||||
|
||||
static void extents (benchmark::State &state, const char *font_path, bool is_var, backend_t backend)
|
||||
{
|
||||
hb_font_t *font;
|
||||
unsigned num_glyphs;
|
||||
{
|
||||
hb_blob_t *blob = hb_blob_create_from_file (font_path);
|
||||
assert (hb_blob_get_length (blob));
|
||||
hb_face_t *face = hb_face_create (blob, 0);
|
||||
hb_blob_destroy (blob);
|
||||
num_glyphs = hb_face_get_glyph_count (face);
|
||||
font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
if (is_var)
|
||||
{
|
||||
hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
|
||||
hb_font_set_variations (font, &wght, 1);
|
||||
}
|
||||
|
||||
if (backend == HARFBUZZ || backend == FREETYPE)
|
||||
{
|
||||
if (backend == FREETYPE)
|
||||
{
|
||||
hb_ft_font_set_funcs (font);
|
||||
hb_ft_font_set_load_flags (font, FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE);
|
||||
}
|
||||
|
||||
hb_glyph_extents_t extents;
|
||||
for (auto _ : state)
|
||||
for (unsigned gid = 0; gid < num_glyphs; ++gid)
|
||||
hb_font_get_glyph_extents (font, gid, &extents);
|
||||
}
|
||||
else if (backend == TTF_PARSER)
|
||||
{
|
||||
#ifdef HAVE_TTFPARSER
|
||||
ttfp_face *tp_font = (ttfp_face *) malloc (ttfp_face_size_of ());
|
||||
hb_blob_t *blob = hb_face_reference_blob (hb_font_get_face (font));
|
||||
assert (ttfp_face_init (hb_blob_get_data (blob, nullptr), hb_blob_get_length (blob), 0, tp_font));
|
||||
if (is_var) ttfp_set_variation (tp_font, TTFP_TAG('w','g','h','t'), 500);
|
||||
|
||||
ttfp_rect bbox;
|
||||
for (auto _ : state)
|
||||
for (unsigned gid = 0; gid < num_glyphs; ++gid)
|
||||
ttfp_get_glyph_bbox(tp_font, gid, &bbox);
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
free (tp_font);
|
||||
#endif
|
||||
}
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
#define FONT_BASE_PATH "test/subset/data/fonts/"
|
||||
|
||||
BENCHMARK_CAPTURE (extents, cff - ot - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, cff - ft - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, cff - tp - SourceSansPro, FONT_BASE_PATH "SourceSansPro-Regular.otf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, cff2 - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, cff2 - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, cff2 - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, cff2/vf - ot - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, cff2/vf - ft - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, cff2/vf - tp - AdobeVFPrototype, FONT_BASE_PATH "AdobeVFPrototype.otf", true, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, glyf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, glyf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, glyf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, glyf/vf - ot - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, glyf/vf - ft - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, glyf/vf - tp - SourceSerifVariable, FONT_BASE_PATH "SourceSerifVariable-Roman.ttf", true, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, glyf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, glyf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, glyf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", false, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, glyf/vf - ot - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, glyf/vf - ft - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, glyf/vf - tp - Comfortaa, FONT_BASE_PATH "Comfortaa-Regular-new.ttf", true, TTF_PARSER);
|
||||
|
||||
BENCHMARK_CAPTURE (extents, glyf - ot - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, HARFBUZZ);
|
||||
BENCHMARK_CAPTURE (extents, glyf - ft - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, FREETYPE);
|
||||
BENCHMARK_CAPTURE (extents, glyf - tp - Roboto, FONT_BASE_PATH "Roboto-Regular.ttf", false, TTF_PARSER);
|
||||
|
@ -1,65 +0,0 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
static void shape (benchmark::State &state, const char *text_path,
|
||||
hb_direction_t direction, hb_script_t script,
|
||||
const char *font_path)
|
||||
{
|
||||
hb_font_t *font;
|
||||
{
|
||||
hb_blob_t *blob = hb_blob_create_from_file (font_path);
|
||||
assert (hb_blob_get_length (blob));
|
||||
hb_face_t *face = hb_face_create (blob, 0);
|
||||
hb_blob_destroy (blob);
|
||||
font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
hb_blob_t *text_blob = hb_blob_create_from_file (text_path);
|
||||
unsigned text_length;
|
||||
const char *text = hb_blob_get_data (text_blob, &text_length);
|
||||
assert (text_length);
|
||||
|
||||
hb_buffer_t *buf = hb_buffer_create ();
|
||||
for (auto _ : state)
|
||||
{
|
||||
hb_buffer_add_utf8 (buf, text, text_length, 0, -1);
|
||||
hb_buffer_set_direction (buf, direction);
|
||||
hb_buffer_set_script (buf, script);
|
||||
hb_shape (font, buf, nullptr, 0);
|
||||
hb_buffer_clear_contents (buf);
|
||||
}
|
||||
hb_buffer_destroy (buf);
|
||||
|
||||
hb_blob_destroy (text_blob);
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - Amiri,
|
||||
"perf/texts/fa-thelittleprince.txt",
|
||||
HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
|
||||
"perf/fonts/Amiri-Regular.ttf");
|
||||
BENCHMARK_CAPTURE (shape, fa-thelittleprince.txt - NotoNastaliqUrdu,
|
||||
"perf/texts/fa-thelittleprince.txt",
|
||||
HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
|
||||
"perf/fonts/NotoNastaliqUrdu-Regular.ttf");
|
||||
|
||||
BENCHMARK_CAPTURE (shape, fa-monologue.txt - Amiri,
|
||||
"perf/texts/fa-monologue.txt",
|
||||
HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
|
||||
"perf/fonts/Amiri-Regular.ttf");
|
||||
BENCHMARK_CAPTURE (shape, fa-monologue.txt - NotoNastaliqUrdu,
|
||||
"perf/texts/fa-monologue.txt",
|
||||
HB_DIRECTION_RTL, HB_SCRIPT_ARABIC,
|
||||
"perf/fonts/NotoNastaliqUrdu-Regular.ttf");
|
||||
|
||||
BENCHMARK_CAPTURE (shape, en-thelittleprince.txt - Roboto,
|
||||
"perf/texts/en-thelittleprince.txt",
|
||||
HB_DIRECTION_LTR, HB_SCRIPT_LATIN,
|
||||
"perf/fonts/Roboto-Regular.ttf");
|
||||
|
||||
BENCHMARK_CAPTURE (shape, en-words.txt - Roboto,
|
||||
"perf/texts/en-words.txt",
|
||||
HB_DIRECTION_LTR, HB_SCRIPT_LATIN,
|
||||
"perf/fonts/Roboto-Regular.ttf");
|
16
perf/perf.cc
16
perf/perf.cc
@ -1,16 +0,0 @@
|
||||
#include "benchmark/benchmark.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "perf-shaping.hh"
|
||||
#ifdef HAVE_FREETYPE
|
||||
enum backend_t { HARFBUZZ, FREETYPE, TTF_PARSER };
|
||||
#include "perf-extents.hh"
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
#include "perf-draw.hh"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
BENCHMARK_MAIN ();
|
25
perf/run.sh
25
perf/run.sh
@ -1,25 +0,0 @@
|
||||
#!/bin/bash
|
||||
CXX=clang++
|
||||
FONT=fonts/NotoNastaliqUrdu-Regular.ttf
|
||||
TEXT=texts/fa-monologue.txt
|
||||
|
||||
$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \
|
||||
-lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \
|
||||
-I../src $FLAGS $SOURCES \
|
||||
-DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \
|
||||
-DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \
|
||||
-o hb-shape -g -O2 # -O3 \
|
||||
#-march=native -mtune=native \
|
||||
#-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \
|
||||
#-Rpass-analysis=loop-vectorize -fsave-optimization-record
|
||||
|
||||
# -march=native: enable all vector instructions current CPU can offer
|
||||
# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics
|
||||
|
||||
#sudo rm capture.syscap > /dev/null
|
||||
#sysprof-cli -c "./a.out $@"
|
||||
#sysprof capture.syscap
|
||||
|
||||
perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
|
||||
#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
|
||||
#perf report -g
|
File diff suppressed because it is too large
Load Diff
12391
perf/texts/en-words.txt
12391
perf/texts/en-words.txt
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,923 +0,0 @@
|
||||
شازده کوچولو
|
||||
اثر آنتوان دو سنتگزوپهری
|
||||
برگردان احمد شاملو
|
||||
|
||||
|
||||
اهدانامچه
|
||||
به لئون ورث Leon Werth
|
||||
از بچهها عذر میخواهم که این کتاب را به یکی از بزرگترها هدیه کردهام. برای این کار یک دلیل حسابی دارم: این «بزرگتر» بهترین دوست من تو همه دنیا است. یک دلیل دیگرم هم آن که این «بزرگتر» همه چیز را میتواند بفهمد حتا کتابهایی را که برای بچهها نوشته باشند. عذر سومم این است که این «بزرگتر» تو فرانسه زندگی میکند و آنجا گشنگی و تشنگی میکشد و سخت محتاج دلجویی است. اگر همهی این عذرها کافی نباشد اجازه میخواهم این کتاب را تقدیم آن بچهای کنم که این آدمبزرگ یک روزی بوده. آخر هر آدم بزرگی هم روزی روزگاری بچهای بوده (گیرم کمتر کسی از آنها این را به یاد میآورد). پس من هم اهدانامچهام را به این شکل تصحیح میکنم:
|
||||
|
||||
به لئون ورث
|
||||
موقعی که پسربچه بود
|
||||
آنتوان دو سنتگزوپهری
|
||||
|
||||
من هم برگردان فارسی این شعر بزرگ را به دو بچهی دوستداشتنی دیگر تقدیم میکنم: دکتر جهانگیر کازرونی و دکتر محمدجواد گلبن
|
||||
|
||||
احمد شاملو
|
||||
|
||||
۱
|
||||
یک بار شش سالم که بود تو کتابی به اسم قصههای واقعی -که دربارهی جنگل بِکر نوشته شده بود- تصویر محشری دیدم از یک مار بوآ که داشت حیوانی را میبلعید. آن تصویر یک چنین چیزی بود:
|
||||
|
||||
یک مار بوآ که دارد حیوانی را میبلعد
|
||||
تو کتاب آمده بود که: «مارهای بوآ شکارشان را همین جور درسته قورت میدهند. بی این که بجوندش. بعد دیگر نمیتوانند از جا بجنبند و تمام شش ماهی را که هضمش طول میکشد میگیرند میخوابند».
|
||||
|
||||
این را که خواندم، راجع به چیزهایی که تو جنگل اتفاق میافتد کلی فکر کردم و دست آخر توانستم با یک مداد رنگی اولین نقاشیم را از کار درآرم. یعنی نقاشی شمارهی یکم را که این جوری بود:
|
||||
|
||||
نقاشی شمارهی یکم — مار شبیه به کلاه
|
||||
شاهکارم را نشان بزرگتر ها دادم و پرسیدم از دیدنش ترستان بر میدارد؟
|
||||
جوابم دادند: -چرا کلاه باید آدم را بترساند؟
|
||||
|
||||
نقاشی من کلاه نبود، یک مار بوآ بود که داشت یک فیل را هضم میکرد. آن وقت برای فهم بزرگترها برداشتم توی شکم بوآ را کشیدم. آخر همیشه باید به آنها توضیحات داد. نقاشی دومم این جوری بود:
|
||||
|
||||
نقاشی دوم — مار و فیل درونش
|
||||
بزرگترها بم گفتند کشیدن مار بوآی باز یا بسته را بگذارم کنار و عوضش حواسم را بیشتر جمع جغرافی و تاریخ و حساب و دستور زبان کنم. و این جوری شد که تو شش سالگی دور کار ظریف نقاشی را قلم گرفتم. از این که نقاشی شمارهی یک و نقاشی شمارهی دو ام یخشان نگرفت دلسرد شده بودم. بزرگترها اگر به خودشان باشد هیچ وقت نمیتوانند از چیزی سر درآرند. برای بچهها هم خسته کننده است که همین جور مدام هر چیزی را به آنها توضیح بدهند.
|
||||
|
||||
ناچار شدم برای خودم کار دیگری پیدا کنم و این بود که رفتم خلبانی یاد گرفتم. بگویی نگویی تا حالا به همه جای دنیا پرواز کرده ام و راستی راستی جغرافی خیلی بم خدمت کرده. میتوانم به یک نظر چین و آریزونا را از هم تمیز بدهم. اگر آدم تو دل شب سرگردان شده باشد جغرافی خیلی به دادش میرسد.
|
||||
|
||||
از این راه است که من تو زندگیم با گروه گروه آدمهای حسابی برخورد داشتهام. پیش خیلی از بزرگترها زندگی کردهام و آنها را از خیلی نزدیک دیدهام گیرم این موضوع باعث نشده در بارهی آنها عقیدهی بهتری پیدا کنم.
|
||||
|
||||
هر وقت یکیشان را گیر آوردهام که یک خرده روشن بین به نظرم آمده با نقاشی شمارهی یکم که هنوز هم دارمش محکش زدهام ببینم راستی راستی چیزی بارش هست یا نه. اما او هم طبق معمول در جوابم در آمده که: «این یک کلاه است». آن وقت دیگر من هم نه از مارهای بوآ باش اختلاط کردهام نه از جنگلهای بکر دست نخورده نه از ستارهها. خودم را تا حد او آوردهام پایین و باش از بریج و گلف و سیاست و انواع کرات حرف زدهام. او هم از این که با یک چنین شخص معقولی آشنایی به هم رسانده سخت خوشوقت شده.
|
||||
|
||||
۲
|
||||
این جوری بود که روزگارم تو تنهایی میگذشت بی این که راستی راستی یکی را داشته باشم که باش دو کلمه حرف بزنم، تااین که زد و شش سال پیش در کویر صحرا حادثهیی برایم اتفاق افتاد؛ یک چیز موتور هواپیمایم شکسته بود و چون نه تعمیرکاری همراهم بود نه مسافری یکه و تنها دست به کار شدم تا از پس چنان تعمیر مشکلی برآیم. مسالهی مرگ و زندگی بود. آبی که داشتم زورکی هشت روز را کفاف میداد.
|
||||
|
||||
شب اول را هزار میل دورتر از هر آبادی مسکونی رو ماسهها به روز آوردم پرت افتادهتر از هر کشتی شکستهیی که وسط اقیانوس به تخته پارهیی چسبیده باشد. پس لابد میتوانید حدس بزنید چه جور هاج و واج ماندم وقتی کلهی آفتاب به شنیدن صدای ظریف عجیبی که گفت: «بی زحمت یک برّه برام بکش!» از خواب پریدم.
|
||||
-ها؟
|
||||
-یک برّه برام بکش...
|
||||
|
||||
چنان از جا جستم که انگار صاعقه بم زده. خوب که چشمهام را مالیدم و نگاه کردم آدم کوچولوی بسیار عجیبی را دیدم که با وقار تمام تو نخ من بود. این بهترین شکلی است که بعد ها توانستم از او در آرم، گیرم البته آنچه من کشیدهام کجا و خود او کجا! تقصیر من چیست؟ بزرگتر ها تو شش سالگی از نقاشی دلسردم کردند و جز بوآی باز و بسته یاد نگرفتم چیزی بکشم.
|
||||
|
||||
با چشمهایی که از تعجب گرد شده بود به این حضور ناگهانی خیره شدم. یادتان نرود که من از نزدیکترین آبادی مسکونی هزار میل فاصله داشتم و این آدمیزاد کوچولوی من هم اصلا به نظر نمیآمد که راه گم کرده باشد یا از خستگی دم مرگ باشد یا از گشنگی دم مرگ باشد یا از تشنگی دم مرگ باشد یا از وحشت دم مرگ باشد. هیچ چیزش به بچهیی نمیبُرد که هزار میل دور از هر آبادی مسکونی تو دل صحرا گم شده باشد.
|
||||
|
||||
این بهترین شکلی است که بعدها از او در آوردم.
|
||||
وقتی بالاخره صدام در آمد، گفتم:
|
||||
-آخه... تو این جا چه میکنی؟
|
||||
و آن وقت او خیلی آرام، مثل یک چیز خیلی جدی، دوباره در آمد که:
|
||||
-بی زحمت واسهی من یک برّه بکش.
|
||||
آدم وقتی تحت تاثیر شدید رازی قرار گرفت جرات نافرمانی نمیکند. گرچه تو آن نقطهی هزار میل دورتر از هر آبادی مسکونی و با قرار داشتن در معرض خطر مرگ این نکته در نظرم بی معنی جلوه کرد باز کاغذ و خودنویسی از جیبم در آوردم اما تازه یادم آمد که آنچه من یاد گرفتهام بیشتر جغرافیا و تاریخ و حساب و دستور زبان است، و با کج خلقی مختصری به آن موجود کوچولو گفتم نقاشی بلد نیستم.
|
||||
بم جواب داد: -عیب ندارد، یک بَرّه برام بکش.
|
||||
|
||||
از آنجایی که هیچ وقت تو عمرم بَرّه نکشیده بودم یکی از آن دو تا نقاشیای را که بلد بودم برایش کشیدم. آن بوآی بسته را. ولی چه یکهای خوردم وقتی آن موجود کوچولو در آمد که: -نه! نه! فیلِ تو شکم یک بوآ نمیخواهم. بوآ خیلی خطرناک است فیل جا تنگ کن. خانهی من خیلی کوچولوست، من یک بره لازم دارم. برام یک بره بکش.برهی مریض
|
||||
-خب، کشیدم.
|
||||
با دقت نگاهش کرد و گفت:
|
||||
-نه! این که همین حالاش هم حسابی مریض است. یکی دیگر بکش.قوچ
|
||||
-کشیدم.
|
||||
لبخند با نمکی زد و در نهایت گذشت گفت:
|
||||
-خودت که میبینی... این بره نیست، قوچ است. شاخ دارد نه...برهی پیر
|
||||
باز نقاشی را عوض کردم.
|
||||
آن را هم مثل قبلی ها رد کرد:
|
||||
-این یکی خیلی پیر است... من یک بره میخواهم که مدت ها عمر کند...
|
||||
|
||||
باری چون عجله داشتم که موتورم را پیاده کنم رو بی حوصلگی جعبهای کشیدم که دیوارهاش سه تا سوراخ داشت، و از دهنم پرید که:جعبه
|
||||
-این یک جعبه است. برهای که میخواهی این تو است.
|
||||
|
||||
و چه قدر تعجب کردم از این که دیدم داور کوچولوی من قیافهاش از هم باز شد و گفت:
|
||||
-آها... این درست همان چیزی است که میخواستم! فکر میکنی این بره خیلی علف بخواهد؟
|
||||
-چطور مگر؟
|
||||
-آخر جای من خیلی تنگ است...
|
||||
-هر چه باشد حتماً بسش است. برهیی که بت دادهام خیلی کوچولوست.
|
||||
-آن قدرهاهم کوچولو نیست... اِه! گرفته خوابیده...
|
||||
|
||||
و این جوری بود که من با شهریار کوچولو آشنا شدم.
|
||||
|
||||
۳
|
||||
خیلی طول کشید تا توانستم بفهمم از کجا آمده. شهریار کوچولو که مدام مرا سوال پیچ میکرد خودش انگار هیچ وقت سوالهای مرا نمیشنید. فقط چیزهایی که جسته گریخته از دهنش میپرید کم کم همه چیز را به من آشکار کرد. مثلا اول بار که هواپیمای مرا دید (راستی من هواپیما نقاشی نمیکنم، سختم است.) ازم پرسید:
|
||||
-این چیز چیه؟
|
||||
-این «چیز» نیست: این پرواز میکند. هواپیماست. هواپیمای من است.
|
||||
|
||||
و از این که بهاش میفهماندم من کسیام که پرواز میکنم به خود میبالیدم.
|
||||
حیرت زده گفت: -چی؟ تو از آسمان افتادهای؟
|
||||
با فروتنی گفتم: -آره.
|
||||
گفت: -اوه، این دیگر خیلی عجیب است!
|
||||
و چنان قهقههی ملوسی سر داد که مرا حسابی از جا در برد. راستش من دلم میخواهد دیگران گرفتاریهایم را جدی بگیرند.
|
||||
خندههایش را که کرد گفت: -خب، پس تو هم از آسمان میآیی! اهل کدام سیارهای؟...
|
||||
|
||||
بفهمی نفهمی نور مبهمی به معمای حضورش تابید. یکهو پرسیدم:
|
||||
-پس تو از یک سیارهی دیگر آمدهای؟
|
||||
آرام سرش را تکان داد بی این که چشم از هواپیما بردارد.
|
||||
|
||||
اما جوابم را نداد، تو نخ هواپیما رفته بود و آرام آرام سر تکان میداد.
|
||||
گفت: -هر چه باشد با این نباید از جای خیلی دوری آمده باشی...
|
||||
|
||||
مدت درازی تو خیال فرو رفت، بعد برهاش را از جیب در آورد و محو تماشای آن گنج گرانبها شد.تصویری از شهریار کوچولو بر روی زمین
|
||||
فکر میکنید از این نیمچه اعتراف «سیارهی دیگر»ِ او چه هیجانی به من دست داد؟ زیر پاش نشستم که حرف بیشتری از زبانش بکشم:
|
||||
-تو از کجا میآیی آقا کوچولوی من؟ خانهات کجاست؟ برهی مرا میخواهی کجا ببری؟
|
||||
مدتی در سکوت به فکر فرورفت و بعد در جوابم گفت:
|
||||
-حسن جعبهای که بم دادهای این است که شبها میتواند خانهاش بشود.
|
||||
-معلوم است... اما اگر بچهی خوبی باشی یک ریسمان هم بِت میدهم که روزها ببندیش. یک ریسمان با یک میخ طویله...
|
||||
انگار از پیشنهادم جا خورد، چون که گفت:
|
||||
-ببندمش؟ چه فکر ها!
|
||||
-آخر اگر نبندیش راه میافتد میرود گم میشود.
|
||||
|
||||
دوست کوچولوی من دوباره غش غش خنده را سر داد:
|
||||
-مگر کجا میتواند برود؟
|
||||
-خدا میداند. راستِ شکمش را میگیرد و میرود...
|
||||
-بگذار برود...اوه، خانهی من آنقدر کوچک است!
|
||||
و شاید با یک خرده اندوه در آمد که:
|
||||
-یکراست هم که بگیرد برود جای دوری نمیرود...
|
||||
|
||||
۴
|
||||
به این ترتیب از یک موضوع خیلی مهم دیگر هم سر در آوردم: این که سیارهی او کمی از یک خانهی معمولی بزرگتر بود.این نکته آنقدرها به حیرتم نینداخت. میدانستم گذشته از سیارههای بزرگی مثل زمین و کیوان و تیر و ناهید که هرکدام برای خودشان اسمی دارند، صدها سیارهی دیگر هم هست که بعضیشان از بس کوچکند با دوربین نجومی هم به هزار زحمت دیده میشوند و هرگاه اخترشناسی یکیشان را کشف کند به جای اسم شمارهای بهاش میدهد. مثلا اسمش را میگذارد «اخترک ۳۲۵۱».
|
||||
|
||||
دلایل قاطعی دارم که ثابت میکند شهریار کوچولو از اخترک ب۶۱۲ آمدهبود.
|
||||
|
||||
شهریار کوچولو بر اخترکِ ب۶۱۲
|
||||
این اخترک را فقط یک بار به سال ۱۹۰۹ یک اخترشناس ترک توانسته بود ببیند اخترشناسِ ترک در حالِ دیدنِ اخترکِ ب۶۱۲که تو یک کنگرهی بینالمللی نجوم هم با کشفش هیاهوی زیادی به راه انداخت اما واسه خاطر لباسی که تنش بود هیچ کس حرفش را باور نکرد. اخترشناسِ ترک در کنگرهی بینالمللیِ نجوم، با لباس قدیمیآدم بزرگها این جوریاند!
|
||||
|
||||
بختِ اخترک ب۶۱۲ زد و، ترک مستبدی ملتش را به ضرب دگنک وادار به پوشیدن لباس اروپاییها کرد. اخترشناس به سال ۱۹۲۰ دوباره، و این بار با سر و وضع آراسته برای کشفش ارائهی دلیل کرد و این بار همه جانب او را گرفتند.اخترشناسِ ترک در کنگرهی بینالمللیِ نجوم، با لباس جدید
|
||||
به خاطر آدم بزرگهاست که من این جزئیات را در باب اخترکِ ب۶۱۲ برایتان نقل میکنم یا شمارهاش را میگویم چون که آنها عاشق عدد و رقماند. وقتی با آنها از یک دوست تازهتان حرف بزنید هیچ وقت ازتان دربارهی چیزهای اساسیاش سوال نمیکنند که هیج وقت نمیپرسند «آهنگ صداش چهطور است؟ چه بازیهایی را بیشتر دوست دارد؟ پروانه جمع میکند یا نه؟» -میپرسند: «چند سالش است؟ چند تا برادر دارد؟ وزنش چهقدر است؟ پدرش چهقدر حقوق میگیرد؟» و تازه بعد از این سوالها است که خیال میکنند طرف را شناختهاند.
|
||||
|
||||
اگر به آدم بزرگها بگویید یک خانهی قشنگ دیدم از آجر قرمز که جلو پنجرههاش غرقِ شمعدانی و بامش پر از کبوتر بود محال است بتوانند مجسمش کنند. باید حتماً بهشان گفت یک خانهی صد میلیون تومنی دیدم تا صداشان بلند بشود که: -وای چه قشنگ!
|
||||
|
||||
یا مثلا اگر بهشان بگویید «دلیل وجودِ شهریارِ کوچولو این که تودلبرو بود و میخندید و دلش یک بره میخواست و بره خواستن، خودش بهترین دلیل وجود داشتن هر کسی است» شانه بالا میاندازند و باتان مثل بچهها رفتار میکنند! اما اگر بهشان بگویید «سیارهای که ازش آمدهبود اخترک ب۶۱۲ است» بیمعطلی قبول میکنند و دیگر هزار جور چیز ازتان نمیپرسند. این جوریاند دیگر. نباید ازشان دلخور شد. بچهها باید نسبت به آدم بزرگها گذشت داشته باشند.
|
||||
|
||||
اما البته ماها که مفهوم حقیقی زندگی را درک میکنیم میخندیم به ریش هرچه عدد و رقم است! چیزی که من دلم میخواست این بود که این ماجرا را مثل قصهی پریا نقل کنم. دلم میخواست بگویم: «یکی بود یکی نبود. روزی روزگاری یه شهریار کوچولو بود که تو اخترکی زندگی میکرد همهاش یه خورده از خودش بزرگتر و واسه خودش پیِ دوستِ همزبونی میگشت...»، آن هایی که مفهوم حقیقی زندگی را درک کردهاند واقعیت قضیه را با این لحن بیشتر حس میکنند. آخر من دوست ندارم کسی کتابم را سرسری بخواند. خدا میداند با نقل این خاطرات چه بار غمی روی دلم مینشیند. شش سالی میشود که دوستم با بَرّهاش رفته. این که این جا میکوشم او را وصف کنم برای آن است که از خاطرم نرود. فراموش کردن یک دوست خیلی غمانگیز است. همه کس که دوستی ندارد. من هم میتوانم مثل آدم بزرگها بشوم که فقط اعداد و ارقام چشمشان را میگیرد. و باز به همین دلیل است که رفتهام یک جعبه رنگ و چند تا مداد خریدهام. تو سن و سال من واسه کسی که جز کشیدنِ یک بوآی باز یا یک بوآی بسته هیچ کار دیگری نکرده -و تازه آن هم در شش سالگی- دوباره به نقاشی رو کردن از آن حرفهاست! البته تا آنجا که بتوانم سعی میکنم چیزهایی که میکشم تا حد ممکن شبیه باشد. گیرم به موفقیت خودم اطمینان چندانی ندارم. یکیش شبیه از آب در میآید یکیش نه. سرِ قدّ و قوارهاش هم حرف است. یک جا زیادی بلند درش آوردهام یک جا زیادی کوتاه. از رنگ لباسش هم مطمئن نیستم. خب، رو حدس و گمان پیش رفتهام؛ کاچی به زِ هیچی. و دست آخر گفته باشم که تو بعضِ جزئیات مهمترش هم دچار اشتباه شدهام. اما در این مورد دیگر باید ببخشید: دوستم زیر بار هیچ جور شرح و توصیفی نمیرفت. شاید مرا هم مثل خودش میپنداشت. اما از بختِ بد، دیدن برهها از پشتِ جعبه از من بر نمیآید. نکند من هم یک خرده به آدم بزرگها رفتهام؟ «باید پیر شده باشم».
|
||||
|
||||
۵
|
||||
هر روزی که میگذشت از اخترک و از فکرِ عزیمت و از سفر و این حرفها چیزهای تازهای دستگیرم میشد که همهاش معلولِ بازتابهایِ اتفاقی بود. و از همین راه بود که روز سوم از ماجرایِ تلخِ بائوباب ها سردرآوردم.
|
||||
|
||||
این بار هم بَرّه باعثش شد، چون شهریار کوچولو که انگار سخت دودل ماندهبود ناگهان ازم پرسید:
|
||||
-بَرّهها بتهها را هم میخورند دیگر، مگر نه؟
|
||||
-آره. همین جور است.
|
||||
-آخ! چه خوشحال شدم!
|
||||
|
||||
نتوانستم بفهمم این موضوع که بَرّهها بوتهها را هم میخورند اهمیتش کجاست اما شهریار کوچولو درآمد که:
|
||||
-پس لابد بائوباب ها را هم میخورند دیگر؟
|
||||
|
||||
یک گله فیل که در اخترکِ ب۶۱۲ روی هم چیده شدهاندمن برایش توضیح دادم که بائوباب بُتّه نیست. درخت است و از ساختمان یک معبد هم گندهتر، و اگر یک گَلّه فیل هم با خودش ببرد حتا یک درخت بائوباب را هم نمیتوانند بخورند.
|
||||
از فکر یک گَلّه فیل به خنده افتاد و گفت: -باید چیدشان روی هم.
|
||||
اما با فرزانگی تمام متذکر شد که: -بائوباب هم از بُتِّگی شروع میکند به بزرگ شدن.
|
||||
-درست است. اما نگفتی چرا دلت میخواهد برههایت نهالهای بائوباب را بخورند؟
|
||||
گفت: -دِ! معلوم است!
|
||||
|
||||
و این را چنان گفت که انگار موضوع از آفتاب هم روشنتر است؛ منتها من برای این که به تنهایی از این راز سر در آرم ناچار شدم حسابی کَلّه را به کار بیندازم.
|
||||
|
||||
راستش این که تو اخترکِ شهریار کوچولو هم مثل سیارات دیگر هم گیاهِ خوب به هم میرسید هم گیاهِ بد. یعنی هم تخمِ خوب گیاههای خوب به هم میرسید، هم تخمِ بدِ گیاههایِ بد. اما تخم گیاهها نامرییاند. آنها تو حرمِ تاریک خاک به خواب میروند تا یکیشان هوس بیدار شدن به سرش بزند. آن وقت کش و قوسی میآید و اول با کم رویی شاخکِ باریکِ خوشگل و بیآزاری به طرف خورشید میدواند. اگر این شاخک شاخکِ تربچهای گلِ سرخی چیزی باشد میشود گذاشت برای خودش رشد کند اما اگر گیاهِ بدی باشد آدم باید به مجردی که دستش را خواند ریشهکنش کند.
|
||||
|
||||
باری، تو سیارهی شهریار کوچولو گیاه تخمههای وحشتناکی به هم میرسید. یعنی تخم درختِ بائوباب که خاکِ سیاره حسابی ازشان لطمه خورده بود. بائوباب هم اگر دیر بهاش برسند دیگر هیچ جور نمیشود حریفش شد: تمام سیاره را میگیرد و با ریشههایش سوراخ سوراخش میکند و اگر سیاره خیلی کوچولو باشد و بائوبابها خیلی زیاد باشند پاک از هم متلاشیش میکنند.
|
||||
|
||||
شهریار کوچولو در حال نظافت ِ اخترکششهریار کوچولو بعدها یک روز به من گفت: «این، یک امر انضباطی است. صبح به صبح بعد از نظافتِ خود باید با دفت تمام به نظافتِ اخترک پرداخت. آدم باید خودش را مجبور کند که به مجردِ تشخیص دادن بائوبابها از بتههای گلِ سرخ که تا کوچولواَند عین هماَند با دقت ریشهکنشان بکند. کار کسلکنندهای هست اما هیچ مشکل نیست.»
|
||||
|
||||
یک روز هم بم توصیه کرد سعی کنم هر جور شده یک نقاشی حسابی از کار درآرم که بتواند قضیه را به بچههای سیارهی من هم حالی کند. گفت اگر یک روز بروند سفر ممکن است به دردشان بخورد. پارهای وقتها پشت گوش انداختن کار ایرادی ندارد اما اگر پای بائوباب در میان باشد گاوِ آدم میزاید. اخترکی را سراغ دارم که یک تنبلباشی ساکنش بود و برای کندن سه تا نهال بائوباب امروز و فردا کرد...».
|
||||
|
||||
آن وقت من با استفاده از چیزهایی که گفت شکل آن اخترک را کشیدم.
|
||||
|
||||
اخترکِ تنبلباشی با سه درختِ بائوباب
|
||||
هیچ دوست ندارم اندرزگویی کنم. اما خطر بائوبابها آنقدر کم شناخته شده و سر راهِ کسی که تو چنان اخترکی سرگیدان بشود آن قدر خطر به کمین نشسته که این مرتبه را از رویهی همیشگی خودم دست بر میدارم و میگویم: «بچهها! هوای بائوبابها را داشته باشید!»
|
||||
|
||||
اگر من سرِ این نقاشی این همه به خودم فشار آوردهام فقط برای آن بوده که دوستانم را متوجه خطری کنم که از مدتها پیش بیخ گوششان بوده و مثلِ خودِ من ازش غافل بودهاند. درسی که با این نقاشی دادهام به زحمتش میارزد. حالا ممکن است شما از خودتان بپرسید: «پس چرا هیچ کدام از بقیهی نقاشیهای این کتاب هیبتِ تصویرِ بائوبابها را ندارد؟» -خب، جوابش خیلی ساده است: من زور خودم را زدهام اما نتوانستهام از کار درشان بیاورم. اما عکس بائوبابها را که میکشیدم احساس میکردم قضیه خیلی فوریت دارد و به این دلیل شور بَرَم داشته بود.
|
||||
|
||||
۶
|
||||
آخ، شهریار کوچولو! این جوری بود که من کَم کَمَک از زندگیِ محدود و دلگیر تو سر درآوردم. تا مدتها تنها سرگرمیِ تو تماشای زیباییِ غروب آفتاب بوده. به این نکتهی تازه صبح روز چهارم بود که پی بردم؛ یعنی وقتی که به من گفتی:
|
||||
-غروب آفتاب را خیلی دوست دارم. برویم فرورفتن آفتاب را تماشا کنیم...شهریار کوچولو در اخترکش مشغولِ تماشای غروبِ آفتاب
|
||||
-هوم، حالاها باید صبر کنی...
|
||||
-واسه چی صبر کنم؟
|
||||
-صبر کنی که آفتاب غروب کند.
|
||||
|
||||
اول سخت حیرت کردی بعد از خودت خندهات گرفت و برگشتی به من گفتی:
|
||||
-همهاش خیال میکنم تو اخترکِ خودمم!
|
||||
-راستش موقعی که تو آمریکا ظهر باشد همه میدانند تو فرانسه تازه آفتاب دارد غروب میکند. کافی است آدم بتواند در یک دقیقه خودش را برساند به فرانسه تا بتواند غروب آفتاب را تماشا کند. متاسفانه فرانسه کجا اینجا کجا! اما رو اخترک تو که به آن کوچکی است همینقدر که چند قدمی صندلیت را جلو بکشی میتوانی هرقدر دلت خواست غروب تماشا کنی.
|
||||
-یک روز چهل و سه بار غروب آفتاب را تماشا کردم!
|
||||
و کمی بعد گفت:
|
||||
-خودت که میدانی... وقتی آدم خیلی دلش گرفته باشد از تماشای غروب لذت میبرد.
|
||||
-پس خدا میداند آن روز چهل و سه غروبه چهقدر دلت گرفته بوده.
|
||||
|
||||
اما مسافر کوچولو جوابم را نداد.
|
||||
|
||||
۷
|
||||
روز پنجم باز سرِ گوسفند از یک راز دیگر زندگی شهریار کوچولو سر در آوردم. مثل چیزی که مدتها تو دلش بهاش فکر کرده باشد یکهو بی مقدمه از من پرسید:
|
||||
-گوسفندی که بُتّه ها را بخورد گل ها را هم میخورد؟
|
||||
-گوسفند هرچه گیرش بیاید میخورد.
|
||||
-حتا گلهایی را هم که خار دارند؟
|
||||
-آره، حتا گلهایی را هم که خار دارند.
|
||||
-پس خارها فایدهشان چیست؟
|
||||
|
||||
من چه میدانستم؟ یکی از آن: سخت گرفتار باز کردن یک مهرهی سفتِ موتور بودم. از این که یواش یواش بو میبردم خرابیِ کار به آن سادگیها هم که خیال میکردم نیست برج زهرمار شدهبودم و ذخیرهی آبم هم که داشت ته میکشید بیشتر به وحشتم میانداخت.
|
||||
-پس خارها فایدهشان چسیت؟
|
||||
|
||||
شهریار کوچولو وقتی سوالی را میکشید وسط دیگر به این مفتیها دست بر نمیداشت. مهره پاک کلافهام کرده بود. همین جور سرسری پراندم که:
|
||||
-خارها به درد هیچ کوفتی نمیخورند. آنها فقط نشانهی بدجنسی گلها هستند.
|
||||
-دِ!
|
||||
و پس از لحظهیی سکوت با یک جور کینه درآمد که:
|
||||
-حرفت را باور نمیکنم! گلها ضعیفند. بی شیلهپیلهاند. سعی میکنند یک جوری تهِ دل خودشان را قرص کنند. این است که خیال میکنند با آن خارها چیزِ ترسناکِ وحشتآوری میشوند...
|
||||
|
||||
لام تا کام بهاش جواب ندادم. در آن لحظه داشتم تو دلم میگفتم: «اگر این مهرهی لعنتی همین جور بخواهد لج کند با یک ضربهی چکش حسابش را میرسم.» اما شهریار کوچولو دوباره افکارم را به هم ریخت:
|
||||
-تو فکر میکنی گلها...
|
||||
من باز همان جور بیتوجه گفتم:
|
||||
-ای داد بیداد! ای داد بیداد! نه، من هیچ کوفتی فکر نمیکنم! آخر من گرفتار هزار مسالهی مهمتر از آنم!
|
||||
هاج و واج نگاهم کرد و گفت:
|
||||
-مسالهی مهم!
|
||||
|
||||
مرا میدید که چکش به دست با دست و بالِ سیاه روی چیزی که خیلی هم به نظرش زشت میآمد خم شدهام.
|
||||
-مثل آدم بزرگها حرف میزنی!
|
||||
از شنیدنِ این حرف خجل شدم اما او همین جور بیرحمانه میگفت:
|
||||
-تو همه چیز را به هم میریزی... همه چیز را قاتی میکنی!
|
||||
حسابی از کوره در رفتهبود.
|
||||
|
||||
موهای طلایی طلائیش تو باد میجنبید.
|
||||
-اخترکی را سراغ دارم که یک آقا سرخ روئه توش زندگی میکند. او هیچ وقت یک گل را بو نکرده، هیچ وقت یک ستارهرا تماشا نکرده هیچ وقت کسی را دوست نداشته هیچ وقت جز جمع زدن عددها کاری نکرده. او هم مثل تو صبح تا شب کارش همین است که بگوید: «من یک آدم مهمم! یک آدم مهمم!» این را بگوید و از غرور به خودش باد کند. اما خیال کرده: او آدم نیست، یک قارچ است!
|
||||
-یک چی؟
|
||||
-یک قارچ!گلِ سرخ
|
||||
حالا دیگر رنگش از فرط خشم مثل گچ سفید شدهبود:
|
||||
-کرورها سال است که گلها خار میسازند و با وجود این کرورها سال است که برّهها گلها را میخورند. آن وقت هیچ مهم نیست آدم بداند پس چرا گلها واسه ساختنِ خارهایی که هیچ وقتِ خدا به هیچ دردی نمیخورند این قدر به خودشان زحمت میدهند؟ جنگ میان برّهها و گلها هیچ مهم نیست؟ این موضوع از آن جمع زدنهای آقا سرخروئهیِ شکمگنده مهمتر و جدیتر نیست؟ اگر من گلی را بشناسم که تو همهی دنیا تک است و جز رو اخترک خودم هیچ جای دیگر پیدا نمیشه و ممکن است یک روز صبح یک برّه کوچولو، مفت و مسلم، بی این که بفهمد چهکار دارد میکند به یک ضرب پاک از میان ببردش چی؟ یعنی این هم هیچ اهمیتی ندارد؟ اگر کسی گلی را دوست داشته باشد که تو کرورها و کرورها ستاره فقط یک دانه ازش هست واسه احساس وشبختی همین قدر بس است که نگاهی به آن همه ستاره بیندازد و با خودش بگوید: «گل من یک جایی میان آن ستارههاست»، اما اگر برّه گل را بخورد برایش مثل این است که یکهو تمام آن ستارهها پِتّی کنند و خاموش بشوند. یعنی این هم هیچ اهمیتی ندارد؟
|
||||
دیگر نتوانست چیزی بگوید و ناگهان هِق هِق کنان زد زیر گریه.
|
||||
|
||||
حالا دیگر شب شدهبود. اسباب و ابزارم را کنار انداختهبودم. دیگر چکش و مهره و تشنگی و مرگ به نظرم مضحک میآمد. رو ستارهای، رو سیارهای، رو سیارهی من، زمین، شهریارِ کوچولویی بود که احتیاج به دلداری داشت! به آغوشش گرفتم مثل گهواره تابش دادم بهاش گفتم: «گلی که تو دوست داری تو خطر نیست. خودم واسه گوسفندت یک پوزهبند میکشم... خودم واسه گفت یک تجیر میکشم... خودم...» بیش از این نمیدانستم چه بگویم. خودم را سخت چُلمَن و بی دست و پا حس میکردم. نمیدانستم چهطور باید خودم را بهاش برسانم یا بهاش بپیوندم...p چه دیار اسرارآمیزی است دیار اشک!
|
||||
|
||||
۸
|
||||
راه شناختن آن گل را خیلی زود پیدا کردم:
|
||||
تو اخترکِ شهریار کوچولو همیشه یک مشت گلهای خیلی ساده در میآمده. گلهایی با یک ردیف گلبرگ که جای چندانی نمیگرفته، دست و پاگیرِ کسی نمیشده. صبحی سر و کلهشان میان علفها پیدا میشده شب از میان میرفتهاند. اما این یکی یک روز از دانهای جوانه زده بود که خدا میدانست از کجا آمده رود و شهریار کوچولو با جان و دل از این شاخکِ نازکی که به هیچ کدام از شاخکهای دیگر نمیرفت مواظبت کردهبود. بعید بنود که این هم نوعِ تازهای از بائوباب باشد اما بته خیلی زود از رشد بازماند و دستبهکارِ آوردن گل شد. شهریار کوچولو که موقعِ نیش زدن آن غنچهی بزرگ حاضر و ناظر بود به دلش افتاد که باید چیز معجزهآسایی از آن بیرون بیاید. اما گل تو پناهِ خوابگاهِ سبزش سر فرصت دست اندکار خودآرایی بود تا هرچه زیباتر جلوهکند. رنگهایش را با وسواس تمام انتخاب میکرد سر صبر لباس میپوشید و گلبرگها را یکی یکی به خودش میبست. دلش نمیخواست مثل شقایقها با جامهی مچاله و پر چروک بیرون بیاید.
|
||||
|
||||
شهریار کوچولو و گلِ سرخنمیخواست جز در اوج درخشندگی زیبائیش رو نشان بدهد!...
|
||||
|
||||
هوه، بله عشوهگری تمام عیار بود! آرایشِ پر راز و رمزش روزها و روزها طول کشید تا آن که سرانجام یک روز صبح درست با بر آمدن آفتاب نقاب از چهره برداشت و با این که با آن همه دقت و ظرافت روی آرایش و پیرایش خودش کار کرده بود خمیازهکشان گفت:
|
||||
-اوه، تازه همین حالا از خواب پا شدهام... عذر میخواهم که موهام این جور آشفتهاست...
|
||||
|
||||
شهریار کوچولو نتوانست جلو خودش را بگیرد و از ستایش او خودداری کند:
|
||||
-وای چهقدر زیبائید!
|
||||
گل به نرمی گفت:
|
||||
-چرا که نه؟ من و آفتاب تو یک لحظه به دنیا آمدیم...
|
||||
شهریار کوچولو شستش خبردار شد که طرف آنقدرها هم اهل شکستهنفسی نیست اما راستی که چهقدر هیجان انگیز بود!
|
||||
-به نظرم وقت خوردن ناشتایی است. بی زحمت برایم فکری بکنید.
|
||||
و شهریار کوچولوی مشوش و در هم یک آبپاش آب خنک آورده به گل دادهبود.شهریار کوچولو در حالِ تماشای گلِ سرخ
|
||||
با این حساب، هنوزهیچی نشده با آن خودپسندیش که بفهمینفهمی از ضعفش آب میخورد دل او را شکسته بود. مثلا یک روز که داشت راجع به چهارتا خارش حرف میزد یکهو در آمده بود که:ببر و گلِ سرخ
|
||||
-نکند ببرها با آن چنگالهای تیزشان بیایند سراغم!
|
||||
شهریار کوچولو ازش ایراد گرفتهبود که:
|
||||
-تو اخترک من ببر به هم نمیرسد. تازه ببرها که علفخوار نیستند.
|
||||
گل به گلایه جواب داده بود:
|
||||
-من که علف نیستم.
|
||||
و شهریار کوچولو گفته بود:
|
||||
-عذر میخواهم...
|
||||
-من از ببرها هیچ ترسی ندارم اما از جریان هوا وحشت میکنم. تو دستگاهتان تجیر به هم نمیرسد؟شهریار کوچولو در حالِ پوشاندنِ گلِ سرخ
|
||||
شهریار کوچولو تو دلش گفت: «وحشت از جریان هوا... این که واسه یک گیاه تعریفی ندارد... چه مرموز است این گل!»
|
||||
-شب مرا بگذارید زیر یک سرپوش. این جا هواش خیلی سرد است. چه جای بدی افتادم! جایی که پیش از این بودم...شهریار کوچولو در حالِ گذاشتنِ سرپوش روی گلِ سرخ
|
||||
اما حرفش را خورده بود. آخر، آمدنا هنوز به شکل دانه بود. امکان نداشت توانستهباشد دنیاهای دیگری را بشناسد. شرمسار از این که گذاشته بود سر به هم بافتن دروغی به این آشکاری مچش گیربیفتد دو سه بار سرفه کرده بود تا اهمالِ شهریار کوچولو را بهاش یادآور شود:
|
||||
-تجیر کو پس؟
|
||||
-داشتم میرفتم اما شما داشتید صحبت میکردید!
|
||||
و با وجود این زورکی بنا کردهبود به سرفه کردن تا او احساس پشیمانی کند.
|
||||
|
||||
به این ترتیب شهریار کوچولو با همهی حسن نیّتی که از عشقش آب میخورد همان اول کار به او بد گمان شدهبود. حرفهای بی سر و تهش را جدی گرفتهبود و سخت احساس شوربختی میکرد.
|
||||
|
||||
یک روز دردِدل کنان به من گفت: -حقش بود به حرفهاش گوش نمیدادم. هیچ وقت نباید به حرف گلها گوش داد. گل را فقط باید بوئید و تماشا کرد. گلِ من تمامِ اخترکم را معطر میکرد گیرم من بلد نبودم چهجوری از آن لذت ببرم. قضیهی چنگالهای ببر که آن جور دَمَغم کردهبود میبایست دلم را نرم کرده باشد...»
|
||||
|
||||
یک روز دیگر هم به من گفت: «آن روزها نتوانستم چیزی بفهمم. من بایست روی کرد و کارِ او در بارهاش قضاوت میکردم نه روی گفتارش... عطرآگینم میکرد. دلم را روشن میکرد. نمیبایست ازش بگریزم. میبایست به مهر و محبتی که پشتِ آن کلکهای معصومانهاش پنهان بود پی میبردم. گلها پُرَند از این جور تضادها. اما خب دیگر، من خامتر از آن بودم که راهِ دوست داشتنش را بدانم!».
|
||||
|
||||
۹
|
||||
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرندههای وحشی استفاده کرد.
|
||||
|
||||
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرندههای وحشی استفاده کرد.
|
||||
صبح روز حرکت، اخترکش را آن جور که باید مرتب کرد، آتشفشانهای فعالش را با دقت پاک و دودهگیری کرد: شهریار کوچولو در حالِ پاک کردنِ آتشفشان.دو تا آتشفشان فعال داشت که برای گرم کردن ناشتایی خیلی خوب بود. یک آتشفشان خاموش هم داشت. منتها به قول خودش «آدم کف دستش را که بو نکرده!» این بود که آتشفشان خاموش را هم پاک کرد. آتشفشان که پاک باشد مرتب و یک هوا میسوزد و یکهو گُر نمیزند. آتشفشان هم عینهو بخاری یکهو اَلُو میزند. البته ما رو سیارهمان زمین کوچکتر از آن هستیم که آتشفشانهامان را پاک و دودهگیری کنیم و برای همین است که گاهی آن جور اسباب زحمتمان میشوند.
|
||||
|
||||
شهریار کوچولو با دلِگرفته آخرین نهالهای بائوباب را هم ریشهکن کرد. فکر میکرد دیگر هیچ وقت نباید برگردد. اما آن روز صبح گرچه از این کارهای معمولیِ هر روزه کُلّی لذت برد موقعی که آخرین آب را پای گل داد و خواست بگذاردش زیرِ سرپوش چیزی نماندهبود که اشکش سرازیر شود.
|
||||
به گل گفت: -خدا نگهدار!
|
||||
اما او جوابش را نداد.
|
||||
دوباره گفت: -خدا نگهدار!
|
||||
گل سرفهکرد، گیرم این سرفه اثر چائیدن نبود. بالاخره به زبان آمد و گفت:
|
||||
-من سبک مغز بودم. ازت عذر میخواهم. سعی کن خوشبخت باشی.
|
||||
از این که به سرکوفت و سرزنشهای همیشگی برنخورد حیرت کرد و سرپوش به دست هاجوواج ماند. از این محبتِ آرام سر در نمیآورد.
|
||||
گل بهاش گفت: -خب دیگر، دوستت دارم. اگر تو روحت هم از این موضوع خبردار نشد تقصیر من است. باشد، زیاد مهم نیست. اما تو هم مثل من بیعقل بودی... سعی کن خوشبخت بشوی... این سرپوش را هم بگذار کنار، دیگر به دردم نمیخورد.
|
||||
-آخر، باد...
|
||||
-آن قدرهاهم سَرمائو نیستم... هوای خنک شب برای سلامتیم خوب است. خدانکرده گُلم آخر.
|
||||
-آخر حیوانات...
|
||||
-اگر خواستهباشم با شبپرهها آشنا بشوم جز این که دو سه تا کرمِ حشره را تحمل کنم چارهای ندارم. شبپره باید خیلی قشنگ باشد. جز آن کی به دیدنم میآید؟ تو که میروی به آن دور دورها. از بابتِ درندهها هم هیچ کَکَم نمیگزد: «من هم برای خودم چنگ و پنجهای دارم».
|
||||
و با سادگی تمام چهارتا خارش را نشان داد. بعد گفت:
|
||||
-دستدست نکن دیگر! این کارت خلق آدم را تنگ میکند. حالا که تصمیم گرفتهای بروی برو!
|
||||
|
||||
و این را گفت، چون که نمیخواست شهریار کوچولو گریهاش را ببیند. گلی بود تا این حد خودپسند...
|
||||
|
||||
۱۰
|
||||
خودش را در منطقهی اخترکهای ۳۲۵، ۳۲۶، ۳۲۷، ۳۲۸، ۳۲۹ و ۳۳۰ دید. این بود که هم برای سرگرمی و هم برای چیزیادگرفتن بنا کرد یکییکیشان را سیاحت کردن.
|
||||
|
||||
اخترکِ اول مسکن پادشاهی بود که با شنلی از مخمل ارغوانی قاقم بر اورنگی بسیار ساده و در عین حال پرشکوه نشسته بود و همین که چشمش به شهریار کوچولو افتاد داد زد:
|
||||
-خب، این هم رعیت!
|
||||
شهریار کوچولو از خودش پرسید: -او که تا حالا هیچ وقت مرا ندیده چه جوری میتواند بشناسدم؟
|
||||
دیگر اینش را نخواندهبود که دنیابرای پادشاهان به نحو عجیبی ساده شده و تمام مردم فقط یک مشت رعیت به حساب میآیند.
|
||||
|
||||
پادشاه در سیارهاش
|
||||
پادشاه که میدید بالاخره شاهِ کسی شده و از این بابت کبکش خروس میخواند گفت: -بیا جلو بهتر ببینیمت. شهریار کوچولو با چشم پیِ جایی گشت که بنشیند اما شنلِ قاقمِ حضرتِ پادشاهی تمام اخترک را دربرگرفتهبود. ناچار همان طور سر پا ماند و چون سخت خسته بود به دهندره افتاد.
|
||||
شاه بهاش گفت: -خمیازه کشیدن در حضرتِ سلطان از نزاکت به دور است. این کار را برایت قدغن میکنم. شهریار کوچولو که سخت خجل شدهبود در آمد که:
|
||||
-نمیتوانم جلوِ خودم را بگیرم. راه درازی طیکردهام و هیچ هم نخوابیدهام...
|
||||
پادشاه گفت: -خب خب، پس بِت امر میکنم خمیازه بکشی. سالهاست خمیازهکشیدن کسی را ندیدهام برایم تازگی دارد. یاالله باز هم خمیازه بکش. این یک امر است.
|
||||
شهریار کوچولو گفت: -آخر این جوری من دست و پایم را گم میکنم... دیگر نمیتوانم.
|
||||
شاه گفت: -هوم! هوم! خب، پس من بهات امر میکنم که گاهی خمیازه بکشی گاهی نه.
|
||||
تند و نامفهوم حرف میزد و انگار خلقش حسابی تنگ بود.
|
||||
|
||||
پادشاه فقط دربند این بود که مطیع فرمانش باشند. در مورد نافرمانیها هم هیچ نرمشی از خودش نشان نمیداد. یک پادشاهِ تمام عیار بود گیرم چون زیادی خوب بود اوامری که صادر میکرد اوامری بود منطقی. مثلا خیلی راحت در آمد که: «اگر من به یکی از سردارانم امر کنم تبدیل به یکی از این مرغهای دریایی بشود و یارو اطاعت نکند تقسیر او نیست که، تقصیر خودم است».
|
||||
شهریار کوچولو در نهایت ادب پرسید: -اجازه میفرمایید بنشینم؟
|
||||
پادشاه که در نهایتِ شکوه و جلال چینی از شنل قاقمش را جمع میکرد گفت: -بهات امر میکنیم بنشینی.
|
||||
|
||||
منتها شهریار کوچولو ماندهبود حیران: آخر آن اخترک کوچکتر از آن بود که تصورش را بشود کرد. واقعا این پادشاه به چی سلطنت میکرد؟ گفت: -قربان عفو میفرمایید که ازتان سوال میکنم...
|
||||
پادشاه با عجله گفت: -بهات امر میکنیم از ما سوال کنی.
|
||||
-شما قربان به چی سلطنت میفرمایید؟
|
||||
پادشاه خیلی ساده گفت: -به همه چی.
|
||||
-به همهچی؟
|
||||
پادشاه با حرکتی قاطع به اخترک خودش و اخترکهای دیگر و باقی ستارهها اشاره کرد.
|
||||
شهریار کوچولو پرسید: -یعنی به همهی این ها؟
|
||||
شاه جواب داد: -به همهی این ها.
|
||||
آخر او فقط یک پادشاه معمولی نبود که، یک پادشاهِ جهانی بود.
|
||||
-آن وقت ستارهها هم سربهفرمانتانند؟
|
||||
پادشاه گفت: -البته که هستند. همهشان بیدرنگ هر فرمانی را اطاعت میکنند. ما نافرمانی را مطلقا تحمل نمیکنیم.
|
||||
|
||||
یک چنین قدرتی شهریار کوچولو را به شدت متعجب کرد. اگر خودش چنین قدرتی میداشت بی این که حتا صندلیش را یک ذره تکان بدهد روزی چهل و چهار بار که هیچ روزی هفتاد بار و حتا صدبار و دویستبار غروب آفتاب را تماشا میکرد! و چون بفهمی نفهمی از یادآوریِ اخترکش که به امان خدا ولکردهبود غصهاش شد جراتی به خودش داد که از پادشاه درخواست محبتی بکند:
|
||||
-دلم میخواست یک غروب آفتاب تماشا کنم... در حقم التفات بفرمایید امر کنید خورشید غروب کند.
|
||||
-اگر ما به یک سردار امر کنیم مثل شبپره از این گل به آن گل بپرد یا قصهی سوزناکی بنویسد یا به شکل مرغ دریایی در آید و او امریه را اجرا نکند کدام یکیمان مقصریم، ما یا او؟
|
||||
شهریار کوچولو نه گذاشت، نه برداشت، گفت: -شما.
|
||||
پادشاه گفت: -حرف ندارد. باید از هر کسی چیزی را توقع داشت که ازش ساخته باشد. قدرت باید پیش از هر چیز به عقل متکی باشد. اگر تو به ملتت فرمان بدهی که بروند خودشان را بیندازند تو دریا انقلاب میکنند. حق داریم توقع اطاعت داشته باشیم چون اوامرمان عاقلانه است.
|
||||
شهریار کوچولو که هیچ وقت چیزی را که پرسیده بود فراموش نمیکرد گفت: -غروب آفتاب من چی؟
|
||||
-تو هم به غروب آفتابت میرسی. امریهاش را صادر میکنیم. منتها با شَمِّ حکمرانیمان منتظریم زمینهاش فراهم بشود.
|
||||
شهریار کوچولو پرسید: -کِی فراهم میشود؟
|
||||
پادشاه بعد از آن که تقویم کَت و کلفتی را نگاه کرد جواب داد:
|
||||
-هوم! هوم! حدودِ... حدودِ... غروب. حدودِ ساعت هفت و چهل دقیقه... و آن وقت تو با چشمهای خودت میبینی که چهطور فرمان ما اجرا میشود!
|
||||
|
||||
شهریار کوچولو خمیازه کشید. از این که تماشای آفتاب غروب از کیسهاش رفتهبود تاسف میخورد. از آن گذشته دلش هم کمی گرفتهبود. این بود که به پادشاه گفت:
|
||||
-من دیگر اینجا کاری ندارم. میخواهم بروم.
|
||||
شاه که دلش برای داشتن یک رعیت غنج میزد گفت:
|
||||
-نرو! نرو! وزیرت میکنیم.
|
||||
-وزیرِ چی؟
|
||||
-وزیرِ دادگستری!
|
||||
-آخر این جا کسی نیست که محاکمه بشود.
|
||||
پادشاه گفت: -معلوم نیست. ما که هنوز گشتی دور قلمرومان نزدهایم. خیلی پیر شدهایم، برای کالسکه جا نداریم. پیادهروی هم خستهمان میکند.
|
||||
شهریار کوچولو که خم شدهبود تا نگاهی هم به آن طرف اخترک بیندازد گفت: -بَه! من نگاه کردهام، آن طرف هم دیارالبشری نیست.
|
||||
پادشاه بهاش جواب داد: -خب، پس خودت را محاکمه کن. این کار مشکلتر هم هست. محاکمه کردن خود از محاکمهکردن دیگران خیلی مشکل تر است. اگر توانستی در مورد خودت قضاوت درستی بکنی معلوم میشود یک فرزانهی تمام عیاری.
|
||||
شهریار کوچولو گفت: -من هر جا باشم میتوانم خودم را محاکمه کنم، چه احتیاجی است این جا بمانم؟ پادشاه گفت: -هوم! هوم! فکر میکنیم یک جایی تو اخترک ما یک موش پیر هست. صدایش را شب ها میشنویم. میتوانی او را به محاکمه بکشی و گاهگاهی هم به اعدام محکومش کنی. در این صورت زندگی او به عدالت تو بستگی پیدا میکند. گیرم تو هر دفعه عفوش میکنی تا همیشه زیر چاق داشته باشیش. آخر یکی بیشتر نیست که.
|
||||
شهریار کوچولو جواب داد: -من از حکم اعدام خوشم نمیآید. فکر میکنم دیگر باید بروم.
|
||||
پادشاه گفت: -نه!
|
||||
|
||||
اما شهریار کوچولو که آمادهی حرکت شده بود و ضمنا هم هیچ دلش نمیخواست اسباب ناراحتی سلطان پیر بشود گفت:
|
||||
-اگر اعلیحضرت مایلند اوامرشان دقیقا اجرا بشود میتوانند فرمان خردمندانهای در مورد بنده صادر بفرمایند. مثلا میتوانند به بنده امر کنند ظرف یک دقیقه راه بیفتم. تصور میکنم زمینهاش هم آماده باشد...
|
||||
چون پادشاه جوابی نداد شهریار کوچولو اول دو دل ماند اما بعد آهی کشید و به راه افتاد.
|
||||
آنوقت پادشاه با شتاب فریاد زد: -سفیر خودمان فرمودیمت!
|
||||
حالت بسیار شکوهمندی داشت.
|
||||
|
||||
شهریار کوچولو همان طور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۱
|
||||
اخترک دوم مسکن آدم خود پسندی بود.
|
||||
خود پسند چشمش که به شهریار کوچولو افتاد از همان دور داد زد: -بهبه! این هم یک ستایشگر که دارد میآید مرا ببیند!
|
||||
|
||||
خودپسند در سیارهاش
|
||||
آخر برای خودپسندها دیگران فقط یک مشت ستایشگرند.
|
||||
شهریار کوچولو گفت: -سلام! چه کلاه عجیب غریبی سرتان گذاشتهاید!
|
||||
خود پسند جواب داد: -مال اظهار تشکر است. منظورم موقعی است که هلهلهی ستایشگرهایم بلند میشود. گیرم متاسفانه تنابندهای گذارش به این طرفها نمیافتد.
|
||||
شهریار کوچولو که چیزی حالیش نشده بود گفت:
|
||||
-چی؟
|
||||
خودپسند گفت: -دستهایت را بزن به هم دیگر.
|
||||
شهریار کوچولو دست زد و خودپسند کلاهش را برداشت و متواضعانه از او تشکر کرد.
|
||||
شهریار کوچولو با خودش گفت: «دیدنِ این تفریحش خیلی بیشتر از دیدنِ پادشاهاست». و دوباره بنا کرد دستزدن و خودپسند با برداشتن کلاه بنا کرد تشکر کردن.
|
||||
|
||||
پس از پنج دقیقهای شهریار کوچولو که از این بازی یکنواخت خسته شده بود پرسید: -چه کار باید کرد که کلاه از سرت بیفتد؟
|
||||
اما خودپسند حرفش را نشنید. آخر آنها جز ستایش خودشان چیزی را نمیشنوند.
|
||||
از شهریار کوچولو پرسید: -تو راستی راستی به من با چشم ستایش و تحسین نگاه میکنی؟
|
||||
-ستایش و تحسین یعنی چه؟
|
||||
-یعنی قبول این که من خوشقیافهترین و خوشپوشترین و ثروتمندترین و باهوشترین مرد این اخترکم.
|
||||
-آخر روی این اخترک که فقط خودتی و کلاهت.
|
||||
-با وجود این ستایشم کن. این لطف را در حق من بکن.
|
||||
شهریار کوچولو نیمچه شانهای بالا انداخت و گفت: -خب، ستایشت کردم. اما آخر واقعا چیِ این برایت جالب است؟
|
||||
|
||||
شهریار کوچولو به راه افتاد و همان طور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۲
|
||||
تو اخترک بعدی میخوارهای مینشست. دیدار کوتاه بود اما شهریار کوچولو را به غم بزرگی فرو برد.
|
||||
|
||||
میخواره در سیارهاش
|
||||
|
||||
به میخواره که صُمبُکم پشت یک مشت بطری خالی و یک مشت بطری پر نشسته بود گفت: -چه کار داری میکنی؟
|
||||
میخواره با لحن غمزدهای جواب داد: -مِی میزنم.
|
||||
شهریار کوچولو پرسید: -مِی میزنی که چی؟
|
||||
میخواره جواب داد: -که فراموش کنم.
|
||||
شهریار کوچولو که حالا دیگر دلش برای او میسوخت پرسید: -چی را فراموش کنی؟
|
||||
میخواره همان طور که سرش را میانداخت پایین گفت: -سر شکستگیم را.
|
||||
شهریار کوچولو که دلش میخواست دردی از او دوا کند پرسید: -سرشکستگی از چی؟
|
||||
میخواره جواب داد: -سرشکستگیِ میخواره بودنم را.
|
||||
این را گفت و قال را کند و به کلی خاموش شد. و شهریار کوچولو مات و مبهوت راهش را گرفت و رفت و همان جور که میرفت تو دلش میگفت: -این آدم بزرگها راستیراستی چهقدر عجیبند!
|
||||
|
||||
۱۳
|
||||
اخترک چهارم اخترک مرد تجارتپیشه بود. این بابا چنان مشغول و گرفتار بود که با ورود شهریار کوچولو حتا سرش را هم بلند نکرد.
|
||||
|
||||
مردِ تجارتپیشه در سیارهاش
|
||||
شهریار کوچولو گفت: -سلام. آتشسیگارتان خاموش شده.
|
||||
-سه و دو میکند پنج. پنج و هفت دوازده و سه پانزده. سلام. پانزده و هفت بیست و دو. بیست و دو و شش بیست و هشت. وقت ندارم روشنش کنم. بیست و شش و پنج سی و یک. اوف! پس جمعش میکند پانصدویک میلیون و ششصد و بیست و دو هزار هفتصد و سی و یک.
|
||||
-پانصد میلیون چی؟
|
||||
-ها؟ هنوز این جایی تو؟ پانصد و یک میلیون چیز. چه میدانم، آن قدر کار سرم ریخته که!... من یک مرد جدی هستم و با حرفهای هشتمننهشاهی سر و کار ندارم!... دو و پنج هفت...
|
||||
شهریار کوچولو که وقتی چیزی میپرسید دیگر تا جوابش را نمیگرفت دست بردار نبود دوباره پرسید:
|
||||
-پانصد و یک میلیون چی؟
|
||||
تاجر پیشه سرش را بلند کرد:
|
||||
-تو این پنجاه و چهار سالی که ساکن این اخترکم همهاش سه بار گرفتار مودماغ شدهام. اولیش بیست و دو سال پیش یک سوسک بود که خدا میداند از کدام جهنم پیدایش شد. صدای وحشتناکی از خودش در میآورد که باعث شد تو یک جمع چهار جا اشتباه کنم. دفعهی دوم یازده سال پیش بود که استخوان درد بیچارهام کرد. من ورزش نمیکنم. وقت یللیتللی هم ندارم. آدمی هستم جدی... این هم بار سومش!... کجا بودم؟ پانصد و یک میلیون و...
|
||||
-این همه میلیون چی؟
|
||||
تاجرپیشه فهمید که نباید امید خلاصی داشته باشد. گفت: -میلیونها از این چیزهای کوچولویی که پارهای وقتها تو هوا دیده میشود.
|
||||
-مگس؟
|
||||
-نه بابا. این چیزهای کوچولوی براق.
|
||||
-زنبور عسل؟
|
||||
-نه بابا! همین چیزهای کوچولوی طلایی که وِلِنگارها را به عالم هپروت میبرد. گیرم من شخصا آدمی هستم جدی که وقتم را صرف خیالبافی نمیکنم.
|
||||
-آها، ستاره؟
|
||||
-خودش است: ستاره.
|
||||
-خب پانصد میلیون ستاره به چه دردت میخورد؟
|
||||
-پانصد و یک میلیون و ششصد و بیست و دو هزار و هفتصد و سی و یکی. من جدیّم و دقیق.
|
||||
-خب، به چه دردت میخورند؟
|
||||
-به چه دردم میخورند؟
|
||||
-ها.
|
||||
-هیچی تصاحبشان میکنم.
|
||||
-ستارهها را؟
|
||||
-آره خب.
|
||||
-آخر من به یک پادشاهی برخوردم که...
|
||||
-پادشاهها تصاحب نمیکنند بلکه بهاش «سلطنت» میکنند. این دو تا با هم خیلی فرق دارد.
|
||||
-خب، حالا تو آنها را تصاحب میکنی که چی بشود؟
|
||||
-که دارا بشوم.
|
||||
-خب دارا شدن به چه کارت میخورد؟
|
||||
-به این کار که، اگر کسی ستارهای پیدا کرد من ازش بخرم.
|
||||
شهریار کوچولو با خودش گفت: «این بابا هم منطقش یک خرده به منطق آن دائمالخمره میبَرَد.» با وجود این باز ازش پرسید:
|
||||
-چه جوری میشود یک ستاره را صاحب شد؟
|
||||
تاجرپیشه بی درنگ با اَخم و تَخم پرسید: -این ستارهها مال کیاند؟
|
||||
-چه میدانم؟ مال هیچ کس.
|
||||
-پس مال منند، چون من اول به این فکر افتادم.
|
||||
-همین کافی است؟
|
||||
-البته که کافی است. اگر تو یک جواهر پیدا کنی که مال هیچ کس نباشد میشود مال تو. اگر جزیرهای کشف کنی که مال هیچ کس نباشد میشود مال تو. اگر فکری به کلهات بزند که تا آن موقع به سر کسی نزده به اسم خودت ثبتش میکنی و میشود مال تو. من هم ستارهها را برای این صاحب شدهام که پیش از من هیچ کس به فکر نیفتاده بود آنها را مالک بشود.
|
||||
شهریار کوچولو گفت: -این ها همهاش درست. منتها چه کارشان میکنی؟
|
||||
تاجر پیشه گفت: -ادارهشان میکنم، همین جور میشمارمشان و میشمارمشان. البته کار مشکلی است ولی خب دیگر، من آدمی هستم بسیار جدی.
|
||||
شهریار کوچولو که هنوز این حرف تو کَتَش نرفتهبود گفت:
|
||||
-اگر من یک شال گردن ابریشمی داشته باشم میتوانم بپیچم دور گردنم با خودم ببرمش. اگر یک گل داشته باشم میتوانم بچینم با خودم ببرمش. اما تو که نمیتوانی ستارهها را بچینی!
|
||||
-نه. اما میتوانم بگذارمشان تو بانک.
|
||||
-اینی که گفتی یعنی چه؟
|
||||
-یعنی این که تعداد ستارههایم را رو یک تکه کاغذ مینویسم میگذارم تو کشو درش را قفل میکنم.
|
||||
-همهاش همین؟
|
||||
-آره همین کافی است.
|
||||
|
||||
شهریار کوچولو فکر کرد «جالب است. یک خرده هم شاعرانه است. اما کاری نیست که آن قدرها جدیش بشود گرفت». آخر تعبیر او از چیزهای جدی با تعبیر آدمهای بزرگ فرق میکرد.
|
||||
باز گفت: -من یک گل دارم که هر روز آبش میدهم. سه تا هم آتشفشان دارم که هفتهای یک بار پاک و دودهگیریشان میکنم. آخر آتشفشان خاموشه را هم پاک میکنم. آدم کفِ دستش را که بو نکرده! رو این حساب، هم برای آتشفشانها و هم برای گل این که من صاحبشان باشم فایده دارد. تو چه فایدهای به حال ستارهها داری؟
|
||||
|
||||
تاجرپیشه دهن باز کرد که جوابی بدهد اما چیزی پیدا نکرد. و شهریار کوچولو راهش را گرفت و رفت و همان جور که میرفت تو دلش میگفت: -این آدم بزرگها راستی راستی چهقدر عجیبند!
|
||||
|
||||
۱۴
|
||||
اخترکِ پنجم چیز غریبی بود. از همهی اخترکهای دیگر کوچکتر بود، یعنی فقط به اندازهی یک فانوس پایهدار و یک فانوسبان جا داشت.
|
||||
|
||||
فانوسبان در حالِ روشن کردنِ فانوس در سیارهاش
|
||||
شهریار کوچولو از این راز سر در نیاورد که یک جا میان آسمان خدا تو اخترکی که نه خانهای روش هست نه آدمی، حکمت وجودی یک فانوس و یک فانوسبان چه میتواند باشد. با وجود این تو دلش گفت:
|
||||
-خیلی احتمال دارد که این بابا عقلش پارهسنگ ببرد. اما به هر حال از پادشاه و خودپسند و تاجرپیشه و مسته کم عقلتر نیست. دست کم کاری که میکند یک معنایی دارد. فانوسش را که روشن میکند عینهو مثل این است که یک ستارهی دیگر یا یک گل به دنیا میآورد و خاموشش که میکند پنداری گل یا ستارهای را میخواباند. سرگرمی زیبایی است و چیزی که زیبا باشد بی گفتوگو مفید هم هست.
|
||||
|
||||
وقتی رو اخترک پایین آمد با ادب فراوان به فانوسبان سلام کرد:
|
||||
-سلام. واسه چی فانوس را خاموش کردی؟
|
||||
-دستور است. صبح به خیر!
|
||||
-دستور چیه؟
|
||||
-این است که فانوسم را خاموش کنم. شب خوش!
|
||||
و دوباره فانوس را روشن کرد.
|
||||
-پس چرا روشنش کردی باز؟
|
||||
فانوسبان جواب داد: -خب دستور است دیگر.
|
||||
شهریار کوچولو گفت: -اصلا سر در نمیارم.
|
||||
فانوسبان گفت: -چیز سر در آوردنییی توش نیست که. دستور دستور است. روز بخیر!
|
||||
و باز فانوس را خاموش کرد.
|
||||
بعد با دستمال شطرنجی قرمزی عرق پیشانیش را خشکاند و گفت:
|
||||
-کار جانفرسایی دارم. پیشتر ها معقول بود: صبح خاموشش میکردم و شب که میشد روشنش میکردم. باقی روز را فرصت داشتم که استراحت کنم و باقی شب را هم میتوانستم بگیرم بخوابم...
|
||||
-بعدش دستور عوض شد؟
|
||||
فانوسبان گفت: -دستور عوض نشد و بدبختی من هم از همین جاست: سیاره سال به سال گردشش تندتر و تندتر شده اما دستور همان جور به قوت خودش باقی مانده است.
|
||||
-خب؟
|
||||
-حالا که سیاره دقیقهای یک بار دور خودش میگردد دیگر من یک ثانیه هم فرصت استراحت ندارم: دقیقهای یک بار فانوس را روشن میکنم یک بار خاموش.
|
||||
-چه عجیب است! تو اخترک تو شبانه روز همهاش یک دقیقه طول میکشد!
|
||||
فانوسبان گفت: -هیچ هم عجیب نیست. الان یک ماه تمام است که ما داریم با هم اختلاط میکنیم.
|
||||
-یک ماه؟
|
||||
-آره. سی دقیقه. سی روز! شب خوش!
|
||||
و دوباره فانوس را روشن کرد.
|
||||
|
||||
شهریار کوچولو به فانوسبان نگاه کرد و حس کرد این مرد را که تا این حد به دستور وفادار است دوست میدارد. یادِ آفتابغروبهایی افتاد که آن وقتها خودش با جابهجا کردن صندلیش دنبال میکرد. برای این که دستی زیر بال دوستش کرده باشد گفت:
|
||||
-میدانی؟ یک راهی بلدم که میتوانی هر وقت دلت بخواهد استراحت کنی.
|
||||
فانوسبان گفت: -آرزوش را دارم.
|
||||
آخر آدم میتواند هم به دستور وفادار بماند هم تنبلی کند.
|
||||
شهریار کوچولو دنبال حرفش را گرفت و گفت:
|
||||
-تو، اخترکت آنقدر کوچولوست که با سه تا شلنگ برداشتن میتوانی یک بار دور بزنیش. اگر آن اندازه که لازم است یواش راه بروی میتوانی کاری کنی که مدام تو آفتاب بمانی. پس هر وقت خواستی استراحت کنی شروع میکنی به راهرفتن... به این ترتیب روز هرقدر که بخواهی برایت کِش میآید.
|
||||
فانوسبان گفت: -این کار گرهی از بدبختی من وا نمیکند. تنها چیزی که تو زندگی آرزویش را دارم یک چرت خواب است.
|
||||
شهریار کوچولو گفت: -این یکی را دیگر باید بگذاری در کوزه.
|
||||
فانوسبان گفت: -آره. باید بگذارمش در کوزه... صبح بخیر!
|
||||
و فانوس را خاموش کرد.
|
||||
|
||||
شهریار کوچولو میان راه با خودش گفت: گرچه آنهای دیگر، یعنی خودپسنده و تاجره اگر این را میدیدند دستش میانداختند و تحقیرش میکردند، هر چه نباشد کار این یکی به نظر من کمتر از کار آنها بیمعنی و مضحک است. شاید به خاطر این که دست کم این یکی به چیزی جز خودش مشغول است.
|
||||
|
||||
از حسرت آهی کشید و همان طور با خودش گفت:
|
||||
-این تنها کسی بود که من میتوانستم باش دوست بشوم. گیرم اخترکش راستی راستی خیلی کوچولو است و دو نفر روش جا نمیگیرند.
|
||||
|
||||
چیزی که جرات اعترافش را نداشت حسرت او بود به این اخترک کوچولویی که، بخصوص، به هزار و چهارصد و چهل بار غروب آفتاب در هر بیست و چهار ساعت برکت پیدا کرده بود.
|
||||
|
||||
۱۵
|
||||
اخترک ششم اخترکی بود ده بار فراختر، و آقاپیرهای توش بود که کتابهای کَتوکلفت مینوشت.
|
||||
|
||||
جغرافیدان در سیارهاش
|
||||
همین که چشمش به شهریار کوچولو افتاد با خودش گفت:
|
||||
-خب، این هم یک کاشف!
|
||||
شهریار کوچولو لب میز نشست و نفس نفس زد. نه این که راه زیادی طی کرده بود؟
|
||||
آقا پیره بهاش گفت: -از کجا میآیی؟
|
||||
شهریار کوچولو گفت: -این کتاب به این کلفتی چی است؟ شما اینجا چهکار میکنید؟
|
||||
آقا پیره گفت: -من جغرافیدانم.
|
||||
-جغرافیدان چه باشد؟
|
||||
-جغرافیدان به دانشمندی میگویند که جای دریاها و رودخانهها و شهرها و کوهها و بیابانها را میداند.
|
||||
شهریار کوچولو گفت: -محشر است. یک کار درست و حسابی است.
|
||||
و به اخترک جغرافیدان، این سو و آنسو نگاهی انداخت. تا آن وقت اخترکی به این عظمت ندیدهبود.
|
||||
-اخترکتان خیلی قشنگ است. اقیانوس هم دارد؟
|
||||
جغرافیدان گفت: -از کجا بدانم؟
|
||||
شهریار کوچولو گفت: -عجب! (بد جوری جا خورده بود) کوه چهطور؟
|
||||
جغرافیدان گفت: -از کجا بدانم؟
|
||||
-شهر، رودخانه، بیابان؟
|
||||
جغرافیدان گفت: از اینها هم خبری ندارم.
|
||||
-آخر شما جغرافیدانید؟
|
||||
جغرافیدان گفت: -درست است ولی کاشف که نیستم. من حتا یک نفر کاشف هم ندارم. کار جغرافیدان نیست که دورهبیفتد برود شهرها و رودخانهها و کوهها و دریاها و اقیانوسها و بیابانها را بشمرد. مقام جغرافیدان برتر از آن است که دوره بیفتد و ولبگردد. اصلا از اتاق کارش پا بیرون نمیگذارد بلکه کاشفها را آن تو میپذیرد ازشان سوالات میکند و از خاطراتشان یادداشت بر میدارد و اگر خاطرات یکی از آنها به نظرش جالب آمد دستور میدهد روی خُلقیات آن کاشف تحقیقاتی صورت بگیرد.
|
||||
-برای چه؟
|
||||
-برای این که اگر کاشفی گندهگو باشد کار کتابهای جغرافیا را به فاجعه میکشاند. هکذا کاشفی که اهل پیاله باشد.
|
||||
-آن دیگر چرا؟
|
||||
b-چون آدمهای دائمالخمر همه چیز را دوتا میبینند. آن وقت جغرافیدان برمیدارد جایی که یک کوه
|
||||
بیشتر نیست مینویسد دو کوه.
|
||||
شهریار کوچولو گفت: -پس من یک بابایی را میشناسم که کاشف هجوی از آب در میآید.
|
||||
-بعید نیست. بنابراین، بعد از آن که کاملا ثابت شد پالان کاشف کج نیست تحقیقاتی هم روی کشفی که کرده انجام میگیرد.
|
||||
-یعنی میروند میبینند؟
|
||||
-نه، این کار گرفتاریش زیاد است. از خود کاشف میخواهند دلیل بیاورد. مثلا اگر پای کشف یک کوه بزرگ در میان بود ازش میخواهند سنگهای گندهای از آن کوه رو کند.
|
||||
جغرافیدان ناگهان به هیجان در آمد و گفت: -راستی تو داری از راه دوری میآیی! تو کاشفی! باید چند و چون اخترکت را برای من بگویی.
|
||||
و با این حرف دفتر و دستکش را باز کرد و مدادش را تراشید. معمولا خاطرات کاشفها را اول بامداد یادداشت میکنند و دست نگه میدارند تا دلیل اقامه کند، آن وقت با جوهر مینویسند.
|
||||
گفت: -خب؟
|
||||
شهریار کوچولو گفت: -اخترک من چیز چندان جالبی ندارد. آخر خیلی کوچک است. سه تا آتشفشان دارم که دوتاش فعال است یکیش خاموش. اما، خب دیگر، آدم کف دستش را که بو نکرده.
|
||||
جغرافیدان هم گفت: -آدم چه میداند چه پیش میآید.
|
||||
-یک گل هم دارم.
|
||||
-نه، نه، ما دیگر گل ها را یادداشت نمیکنیم.
|
||||
-چرا؟ گل که زیباتر است.
|
||||
-برای این که گلها فانیاند.
|
||||
-فانی یعنی چی؟
|
||||
جغرافیدان گفت: -کتابهای جغرافیا از کتابهای دیگر گرانبهاترست و هیچ وقت هم از اعتبار نمیافتد. بسیار به ندرت ممکن است یک کوه جا عوض کند. بسیار به ندرت ممکن است آب یک اقیانوس خالی شود. ما فقط چیزهای پایدار را مینویسیم.
|
||||
شهریار کوچولو تو حرف او دوید و گفت: -اما آتشفشانهای خاموش میتوانند از نو بیدار بشوند. فانی را نگفتید یعنی چه؟
|
||||
جغرافیدان گفت: -آتشفشان چه روشن باشد چه خاموش برای ما فرقی نمیکند. آنچه به حساب میآید خود کوه است که تغییر پیدا نمیکند.
|
||||
شهریار کوچولو که تو تمام عمرش وقتی چیزی از کسی میپرسید دیگر دست بردار نبود دوباره سوال کرد: -فانی یعنی چه؟
|
||||
-یعنی چیزی که در آینده تهدید به نابودی شود.
|
||||
-گل من هم در آینده نابود میشود؟
|
||||
-البته که میشود.
|
||||
شهریار کوچولو در دل گفت: «گل من فانی است و جلو دنیا برای دفاع از خودش جز چهارتا خار هیچی ندارد، و آن وقت مرا بگو که او را توی اخترکم تک و تنها رها کردهام!»
|
||||
این اولین باری بود که دچار پریشانی و اندوه میشد اما توانست به خودش مسلط بشود. پرسید: -شما به من دیدن کجا را توصیه میکنید؟
|
||||
جغرافیدان بهاش جواب داد: -سیارهی زمین. شهرت خوبی دارد...
|
||||
|
||||
و شهریار کوچولو هم چنان که به گلش فکر میکرد به راه افتاد.
|
||||
|
||||
۱۶
|
||||
لاجرم، زمین، سیارهی هفتم شد.
|
||||
|
||||
زمین، فلان و بهمان سیاره نیست. رو پهنهی زمین یکصد و یازده پادشاه (البته بامحاسبهی پادشاهان سیاهپوست)، هفت هزار جغرافیدان، نهصد هزار تاجرپیشه، پانزده کرور میخواره و ششصد و بیست و دو کرور خودپسند و به عبارت دیگر حدود دو میلیارد آدم بزرگ زندگی میکند. برای آنکه از حجم زمین مقیاسی به دستتان بدهم بگذارید بهتان بگویم که پیش از اختراع برق مجبور بودند در مجموع شش قارهی زمین وسایل زندگیِ لشکری جانانه شامل یکصد و شصت و دو هزار و پانصد و یازده نفر فانوسبان را تامین کنند.
|
||||
|
||||
روشن شدن فانوسها از دور خیلی باشکوه بود. حرکات این لشکر مثل حرکات یک بالهی تو اپرا مرتب و منظم بود. اول از همه نوبت فانوسبانهای زلاندنو و استرالیا بود. اینها که فانوسهاشان را روشن میکردند، میرفتند میگرفتند میخوابیدند آن وقت نوبت فانوسبانهای چین و سیبری میرسید که به رقص درآیند. بعد، اینها با تردستی تمام به پشت صحنه میخزیدند و جا را برای فانوسبانهای ترکیه و هفت پَرکَنِهی هند خالی می کردند. بعد نوبت به فانوسبانهای آمریکایجنوبی میشد. و آخر سر هم نوبت فانوسبانهای افریقا و اروپا میرسد و بعد نوبت فانوسبانهای آمریکای شمالی بود. و هیچ وقتِ خدا هم هیچکدام اینها در ترتیب ورودشان به صحنه دچار اشتباه نمیشدند. چه شکوهی داشت! میان این جمع عظیم فقط نگهبانِ تنها فانوسِ قطب شمال و همکارش نگهبانِ تنها فانوسِ قطب جنوب بودند که عمری به بطالت و بیهودگی میگذراندند: آخر آنها سالی به سالی همهاش دو بار کار میکردند.
|
||||
|
||||
۱۷
|
||||
آدمی که اهل اظهار لحیه باشد بفهمی نفهمی میافتد به چاخان کردن. من هم تو تعریف قضیهی فانوسبانها برای شما آنقدرهاروراست نبودم. میترسم به آنهایی که زمین ما را نمیسناسند تصور نادرستی داده باشم. انسانها رو پهنهی زمین جای خیلی کمی را اشغال میکنند. اگر همهی دو میلیارد نفری که رو کرهی زمین زندگی میکنند بلند بشوند و مثل موقعی که به تظاهرات میروند یک خورده جمع و جور بایستند راحت و بیدرپسر تو میدانی به مساحت بیست میل در بیست میل جا میگیرند. همهی جامعهی بشری را میشود یکجا روی کوچکترین جزیرهی اقیانوس آرام کُپه کرد.
|
||||
|
||||
البته گفتوگو ندارد که آدم بزرگها حرفتان را باور نمیکنند. آخر تصور آنها این است که کلی جا اشغال کردهاند، نه اینکه مثل بائوبابها خودشان را خیلی مهم میبینند؟ بنابراین بهشان پیشنهاد میکنید که بنشینند حساب کنند. آنها هم که عاشق اعداد و ارقامند، پس این پیشنهاد حسابی کیفورشان میکند. اما شما را به خدا بیخودی وقت خودتان را سر این جریمهی مدرسه به هدر ندهید. این کار دو قاز هم نمیارزد. به من که اطمینان دارید. شهریار کوچولو پاش که به زمین رسید از این که دیارالبشری دیده نمیشد سخت هاج و واج ماند.
|
||||
|
||||
شهریار کوچولو وسطِ کویر
|
||||
تازه داشت از این فکر که شاید سیاره را عوضی گرفته ترسش بر میداشت که چنبرهی مهتابی رنگی رو ماسهها جابهجا شد.شهریار کوچولو و مار
|
||||
شهریار کوچولو همینجوری سلام کرد.
|
||||
مار گفت: -سلام.
|
||||
شهریار کوچولو پرسید: -رو چه سیارهای پایین آمدهام؟
|
||||
مار جواب داد: -رو زمین تو قارهی آفریقا.
|
||||
-عجب! پس رو زمین انسان به هم نمیرسد؟
|
||||
مار گفت: -اینجا کویر است. تو کویر کسی زندگی نمیکند. زمین بسیار وسیع است.
|
||||
شهریار کوچولو رو سنگی نشست و به آسمان نگاه کرد. گفت: -به خودم میگویم ستارهها واسه این روشنند که هرکسی بتواند یک روز مال خودش را پیدا کند!... اخترک مرا نگاه! درست بالا سرمان است... اما چهقدر دور است!
|
||||
مار گفت: -قشنگ است. اینجا آمدهای چه کار؟
|
||||
شهریار کوچولو گفت: -با یک گل بگومگویم شده.
|
||||
مار گفت: -عجب!
|
||||
و هر دوشان خاموش ماندند.
|
||||
دست آخر شهریار کوچولو درآمد که: -آدمها کجاند؟ آدم تو کویر یک خرده احساس تنهایی میکند.
|
||||
مار گفت: -پیش آدمها هم احساس تنهایی میکنی.
|
||||
شهریار کوچولو مدت درازی تو نخ او رفت و آخر سر بهاش گفت: -تو چه جانور بامزهای هستی! مثل یک انگشت، باریکی.
|
||||
مار گفت: -عوضش از انگشت هر پادشاهی مقتدرترم.
|
||||
شهریار کوچولو لبخندی زد و گفت: -نه چندان... پا هم که نداری. حتا راه هم نمیتونی بری...
|
||||
-من میتونم تو را به چنان جای دوری ببرم که با هیچ کشتییی هم نتونی بری.
|
||||
مار این را گفت و دور قوزک پای شهریار کوچولو پیچید. عین یک خلخال طلا. و باز درآمد که: -هر کسی را لمس کنم به خاکی که ازش درآمده بر میگردانم اما تو پاکی و از یک سیّارهی دیگر آمدهای...
|
||||
شهریار کوچولو جوابی بش نداد.
|
||||
-تو رو این زمین خارایی آنقدر ضعیفی که به حالت رحمم میآید. روزیروزگاری اگر دلت خیلی هوای اخترکت را کرد بیا من کمکت کنم... من میتوانم...
|
||||
شهریار کوچولو گفت: -آره تا تهش را خواندم. اما راستی تو چرا همهی حرفهایت را به صورت معما درمیآری؟
|
||||
|
||||
مار گفت: -حلّال همهی معماهام من.
|
||||
و هر دوشان خاموش شدند.
|
||||
|
||||
۱۸
|
||||
شهریار کوچولو کویر را از پاشنه درکرد و جز یک گل به هیچی برنخورد: یک گل سه گلبرگه. یک گلِ ناچیز.
|
||||
|
||||
یک گُل وسطِ کویر
|
||||
|
||||
شهریار کوچولو گفت: -سلام.
|
||||
گل گفت: -سلام.
|
||||
شهریار کوچولو با ادب پرسید: -آدمها کجاند؟
|
||||
گل روزی روزگاری عبور کاروانی را دیدهبود. این بود که گفت: -آدمها؟ گمان کنم ازشان شش هفت تایی باشد. سالها پیش دیدمشان. منتها خدا میداند کجا میشود پیداشان کرد. باد اینور و آنور میبَرَدشان؛ نه این که ریشه ندارند؟ بیریشگی هم حسابی اسباب دردسرشان شده.
|
||||
شهریار کوچولو گفت: -خداحافظ.
|
||||
گل گفت: -خداحافظ.
|
||||
|
||||
۱۹
|
||||
از کوه بلندی بالا رفت.
|
||||
|
||||
شهریار کوچولو بر قلهی کوهِ بلند
|
||||
تنها کوههایی که به عمرش دیده بود سه تا آتشفشانهای اخترک خودش بود که تا سر زانویش میرسید و از آن یکی که خاموش بود جای چارپایه استفاده میکرد. این بود که با خودش گفت: «از سر یک کوه به این بلندی میتوانم به یک نظر همهی سیاره و همهی آدمها را ببینم...» اما جز نوکِ تیزِ صخرههای نوکتیز چیزی ندید.
|
||||
همین جوری گفت: -سلام.
|
||||
طنین بهاش جواب داد: -سلام... سلام... سلام...
|
||||
شهریار کوچولو گفت: -کی هستید شما؟
|
||||
طنین بهاش جواب داد: -کی هستید شما... کی هستید شما... کی هستید شما...
|
||||
گفت: -با من دوست بشوید. من تک و تنهام.
|
||||
طنین بهاش جواب داد: -من تک و تنهام... من تک و تنهام... من تک و تنهام...
|
||||
آنوقت با خودش فکر کرد: «چه سیارهی عجیبی! خشکِخشک و تیزِتیز و شورِشور. این آدمهاش که یک ذره قوهی تخیل ندارند و هر چه را بشنوند عینا تکرار میکنند... تو اخترک خودم گلی داشتم که همیشه اول او حرف میزد...»
|
||||
|
||||
۲۰
|
||||
اما سرانجام، بعد از مدتها راه رفتن از میان ریگها و صخرهها و برفها به جادهای برخورد. و هر جادهای یکراست میرود سراغ آدمها.
|
||||
گفت: -سلام.
|
||||
و مخاطبش گلستان پرگلی بود.
|
||||
|
||||
شهریار کوچولو در گلستانِ پرگل
|
||||
|
||||
گلها گفتند: -سلام.
|
||||
شهریار کوچولو رفت تو بحرشان. همهشان عین گل خودش بودند. حیرتزده ازشان پرسید: -شماها کی هستید؟
|
||||
گفتند: -ما گل سرخیم.
|
||||
|
||||
آهی کشید و سخت احساس شوربختی کرد. گلش به او گفته بود که از نوع او تو تمام عالم فقط همان یکی هست و حالا پنجهزارتا گل، همه مثل هم، فقط تو یک گلستان! فکر کرد: «اگر گل من این را میدید بدجور از رو میرفت. پشت سر هم بنا میکرد سرفهکردن و، برای اینکه از هُوشدن نجات پیدا کند خودش را به مردن میزد و من هم مجبور میشدم وانمود کنم به پرستاریش، وگرنه برای سرشکسته کردنِ من هم شده بود راستی راستی میمرد...» و باز تو دلش گفت: «مرا باش که فقط بایک دانه گل خودم را دولتمندِ عالم خیال میکردم در صورتیکه آنچه دارم فقط یک گل معمولی است. با آن گل و آن سه تا آتشفشان که تا سرِ زانومَند و شاید هم یکیشان تا ابد خاموش بماند شهریارِ چندان پُرشوکتی به حساب نمیآیم.»
|
||||
|
||||
شهریار کوچولو در حالِ احساسِ شوربختی
|
||||
رو سبزهها دراز شد و حالا گریه نکن کی گریهکن.
|
||||
|
||||
۲۱
|
||||
آن وقت بود که سر و کلهی روباه پیدا شد.
|
||||
|
||||
شهریار کوچولو و روباه
|
||||
|
||||
روباه گفت: -سلام.
|
||||
شهریار کوچولو برگشت اما کسی را ندید. با وجود این با ادب تمام گفت: -سلام.
|
||||
صداگفت: -من اینجام، زیر درخت سیب...
|
||||
شهریار کوچولو گفت: -کی هستی تو؟ عجب خوشگلی!
|
||||
روباه گفت: -یک روباهم من.
|
||||
شهریار کوچولو گفت: -بیا با من بازی کن. نمیدانی چه قدر دلم گرفته...
|
||||
روباه گفت: -نمیتوانم بات بازی کنم. هنوز اهلیم نکردهاند آخر.
|
||||
شهریار کوچولو آهی کشید و گفت: -معذرت میخواهم.
|
||||
اما فکری کرد و پرسید: -اهلی کردن یعنی چه؟
|
||||
روباه گفت: -تو اهل اینجا نیستی. پی چی میگردی؟
|
||||
شهریار کوچولو گفت: -پی آدمها میگردم. نگفتی اهلی کردن یعنی چه؟
|
||||
روباه گفت: -آدمها تفنگ دارند و شکار میکنند. اینش اسباب دلخوری است! اما مرغ و ماکیان هم پرورش میدهند و خیرشان فقط همین است. تو پی مرغ میکردی؟
|
||||
شهریار کوچولو گفت: -نَه، پیِ دوست میگردم. اهلی کردن یعنی چی؟
|
||||
روباه گفت: -یک چیزی است که پاک فراموش شده. معنیش ایجاد علاقه کردن است.
|
||||
-ایجاد علاقه کردن؟
|
||||
روباه گفت: -معلوم است. تو الان واسه من یک پسر بچهای مثل صد هزار پسر بچهی دیگر. نه من هیچ احتیاجی به تو دارم نه تو هیچ احتیاجی به من. من هم واسه تو یک روباهم مثل صد هزار روباه دیگر. اما اگر منو اهلی کردی هر دوتامان به هم احتیاج پیدا میکنیم. تو واسه من میان همهی عالم موجود یگانهای میشوی من واسه تو.
|
||||
شهریار کوچولو گفت: -کمکم دارد دستگیرم میشود. یک گلی هست که گمانم مرا اهلی کرده باشد.
|
||||
روباه گفت: -بعید نیست. رو این کرهی زمین هزار جور چیز میشود دید.
|
||||
شهریار کوچولو گفت: -اوه نه! آن رو کرهی زمین نیست.
|
||||
روباه که انگار حسابی حیرت کرده بود گفت: -رو یک سیارهی دیگر است؟
|
||||
-آره.
|
||||
شکارچی-تو آن سیاره شکارچی هم هست؟
|
||||
-نه.
|
||||
-محشر است! مرغ و ماکیان چهطور؟
|
||||
-نه.
|
||||
روباه آهکشان گفت: -همیشهی خدا یک پای بساط لنگ است!
|
||||
اما پی حرفش را گرفت و گفت: -زندگی یکنواختی دارم. من مرغها را شکار میکنم آدمها مرا. همهی مرغها عین همند همهی آدمها هم عین همند. این وضع یک خرده خلقم را تنگ میکند. اما اگر تو منو اهلی کنی انگار که زندگیم را چراغان کرده باشی. آن وقت صدای پایی را میشناسم که باهر صدای پای دیگر فرق میکند: صدای پای دیگران مرا وادار میکند تو هفت تا سوراخ قایم بشوم اما صدای پای تو مثل نغمهای مرا از سوراخم میکشد بیرون. تازه، نگاه کن آنجا آن گندمزار را میبینی؟ برای من که نان بخور نیستم گندم چیز بیفایدهای است. پس گندمزار هم مرا به یاد چیزی نمیاندازد. اسباب تاسف است. اما تو موهات رنگ طلا است. پس وقتی اهلیم کردی محشر میشود! گندم که طلایی رنگ است مرا به یاد تو میاندازد و صدای باد را هم که تو گندمزار میپیچد دوست خواهم داشت...
|
||||
خاموش شد و مدت درازی شهریار کوچولو را نگاه کرد. آن وقت گفت: -اگر دلت میخواهد منو اهلی کن!
|
||||
شهریار کوچولو جواب داد: -دلم که خیلی میخواهد، اما وقتِ چندانی ندارم. باید بروم دوستانی پیدا کنم و از کلی چیزها سر در آرم.
|
||||
روباه گفت: -آدم فقط از چیزهایی که اهلی کند میتواند سر در آرد. انسانها دیگر برای سر در آوردن از چیزها وقت ندارند. همه چیز را همین جور حاضر آماده از دکانها میخرند. اما چون دکانی نیست که دوست معامله کند آدمها ماندهاند بیدوست... تو اگر دوست میخواهی خب منو اهلی کن!
|
||||
شهریار کوچولو پرسید: -راهش چیست؟
|
||||
روباه جواب داد: -باید خیلی خیلی حوصله کنی. اولش یک خرده دورتر از من میگیری این جوری میان علفها مینشینی. من زیر چشمی نگاهت میکنم و تو لامتاکام هیچی نمیگویی، چون تقصیر همهی سؤِتفاهمها زیر سر زبان است. عوضش میتوانی هر روز یک خرده نزدیکتر بنشینی.
|
||||
|
||||
روباه در حالِ انتظارفردای آن روز دوباره شهریار کوچولو آمد.
|
||||
روباه گفت: -کاش سر همان ساعت دیروز آمده بودی. اگر مثلا سر ساعت چهار بعد از ظهر بیایی من از ساعت سه تو دلم قند آب میشود و هر چه ساعت جلوتر برود بیشتر احساس شادی و خوشبختی میکنم. ساعت چهار که شد دلم بنا میکند شور زدن و نگران شدن. آن وقت است که قدرِ خوشبختی را میفهمم! اما اگر تو وقت و بی وقت بیایی من از کجا بدانم چه ساعتی باید دلم را برای دیدارت آماده کنم؟... هر چیزی برای خودش قاعدهای دارد.
|
||||
شهریار کوچولو گفت: -قاعده یعنی چه؟
|
||||
روباه گفت: -این هم از آن چیزهایی است که پاک از خاطرها رفته. این همان چیزی است که باعث میشود فلان روز با باقی روزها و فلان ساعت با باقی ساعتها فرق کند. مثلا شکارچیهای ما میان خودشان رسمی دارند و آن این است که پنجشنبهها را با دخترهای ده میروند رقص. پس پنجشنبهها بَرّهکشانِ من است: برای خودم گردشکنان میروم تا دم مُوِستان. حالا اگر شکارچیها وقت و بی وقت میرقصیدند همهی روزها شبیه هم میشد و منِ بیچاره دیگر فرصت و فراغتی نداشتم.
|
||||
|
||||
به این ترتیب شهریار کوچولو روباه را اهلی کرد.
|
||||
لحظهی جدایی که نزدیک شد روباه گفت: -آخ! نمیتوانم جلو اشکم را بگیرم.
|
||||
شهریار کوچولو گفت: -تقصیر خودت است. من که بدت را نمیخواستم، خودت خواستی اهلیت کنم.
|
||||
روباه گفت: -همین طور است.
|
||||
شهریار کوچولو گفت: -آخر اشکت دارد سرازیر میشود!
|
||||
روباه گفت: -همین طور است.
|
||||
-پس این ماجرا فایدهای به حال تو نداشته.
|
||||
روباه گفت: -چرا، واسه خاطرِ رنگ گندم.
|
||||
بعد گفت: -برو یک بار دیگر گلها را ببین تا بفهمی که گلِ خودت تو عالم تک است. برگشتنا با هم وداع میکنیم و من به عنوان هدیه رازی را بهات میگویم.
|
||||
شهریار کوچولو بار دیگر به تماشای گلها رفت و به آنها گفت: -شما سرِ سوزنی به گل من نمیمانید و هنوز هیچی نیستید. نه کسی شما را اهلی کرده نه شما کسی را. درست همان جوری هستید که روباه من بود: روباهی بود مثل صدهزار روباه دیگر. او را دوست خودم کردم و حالا تو همهی عالم تک است.
|
||||
گلها حسابی از رو رفتند.
|
||||
شهریار کوچولو دوباره درآمد که: -خوشگلید اما خالی هستید. برایتان نمیشود مُرد. گفتوگو ندارد که گلِ مرا هم فلان رهگذر میبیند مثل شما. اما او به تنهایی از همهی شما سر است چون فقط اوست که آبش دادهام، چون فقط اوست که زیر حبابش گذاشتهام، چون فقط اوست که با تجیر برایش حفاظ درست کردهام، چون فقط اوست که حشراتش را کشتهام (جز دو سهتایی که میبایست شبپره بشوند)، چون فقط اوست که پای گِلِهگزاریها یا خودنماییها و حتا گاهی پای بُغ کردن و هیچی نگفتنهاش نشستهام، چون او گلِ من است.
|
||||
و برگشت پیش روباه.
|
||||
گفت: -خدانگهدار!
|
||||
روباه گفت: -خدانگهدار!... و اما رازی که گفتم خیلی ساده است:
|
||||
جز با دل هیچی را چنان که باید نمیشود دید. نهاد و گوهر را چشمِ سَر نمیبیند.
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -نهاد و گوهر را چشمِ سَر نمیبیند.
|
||||
-ارزش گل تو به قدرِ عمری است که به پاش صرف کردهای.
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -به قدر عمری است که به پاش صرف کردهام.
|
||||
روباه گفت: -انسانها این حقیقت را فراموش کردهاند اما تو نباید فراموشش کنی. تو تا زندهای نسبت به چیزی که اهلی کردهای مسئولی. تو مسئول گُلِتی...
|
||||
|
||||
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -من مسئول گُلمَم.
|
||||
|
||||
۲۲
|
||||
شهریار کوچولو گفت: -سلام.
|
||||
سوزنبان گفت: -سلام.
|
||||
شهریار کوچولو گفت: -تو چه کار میکنی اینجا؟
|
||||
سوزنبان گفت: -مسافرها را به دستههای هزارتایی تقسیم میکنم و قطارهایی را که میبَرَدشان گاهی به سمت راست میفرستم گاهی به سمت چپ. و همان دم سریعالسیری با چراغهای روشن و غرّشی رعدوار اتاقک سوزنبانی را به لرزه انداخت.
|
||||
-عجب عجلهای دارند! پیِ چی میروند؟
|
||||
سوزنبان گفت: -از خودِ آتشکارِ لکوموتیف هم بپرسی نمیداند!
|
||||
سریعالسیر دیگری با چراغهای روشن غرّید و در جهت مخالف گذشت .
|
||||
شهریار کوچولو پرسید: -برگشتند که؟
|
||||
سوزنبان گفت: -اینها اولیها نیستند. آنها رفتند اینها برمیگردند.
|
||||
-جایی را که بودند خوش نداشتند؟
|
||||
سوزنبان گفت: -آدمیزاد هیچ وقت جایی را که هست خوش ندارد.
|
||||
و رعدِ سریعالسیرِ نورانیِ ثالثی غرّید.
|
||||
شهریار کوچولو پرسید: -اینها دارند مسافرهای اولی را دنبال میکنند؟
|
||||
سوزنبان گفت: -اینها هیچ چیزی را دنبال نمیکنند. آن تو یا خوابشان میبَرَد یا دهندره میکنند. فقط بچههاند که دماغشان را فشار میدهند به شیشهها.
|
||||
شهریار کوچولو گفت: -فقط بچههاند که میدانند پیِ چی میگردند. بچههاند که کُلّی وقت صرف یک عروسک پارچهای میکنند و عروسک برایشان آن قدر اهمیت به هم میرساند که اگر یکی آن را ازشان کِش برود میزنند زیر گریه...
|
||||
سوزنبان گفت: -بخت، یارِ بچههاست.
|
||||
|
||||
۲۳
|
||||
شهریار کوچولو گفت: -سلام!
|
||||
پیلهور گفت: -سلام.
|
||||
این بابا فروشندهی حَبهای ضد تشنگی بود. خریدار هفتهای یک حب میانداخت بالا و دیگر تشنگی بی تشنگی.
|
||||
شهریار کوچولو پرسید: -اینها را میفروشی که چی؟
|
||||
پیلهور گفت: -باعث صرفهجویی کُلّی وقت است. کارشناسهای خبره نشستهاند دقیقا حساب کردهاند که با خوردن این حبها هفتهای پنجاه و سه دقیقه وقت صرفهجویی میشود.
|
||||
-خب، آن وقت آن پنجاه و سه دقیقه را چه کار میکنند؟
|
||||
ـ هر چی دلشان خواست...
|
||||
|
||||
چشمه
|
||||
شهریار کوچولو تو دلش گفت: «من اگر پنجاه و سه دقیقه وقتِ زیادی داشته باشم خوشخوشک به طرفِ یک چشمه میروم...»
|
||||
|
||||
۲۴
|
||||
هشتمین روزِ خرابی هواپیمام تو کویر بود که، در حال نوشیدنِ آخرین چکّهی ذخیرهی آبم به قضیهی پیلهوره گوش داده بودم. به شهریار کوچولو گفتم:
|
||||
-خاطرات تو راستی راستی زیباند اما من هنوز از پسِ تعمیر هواپیما برنیامدهام، یک چکه آب هم ندارم. و راستی که من هم اگر میتوانستم خوشخوشک به طرف چشمهای بروم سعادتی احساس میکردم که نگو!
|
||||
درآمد که: -دوستم روباه...
|
||||
گفتم: -آقا کوچولو، دورِ روباه را قلم بگیر!
|
||||
-واسه چی؟
|
||||
-واسه این که تشنگی کارمان را می سازد. واسه این!
|
||||
از استدلال من چیزی حالیش نشد و در جوابم گفت:
|
||||
-حتا اگر آدم دَمِ مرگ باشد هم داشتن یک دوست عالی است. من که از داشتن یک دوستِ روباه خیلی خوشحالم...
|
||||
به خودم گفتم نمیتواند میزان خطر را تخمین بزند: آخر او هیچ وقت نه تشنهاش میشود نه گشنهاش. یه ذره آفتاب بسش است...
|
||||
اما او به من نگاه کرد و در جواب فکرم گفت: -من هم تشنهم است... بگردیم یک چاه پیدا کنیم...
|
||||
از سرِ خستگی حرکتی کردم: -این جوری تو کویرِ برهوت رو هوا پیِ چاه گشتن احمقانه است.
|
||||
و با وجود این به راه افتادیم.
|
||||
|
||||
پس از ساعتها که در سکوت راه رفتیم شب شد و ستارهها یکی یکی درآمدند. من که از زور تشنگی تب کرده بودم انگار آنها را خواب میدیدم. حرفهای شهریار کوچولو تو ذهنم میرقصید.
|
||||
ازش پرسیدم: -پس تو هم تشنهات هست، ها؟
|
||||
اما او به سوآلِ من جواب نداد فقط در نهایت سادگی گفت: -آب ممکن است برای دلِ من هم خوب باشد...
|
||||
از حرفش چیزی دستگیرم نشد اما ساکت ماندم. میدانستم از او نباید حرف کشید.
|
||||
خسته شده بود. گرفت نشست. من هم کنارش نشستم. پس از مدتی سکوت گفت:
|
||||
-قشنگیِ ستارهها واسه خاطرِ گلی است که ما نمیبینیمش...
|
||||
گفتم: -همین طور است
|
||||
و بدون حرف در مهتاب غرق تماشای چین و شکنهای شن شدم.
|
||||
باز گفت: -کویر زیباست.
|
||||
|
||||
و حق با او بود. من همیشه عاشق کویر بودهام. آدم بالای تودهای شن لغزان مینشیند، هیچی نمیبیند و هیچی نمیشنود اما با وجود این چیزی توی سکوت برقبرق میزند.
|
||||
شهریار کوچولو گفت: -چیزی که کویر را زیبا میکند این است که یک جایی یک چاه قایم کرده...
|
||||
از اینکه ناگهان به راز آن درخشش اسرارآمیزِ شن پی بردم حیرتزده شدم. بچگیهام تو خانهی کهنهسازی مینشستیم که معروف بود تو آن گنجی چال کردهاند. البته نگفته پیداست که هیچ وقت کسی آن را پیدا نکرد و شاید حتا اصلا کسی دنبالش نگشت اما فکرش همهی اهل خانه را تردماغ میکرد: «خانهی ما تهِ دلش رازی پنهان کرده بود...»
|
||||
گفتم: -آره. چه خانه باشد چه ستاره، چه کویر، چیزی که اسباب زیباییاش میشود نامریی است!
|
||||
گفت: -خوشحالم که با روباه من توافق داری.
|
||||
|
||||
چون خوابش برده بود بغلش کردم و راه افتادم. دست و دلم میلرزید.انگار چیز شکستنیِ بسیار گرانبهایی را روی دست میبردم. حتا به نظرم میآمد که تو تمام عالم چیزی شکستنیتر از آن هم به نظر نمیرسد. تو روشنی مهتاب به آن پیشانی رنگپریده و آن چشمهای بسته و آن طُرّههای مو که باد میجنباند نگاه کردم و تو دلم گفتم: «آن چه میبینم صورت ظاهری بیشتر نیست. مهمترش را با چشم نمیشود دید...»
|
||||
باز، چون دهان نیمهبازش طرح کمرنگِ نیمهلبخندی را داشت به خود گفتم: «چیزی که تو شهریار کوچولوی خوابیده مرا به این شدت متاثر میکند وفاداری اوست به یک گل: او تصویرِ گل سرخی است که مثل شعلهی چراغی حتا در خوابِ ناز هم که هست تو وجودش میدرخشد...» و آن وقت او را باز هم شکنندهتر دیدم. حس کردم باید خیلی مواظبش باشم: به شعلهی چراغی میمانست که یک وزش باد هم میتوانست خاموشش کند.
|
||||
و همان طور در حال راه رفتن بود که دمدمهی سحر چاه را پیداکردم.
|
||||
|
||||
۲۵
|
||||
شهریار کوچولو درآمد که: -آدمها!... میچپند تو قطارهای تندرو اما نمیدانند دنبال چی میگردند. این است که بنامیکنند دور خودشان چرخکزدن.
|
||||
و بعد گفت: -این هم کار نشد...
|
||||
چاهی که بهاش رسیدهبودیم اصلا به چاههای کویری نمیمانست. چاه کویری یک چالهی ساده است وسط شنها. این یکی به چاههای واحهای میمانست اما آن دوروبر واحهای نبود و من فکر کردم دارم خواب میبینم.
|
||||
گفتم: -عجیب است! قرقره و سطل و تناب، همهچیز روبهراه است.
|
||||
خندید تناب را گرفت و قرقره را به کار انداخت
|
||||
|
||||
شهریار کوچولو در حالِ کشیدنِ آب از چاه
|
||||
و قرقره مثل بادنمای کهنهای که تا مدتها پس از خوابیدنِ باد مینالد به نالهدرآمد.
|
||||
گفت: -میشنوی؟ ما داریم این چاه را از خواب بیدار میکنیم و او دارد برایمان آواز میخواند...
|
||||
دلم نمیخواست او تلاش و تقلا کند. بش گفتم: -بدهش به من. برای تو زیادی سنگین است.
|
||||
سطل را آرام تا طوقهی چاه آوردم بالا و آنجا کاملا در تعادل نگهش داشتم. از حاصل کار شاد بودم. خسته و شاد. آواز قرقره را همانطور تو گوشم داشتم و تو آب که هنوز میلرزید لرزش خورشید را میدیدم.
|
||||
گفت: -بده من، که تشنهی این آبم.
|
||||
ومن تازه توانستم بفهمم پی چه چیز میگشته!
|
||||
|
||||
سطل را تا لبهایش بالا بردم. با چشمهای بسته نوشید. آبی بود به شیرینیِ عیدی. این آب به کُلّی چیزی بود سوایِ هرگونه خوردنی. زاییدهی راه رفتنِ زیر ستارهها و سرود قرقره و تقلای بازوهای من بود. مثل یک چشم روشنی برای دل خوب بود. پسر بچه که بودم هم، چراغ درخت عید و موسیقیِ نماز نیمهشب عید کریسمس و لطف لبخندهها عیدیی را که بم میدادند درست به همین شکل آن همه جلا و جلوه میبخشید.
|
||||
گفت: -مردم سیارهی تو ور میدارند پنج هزار تا گل را تو یک گلستان میکارند، و آن یک دانهای را که پِیَش میگردند آن وسط پیدا نمیکنند...
|
||||
گفتم: -پیدایش نمیکنند.
|
||||
-با وجود این، چیزی که پیَش میگردند ممکن است فقط تو یک گل یا تو یک جرعه آب پیدا بشود...
|
||||
جواب دادم: -گفتوگو ندارد.
|
||||
باز گفت: -گیرم چشمِ سَر کور است، باید با چشم دل پیاش گشت.
|
||||
من هم سیراب شده بودم. راحت نفس میکشیدم. وقتی آفتاب درمیآید شن به رنگ عسل است. من هم از این رنگ عسلی لذت میبردم. چرا میبایست در زحمت باشم...
|
||||
شهریار کوچولو که باز گرفته بود کنار من نشسته بود با لطف بم گفت: -هِی! قولت قول باشد ها!
|
||||
-کدام قول؟
|
||||
-یادت است؟ یک پوزهبند برای بَرّهام... آخر من مسئول گلمَم!
|
||||
طرحهای اولیهام را از جیب درآوردم. نگاهشان کرد و خندانخندان گفت: -بائوبابهات یک خرده شبیه کلم شده.
|
||||
ای وای! مرا بگو که آنقدر به بائوبابهام مینازیدم.
|
||||
-روباهت... گوشهاش بیشتر به شاخ میماند... زیادی درازند!
|
||||
و باز زد زیر خنده.
|
||||
-آقا کوچولو داری بیانصافی میکنی. من جز بوآهای بسته و بوآهای باز چیزی بلد نبودم بکشم که.
|
||||
گفت: -خب، مهم نیست. عوضش بچهها سرشان تو حساب است.
|
||||
با مداد یک پوزهبند کشیدم دادم دستش و با دلِ فشرده گفتم:
|
||||
-تو خیالاتی به سر داری که من ازشان بیخبرم...
|
||||
اما جواب مرا نداد. بم گفت: -میدانی؟ فردا سالِ به زمین آمدنِ من است.
|
||||
بعد پس از لحظهای سکوت دوباره گفت: -همین نزدیکیها پایین آمدم.
|
||||
و سرخ شد.
|
||||
|
||||
و من از نو بی این که بدانم چرا غم عجیبی احساس کردم. با وجود این سوآلی به ذهنم رسید: -پس هشت روز پیش، آن روز صبح که تو تک و تنها هزار میل دورتر از هر آبادی وسطِ کویر به من برخوردی اتفاقی نبود: داشتی برمیگشتی به همان جایی که پایینآمدی...
|
||||
دوباره سرخ شد
|
||||
و من با دودلی به دنبال حرفم گفتم:
|
||||
-شاید به مناسبت همین سالگرد؟...
|
||||
باز سرخ شد. او هیچ وقت به سوآلهایی که ازش میشد جواب نمیداد اما وقتی کسی سرخ میشود معنیش این است که «بله»، مگر نه؟
|
||||
بهاش گفتم: -آخر، من ترسم برداشته...
|
||||
اما او حرفم را برید:
|
||||
-دیگر تو باید بروی به کارت برسی. باید بروی سراغ موتورت. من همینجا منتظرت میمانم. فردا عصر برگرد...
|
||||
|
||||
منتها من خاطر جمع نبودم. به یاد روباه افتادم: اگر آدم گذاشت اهلیش کنند بفهمینفهمی خودش را به این خطر انداخته که کارش به گریهکردن بکشد.
|
||||
|
||||
۲۶
|
||||
کنار چاه دیوارِ سنگی مخروبهای بود. فردا عصر که از سرِ کار برگشتم از دور دیدم که آن بالا نشسته پاها را آویزان کرده،
|
||||
|
||||
شهریار کوچولو نشسته بر دیوارِ سنگی و مار در پایینِ آن
|
||||
و شنیدم که میگوید:
|
||||
-پس یادت نمیآید؟ درست این نقطه نبود ها!
|
||||
لابد صدای دیگری بهاش جوابی داد، چون شهریار کوچولو در رَدِّ حرفش گفت:
|
||||
-چرا چرا! روزش که درست همین امروز است گیرم محلش این جا نیست...
|
||||
راهم را به طرف دیوار ادامه دادم. هنوز نه کسی به چشم خورده بود نه صدای کسی را شنیده بودم اما شهریار کوچولو باز در جواب درآمد که:
|
||||
-... آره، معلوم است. خودت میتوانی ببینی رَدِّ پاهایم روی شن از کجا شروع میشود.
|
||||
همان جا منتظرم باش، تاریک که شد میآیم.
|
||||
بیست متری دیوار بودم و هنوز چیزی نمیدیدم. پس از مختصر مکثی دوباره گفت:
|
||||
-زهرت خوب هست؟ مطمئنی درد و زجرم را کِش نمیدهد؟
|
||||
با دل فشرده از راه ماندم اما هنوز از موضوع سر در نیاورده بودم.
|
||||
گفت: -خب، حالا دیگر برو. دِ برو. میخواهم بیایم پایین!
|
||||
|
||||
آن وقت من نگاهم را به پایین به پای دیوار انداختم و از جا جستم! یکی از آن مارهای زردی که تو سی ثانیه کَلَکِ آدم را میکنند، به طرف شهریار کوچولو قد راست کرده بود. من همان طور که به دنبال تپانچه دست به جیبم میبردم پا گذاشتم به دو، اما ماره از سر و صدای من مثل فوارهای که بنشیند آرام روی شن جاری شد و بی آن که چندان عجلهای از خودش نشان دهد باصدای خفیف فلزی لای سنگها خزید.
|
||||
من درست به موقع به دیوار رسیدم و طفلکی شهریار کوچولو را که رنگش مثل برف پریده بود تو هوا بغل کردم.
|
||||
-این دیگر چه حکایتی است! حالا دیگر با مارها حرف میزنی؟
|
||||
شال زردش را که مدام به گردن داشت باز کردم به شقیقههایش آب زدم و جرعهای بهاش نوشاندم. اما حالا دیگر اصلا جرات نمی کردم ازش چیزی بپرسم. با وقار به من نگاه کرد و دستش را دور گردنم انداخت. حس کردم قلبش مثل قلب پرندهای میزند که تیر خوردهاست و دارد میمیرد.
|
||||
گفت: -از این که کم و کسرِ لوازم ماشینت را پیدا کردی خوشحالم. حالا میتوانی برگردی خانهات...
|
||||
-تو از کجا فهمیدی؟
|
||||
درست همان دم لبواکردهبودم بش خبر بدهم که علیرغم همهی نومیدیها تو کارم موفق شدهام!
|
||||
به سوآلهای من هیچ جوابی نداد اما گفت: -آخر من هم امروز بر میگردم خانهام...
|
||||
و بعد غمزده درآمد که: -گیرم راه من خیلی دورتر است... خیلی سختتر است...
|
||||
|
||||
حس میکردم اتفاق فوقالعادهای دارد میافتد. گرفتمش تو بغلم. عین یک بچهی کوچولو. با وجود این به نظرم میآمد که او دارد به گردابی فرو میرود و برای نگه داشتنش از من کاری ساخته نیست... نگاه متینش به دوردستهای دور راه کشیده بود.
|
||||
گفت: بَرِّهات را دارم. جعبههه را هم واسه برههه دارم. پوزهبنده را هم دارم.
|
||||
و با دلِ گرفته لبخندی زد.
|
||||
مدت درازی صبر کردم. حس کردم کمکمَک تنش دوباره دارد گرم میشود.
|
||||
-عزیز کوچولوی من، وحشت کردی...
|
||||
-امشب وحشت خیلی بیشتری چشم بهراهم است.
|
||||
|
||||
دوباره از احساسِ واقعهای جبران ناپذیر یخ زدم. این فکر که دیگر هیچ وقت غشغش خندهی او را نخواهم شنید برایم سخت تحملناپذیر بود. خندهی او برای من به چشمهای در دلِ کویر میمانست.
|
||||
-کوچولوئَکِ من، دلم میخواهد باز هم غشغشِ خندهات را بشنوم.
|
||||
اما بهام گفت: -امشب درست میشود یک سال و اخترَکَم درست بالای همان نقطهای میرسد که پارسال به زمین آمدم.
|
||||
-کوچولوئک، این قضیهی مار و میعاد و ستاره یک خواب آشفته بیشتر نیست. مگر نه؟
|
||||
به سوال من جوابی نداد اما گفت: -چیزی که مهم است با چشمِ سَر دیده نمیشود.
|
||||
-مسلم است.
|
||||
-در مورد گل هم همینطور است: اگر گلی را دوست داشته باشی که تو یک ستارهی دیگر است، شب تماشای آسمان چه لطفی پیدا میکند: همهی ستارهها غرق گل میشوند!
|
||||
-مسلم است...
|
||||
-در مورد آب هم همینطور است. آبی که تو به من دادی به خاطر قرقره و ریسمان درست به یک موسیقی میمانست... یادت که هست... چه خوب بود.
|
||||
-مسلم است...
|
||||
-شببهشب ستارهها را نگاه میکنی. اخترک من کوچولوتر از آن است که بتوانم جایش را نشانت بدهم. اما چه بهتر! آن هم برای تو میشود یکی از ستارهها؛ و آن وقت تو دوست داری همهی ستارهها را تماشا کنی... همهشان میشوند دوستهای تو... راستی میخواهم هدیهای بت بدهم...
|
||||
و غش غش خندید.
|
||||
-آخ، کوچولوئک، کوچولوئک! من عاشقِ شنیدنِ این خندهام!
|
||||
-هدیهی من هم درست همین است... درست مثل مورد آب.
|
||||
-چی میخواهی بگویی؟
|
||||
-همهی مردم ستاره دارند اما همهی ستارهها یکجور نیست: واسه آنهایی که به سفر میروند حکم راهنما را دارند واسه بعضی دیگر فقط یک مشت روشناییِ سوسوزناند. برای بعضی که اهل دانشند هر ستاره یک معما است واسه آن بابای تاجر طلا بود. اما این ستارهها همهشان زبان به کام کشیده و خاموشند. فقط تو یکی ستارههایی خواهی داشت که تنابندهای مِثلش را ندارد.
|
||||
-چی میخواهی بگویی؟
|
||||
-نه این که من تو یکی از ستارههام؟ نه این که من تو یکی از آنها میخندم؟... خب، پس هر شب که به آسمان نگاه میکنی برایت مثل این خواهد بود که همهی ستارهها میخندند. پس تو ستارههایی خواهی داشت که بلدند بخندند!
|
||||
و باز خندید.
|
||||
-و خاطرت که تسلا پیدا کرد (خب بالاخره آدمیزاد یک جوری تسلا پیدا میکند دیگر) از آشنایی با من خوشحال میشوی. دوست همیشگی من باقی میمانی و دلت میخواهد با من بخندی و پارهای وقتهام واسه تفریح پنجرهی اتاقت را وا میکنی... دوستانت از اینکه میبینند تو به آسمان نگاه میکنی و میخندی حسابی تعجب میکنند آن وقت تو بهشان میگویی: «آره، ستارهها همیشه مرا خنده میاندازند!» و آنوقت آنها یقینشان میشود که تو پاک عقلت را از دست دادهای. جان! میبینی چه کَلَکی بهات زدهام...
|
||||
و باز زد زیر خنده.
|
||||
-به آن میماند که عوضِ ستاره یک مشت زنگوله بت داده باشم که بلدند بخندند...
|
||||
دوباره خندید و بعد حالتی جدی به خودش گرفت:
|
||||
-نه، من تنهات نمیگذارم.
|
||||
|
||||
شهریار کوچولو تنها
|
||||
|
||||
-ظاهر آدمی را پیدا میکنم که دارد درد میکشد... یک خرده هم مثل آدمی میشوم که دارد جان میکند. رو هم رفته این جوریها است. نیا که این را نبینی. چه زحمتی است بیخود؟
|
||||
-تنهات نمیگذارم.
|
||||
اندوهزده بود.
|
||||
-این را بیشتر از بابت ماره میگویم که، نکند یکهو تو را هم بگزد. مارها خیلی خبیثند. حتا واسه خنده هم ممکن است آدم را نیش بزنند.
|
||||
-تنهات نمیگذارم.
|
||||
منتها یک چیز باعث خاطر جمعیش شد:
|
||||
-گر چه، بار دوم که بخواهند بگزند دیگر زهر ندارند.
|
||||
شب متوجه راه افتادنش نشدم. بی سر و صدا گریخت.
|
||||
وقتی خودم را بهاش رساندم با قیافهی مصمم و قدمهای محکم پیش میرفت. همین قدر گفت: -اِ! اینجایی؟
|
||||
و دستم را گرفت.
|
||||
اما باز بیقرار شد وگفت: -اشتباه کردی آمدی. رنج میبری. گرچه حقیقت این نیست، اما ظاهرِ یک مرده را پیدا میکنم.
|
||||
من ساکت ماندم.
|
||||
-خودت درک میکنی. راه خیلی دور است. نمیتوانم این جسم را با خودم ببرم. خیلی سنگین است.
|
||||
من ساکت ماندم.
|
||||
-گیرم عینِ پوستِ کهنهای میشود که دورش انداخته باشند؛ پوست کهنه که غصه ندارد، ها؟
|
||||
من ساکت ماندم.
|
||||
کمی دلسرد شد اما باز هم سعی کرد:
|
||||
-خیلی با مزه میشود، نه؟ من هم به ستارهها نگاه میکنم. همشان به صورت چاههایی در میآیند با قرقرههای زنگ زده. همهی ستارهها بم آب میدهند بخورم...
|
||||
من ساکت ماندم.
|
||||
-خیلی با مزه میشود. نه؟ تو صاحب هزار کرور زنگوله میشوی من صاحب هزار کرور فواره...
|
||||
او هم ساکت شد، چرا که داشت گریه میکرد...
|
||||
-خب، همین جاست. بگذار چند قدم خودم تنهایی بروم.
|
||||
و گرفت نشست، چرا که میترسید.
|
||||
|
||||
شهریار کوچولو نشسته
|
||||
|
||||
میدانی؟... گلم را میگویم... آخر من مسئولشم. تازه چه قدر هم لطیف است و چه قدر هم ساده و بیشیلهپیله. برای آن که جلو همهی عالم از خودش دفاع کند همهاش چی دارد مگر؟ چهارتا خار پِرپِرَک!
|
||||
|
||||
من هم گرفتم نشستم. دیگر نمیتوانستم سر پا بند بشوم.
|
||||
گفت: -همین... همهاش همین و بس...
|
||||
باز هم کمی دودلی نشان داد اما بالاخره پا شد و قدمی به جلو رفت. من قادر به حرکت نبودم.
|
||||
|
||||
کنار قوزکِ پایش جرقهی زردی جست و... فقط همین! یک دم بیحرکت ماند. فریادی نزد. مثل درختی که بیفتد آرامآرام به زمین افتاد که به وجود شن از آن هم صدایی بلند نشد.
|
||||
|
||||
شهریار کوچولو در حالی که آرامآرام به زمین میافتد
|
||||
۲۷
|
||||
شش سال گذشته است و من هنوز بابت این قضیه جایی لبترنکردهام. دوستانم از این که مرا دوباره زنده میدیدند سخت شاد شدند. من غمزده بودم اما به آنها میگفتم اثر خستگی است.
|
||||
حالا کمی تسلای خاطر پیدا کردهام. یعنی نه کاملا... اما این را خوب میدانم که او به اخترکش برگشته. چون آفتاب که زد پیکرش را پیدا نکردم. پیکری هم نبود که چندان وزنی داشته باشد... و شبها دوست دارم به ستارهها گوش بدهم. عین هزار زنگولهاند.
|
||||
اما موضوع خیلی مهمی که هست، من پاک یادم رفت به پوزهبندی که برای شهریار کوچولو کشیدم تسمهی چرمی اضافه کنم و او ممکن نیست بتواند آن را به پوزهی بَرّه ببندد. این است که از خودم میپرسم: «یعنی تو اخترکش چه اتفاقی افتاده؟ نکند برههه گل را چریده باشد؟...»
|
||||
گاه به خودم میگویم: «حتما نه، شهریار کوچولو هر شب گلش را زیر حباب شیشهای میگذارد و هوای برهاش را هم دارد...» آن وقت است که خیالم راحت میشود و ستارهها همه به شیرینی میخندند.
|
||||
گاه به خودم میگویم: «همین کافی است که آدم یک بار حواسش نباشد... آمدیم و یک شب حباب یادش رفت یا بَرّه شب نصفشبی بیسروصدا از جعبه زد بیرون...» آن وقت است که زنگولهها همه تبدیل به اشک میشوند!...
|
||||
|
||||
یک راز خیلی خیلی بزرگ این جا هست: برای شما هم که او را دوست دارید، مثل من هیچ چیزِ عالم مهمتر از دانستن این نیست که تو فلان نقطهای که نمیدانیم، فلان برهای که نمیشماسیم گل سرخی را چریده یا نچریده...
|
||||
|
||||
خب. آسمان را نگاه کنید و بپرسید: «بَرّه گل را چریده یا نچریده؟» و آن وقت با چشمهای خودتان تفاوتش را ببینید...
|
||||
|
||||
و محال است آدم بزرگها روحشان خبردار بشود که این موضوع چه قدر مهم است!
|
||||
|
||||
بدونِ شهریار کوچولو
|
||||
در نظر من این زیباترین و حزنانگیزترین منظرهی عالم است. این همان منظرهی دو صفحه پیش است گیرم آن را دوباره کشیدهام که بهتر نشانتان بدهم: «ظهور شهریار کوچولو بر زمین در این جا بود؛ و بعد در همین جا هم بود که ناپدید شد».
|
||||
|
||||
آن قدر به دقت این منظره را نگاه کنید که مطمئن بشوید اگر روزی تو آفریقا گذرتان به کویر صحرا افتاد حتما آن را خواهید شناخت. و اگر پاداد و گذارتان به آن جا افتاد به التماس ازتان میخواهم که عجله به خرج ندهید و درست زیر ستاره چند لحظهای توقف کنید. آن وقت اگر بچهای به طرفتان آمد، اگر خندید، اگر موهایش طلایی بود، اگر وقتی ازش سوالی کردید جوابی نداد، لابد حدس میزنید که کیست. در آن صورت لطف کنید و نگذارید من این جور افسرده خاطر بمانم:
|
||||
بی درنگ بردارید به من بنویسید که او برگشته.
|
||||
|
@ -1,21 +0,0 @@
|
||||
# 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})
|
462
src/Makefile.am
462
src/Makefile.am
@ -1,462 +0,0 @@
|
||||
# Process this file with automake to produce Makefile.in
|
||||
|
||||
NULL =
|
||||
SUBDIRS =
|
||||
DIST_SUBDIRS =
|
||||
BUILT_SOURCES =
|
||||
EXTRA_DIST =
|
||||
CLEANFILES =
|
||||
DISTCLEANFILES =
|
||||
MAINTAINERCLEANFILES =
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
|
||||
TESTS =
|
||||
check_PROGRAMS =
|
||||
|
||||
EXTRA_DIST += harfbuzz.cc
|
||||
EXTRA_DIST += meson.build
|
||||
EXTRA_DIST += fix_get_types.py
|
||||
|
||||
# Convenience targets:
|
||||
lib: $(BUILT_SOURCES) libharfbuzz.la
|
||||
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
|
||||
tiny:
|
||||
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Os -DHB_TINY $(CPPFLAGS)" libs
|
||||
tinyz:
|
||||
$(MAKE) $(AM_MAKEFLAGS) CPPFLAGS="-Oz -DHB_TINY $(CPPFLAGS)" libs
|
||||
|
||||
lib_LTLIBRARIES = libharfbuzz.la
|
||||
|
||||
include Makefile.sources
|
||||
|
||||
HBCFLAGS =
|
||||
HBLIBS =
|
||||
HBNONPCLIBS =
|
||||
HBDEPS =
|
||||
HBSOURCES = $(HB_BASE_sources)
|
||||
HBSOURCES += $(HB_BASE_RAGEL_GENERATED_sources)
|
||||
HBHEADERS = $(HB_BASE_headers)
|
||||
|
||||
if HAVE_PTHREAD
|
||||
HBCFLAGS += $(PTHREAD_CFLAGS)
|
||||
HBNONPCLIBS += $(PTHREAD_LIBS)
|
||||
endif
|
||||
|
||||
if HAVE_GLIB
|
||||
HBCFLAGS += $(GLIB_CFLAGS)
|
||||
HBLIBS += $(GLIB_LIBS)
|
||||
HBDEPS += $(GLIB_DEPS)
|
||||
HBSOURCES += $(HB_GLIB_sources)
|
||||
HBHEADERS += $(HB_GLIB_headers)
|
||||
endif
|
||||
|
||||
if HAVE_FREETYPE
|
||||
HBCFLAGS += $(FREETYPE_CFLAGS)
|
||||
HBLIBS += $(FREETYPE_LIBS)
|
||||
HBDEPS += $(FREETYPE_DEPS)
|
||||
HBSOURCES += $(HB_FT_sources)
|
||||
HBHEADERS += $(HB_FT_headers)
|
||||
endif
|
||||
|
||||
if HAVE_GRAPHITE2
|
||||
HBCFLAGS += $(GRAPHITE2_CFLAGS)
|
||||
HBLIBS += $(GRAPHITE2_LIBS)
|
||||
HBDEPS += $(GRAPHITE2_DEPS)
|
||||
HBSOURCES += $(HB_GRAPHITE2_sources)
|
||||
HBHEADERS += $(HB_GRAPHITE2_headers)
|
||||
endif
|
||||
|
||||
if HAVE_UNISCRIBE
|
||||
HBCFLAGS += $(UNISCRIBE_CFLAGS)
|
||||
HBNONPCLIBS += $(UNISCRIBE_LIBS)
|
||||
HBSOURCES += $(HB_UNISCRIBE_sources)
|
||||
HBHEADERS += $(HB_UNISCRIBE_headers)
|
||||
endif
|
||||
|
||||
if HAVE_DIRECTWRITE
|
||||
HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
|
||||
HBNONPCLIBS += $(DIRECTWRITE_LIBS)
|
||||
HBSOURCES += $(HB_DIRECTWRITE_sources)
|
||||
HBHEADERS += $(HB_DIRECTWRITE_headers)
|
||||
endif
|
||||
|
||||
if HAVE_GDI
|
||||
HBCFLAGS += $(GDI_CXXFLAGS)
|
||||
HBNONPCLIBS += $(GDI_LIBS)
|
||||
HBSOURCES += $(HB_GDI_sources)
|
||||
HBHEADERS += $(HB_GDI_headers)
|
||||
endif
|
||||
|
||||
if HAVE_CORETEXT
|
||||
HBCFLAGS += $(CORETEXT_CFLAGS)
|
||||
HBNONPCLIBS += $(CORETEXT_LIBS)
|
||||
HBSOURCES += $(HB_CORETEXT_sources)
|
||||
HBHEADERS += $(HB_CORETEXT_headers)
|
||||
endif
|
||||
|
||||
|
||||
BUILT_SOURCES += \
|
||||
hb-version.h
|
||||
|
||||
$(srcdir)/hb-version.h: hb-version.h.in $(top_srcdir)/configure.ac
|
||||
$(AM_V_GEN) $(SED) \
|
||||
-e 's/[@]HB_VERSION_MAJOR@/$(HB_VERSION_MAJOR)/' \
|
||||
-e 's/[@]HB_VERSION_MINOR@/$(HB_VERSION_MINOR)/' \
|
||||
-e 's/[@]HB_VERSION_MICRO@/$(HB_VERSION_MICRO)/' \
|
||||
-e 's/[@]HB_VERSION@/$(HB_VERSION)/' \
|
||||
"$<" > "$@" || ($(RM) "$@"; false)
|
||||
|
||||
# Put the library together
|
||||
|
||||
HBLIBS += $(HBNONPCLIBS)
|
||||
|
||||
if OS_WIN32
|
||||
export_symbols = -export-symbols harfbuzz.def
|
||||
harfbuzz_def_dependency = harfbuzz.def
|
||||
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
|
||||
if HAVE_GCC
|
||||
# Use a C linker for GCC, not C++; Don't link to libstdc++
|
||||
chosen_linker = $(LINK)
|
||||
else
|
||||
chosen_linker = $(CXXLINK)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@CODE_COVERAGE_RULES@
|
||||
|
||||
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) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_la_LDFLAGS = $(base_link_flags) $(export_symbols) $(CODE_COVERAGE_LDFLAGS)
|
||||
libharfbuzz_la_LIBADD = $(HBLIBS)
|
||||
EXTRA_libharfbuzz_la_DEPENDENCIES = $(harfbuzz_def_dependency)
|
||||
pkginclude_HEADERS = $(HBHEADERS)
|
||||
nodist_pkginclude_HEADERS =
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = harfbuzz.pc
|
||||
cmakedir = $(libdir)/cmake/harfbuzz
|
||||
cmake_DATA = harfbuzz-config.cmake
|
||||
EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
|
||||
|
||||
lib_LTLIBRARIES += libharfbuzz-subset.la
|
||||
libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS)
|
||||
libharfbuzz_subset_la_SOURCES = $(HB_SUBSET_sources)
|
||||
libharfbuzz_subset_la_CPPFLAGS = $(HBCFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_subset_la_LDFLAGS = $(base_link_flags) $(export_symbols_subset) $(CODE_COVERAGE_LDFLAGS)
|
||||
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
|
||||
|
||||
if HAVE_ICU
|
||||
if HAVE_ICU_BUILTIN
|
||||
HBCFLAGS += $(ICU_CFLAGS)
|
||||
HBLIBS += $(ICU_LIBS)
|
||||
HBSOURCES += $(HB_ICU_sources)
|
||||
HBHEADERS += $(HB_ICU_headers)
|
||||
else
|
||||
lib_LTLIBRARIES += libharfbuzz-icu.la
|
||||
libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
|
||||
libharfbuzz_icu_la_CPPFLAGS = $(HBCFLAGS) $(ICU_CFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_icu_la_LDFLAGS = $(base_link_flags) $(export_symbols_icu) $(CODE_COVERAGE_LDFLAGS)
|
||||
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
|
||||
endif
|
||||
EXTRA_DIST += harfbuzz-icu.pc.in
|
||||
|
||||
if HAVE_GOBJECT
|
||||
lib_LTLIBRARIES += libharfbuzz-gobject.la
|
||||
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) $(GOBJECT_CFLAGS) $(CODE_COVERAGE_CFLAGS)
|
||||
libharfbuzz_gobject_la_LDFLAGS = $(base_link_flags) $(CODE_COVERAGE_LDFLAGS)
|
||||
libharfbuzz_gobject_la_LIBADD = $(GOBJECT_LIBS) libharfbuzz.la
|
||||
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 += \
|
||||
$(HB_GOBJECT_ENUM_sources) \
|
||||
$(HB_GOBJECT_ENUM_headers) \
|
||||
$(NULL)
|
||||
DISTCLEANFILES += \
|
||||
$(HB_GOBJECT_ENUM_sources) \
|
||||
$(HB_GOBJECT_ENUM_headers) \
|
||||
$(NULL)
|
||||
hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
|
||||
$(AM_V_GEN) PYTHONIOENCODING=UTF-8 $(GLIB_MKENUMS) \
|
||||
--identifier-prefix hb_ --symbol-prefix hb_gobject \
|
||||
--template $^ | \
|
||||
sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
|
||||
|| ($(RM) "$@"; false)
|
||||
endif
|
||||
EXTRA_DIST += \
|
||||
harfbuzz-gobject.pc.in \
|
||||
hb-gobject-enums.cc.tmpl \
|
||||
hb-gobject-enums.h.tmpl \
|
||||
$(NULL)
|
||||
|
||||
|
||||
%.pc: %.pc.in $(top_builddir)/config.status
|
||||
$(AM_V_GEN) \
|
||||
$(SED) -e 's@%prefix%@$(prefix)@g' \
|
||||
-e 's@%exec_prefix%@$(exec_prefix)@g' \
|
||||
-e 's@%libdir%@$(libdir)@g' \
|
||||
-e 's@%includedir%@$(includedir)@g' \
|
||||
-e 's@%libs_private%@$(HBNONPCLIBS)@g' \
|
||||
-e 's@%requires_private%@$(HBDEPS)@g' \
|
||||
-e 's@%VERSION%@$(VERSION)@g' \
|
||||
"$<" > "$@" \
|
||||
|| ($(RM) "$@"; false)
|
||||
|
||||
CLEANFILES += $(pkgconfig_DATA)
|
||||
|
||||
|
||||
DEF_FILES = harfbuzz.def harfbuzz-subset.def harfbuzz-icu.def harfbuzz-deprecated-symbols.txt
|
||||
if HAVE_GOBJECT
|
||||
DEF_FILES += harfbuzz-gobject.def
|
||||
endif
|
||||
check: $(DEF_FILES) # For check-symbols.sh
|
||||
CLEANFILES += $(DEF_FILES)
|
||||
harfbuzz.def: $(top_builddir)/config.status
|
||||
harfbuzz.def: $(HBHEADERS)
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-subset.def: $(HB_SUBSET_headers)
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-icu.def: $(HB_ICU_headers)
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-gobject.def: $(HB_GOBJECT_headers)
|
||||
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
|
||||
harfbuzz-deprecated-symbols.txt: $(srcdir)/hb-deprecated.h
|
||||
$(AM_V_GEN) PLAIN_LIST=1 $(srcdir)/gen-def.py "$@" $^
|
||||
|
||||
|
||||
GENERATORS = \
|
||||
gen-arabic-joining-list.py \
|
||||
gen-arabic-table.py \
|
||||
gen-def.py \
|
||||
gen-emoji-table.py \
|
||||
gen-harfbuzzcc.py \
|
||||
gen-hb-version.py \
|
||||
gen-indic-table.py \
|
||||
gen-os2-unicode-ranges.py \
|
||||
gen-ragel-artifacts.py \
|
||||
gen-tag-table.py \
|
||||
gen-ucd-table.py \
|
||||
gen-use-table.py \
|
||||
gen-vowel-constraints.py \
|
||||
$(NULL)
|
||||
EXTRA_DIST += $(GENERATORS)
|
||||
|
||||
built-sources: $(BUILT_SOURCES)
|
||||
|
||||
.PHONY: built-sources
|
||||
|
||||
RAGEL_GENERATED = \
|
||||
$(patsubst %,$(srcdir)/%,$(HB_BASE_RAGEL_GENERATED_sources)) \
|
||||
$(NULL)
|
||||
BUILT_SOURCES += $(RAGEL_GENERATED)
|
||||
EXTRA_DIST += \
|
||||
$(HB_BASE_RAGEL_sources) \
|
||||
$(NULL)
|
||||
# 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)
|
||||
|
||||
harfbuzz.cc: Makefile.sources
|
||||
$(AM_V_GEN) \
|
||||
for f in \
|
||||
$(HB_BASE_sources) \
|
||||
$(HB_GLIB_sources) \
|
||||
$(HB_FT_sources) \
|
||||
$(HB_GRAPHITE2_sources) \
|
||||
$(HB_UNISCRIBE_sources) \
|
||||
$(HB_GDI_sources) \
|
||||
$(HB_DIRECTWRITE_sources) \
|
||||
$(HB_CORETEXT_sources) \
|
||||
; do echo '#include "'$$f'"'; done | \
|
||||
grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
|
||||
|| ($(RM) $(srcdir)/harfbuzz.cc; false)
|
||||
BUILT_SOURCES += harfbuzz.cc
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
main \
|
||||
test \
|
||||
test-buffer-serialize \
|
||||
test-ot-meta \
|
||||
test-ot-name \
|
||||
test-ot-glyphname \
|
||||
test-gpos-size-params \
|
||||
test-gsub-would-substitute \
|
||||
$(NULL)
|
||||
bin_PROGRAMS =
|
||||
|
||||
main_SOURCES = main.cc
|
||||
main_CPPFLAGS = $(HBCFLAGS)
|
||||
main_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_SOURCES = test.cc
|
||||
test_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
test_buffer_serialize_SOURCES = test-buffer-serialize.cc
|
||||
test_buffer_serialize_CPPFLAGS = $(HBCFLAGS)
|
||||
test_buffer_serialize_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_meta_SOURCES = test-ot-meta.cc
|
||||
test_ot_meta_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_meta_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_name_SOURCES = test-ot-name.cc
|
||||
test_ot_name_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_name_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_glyphname_SOURCES = test-ot-glyphname.cc
|
||||
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_gpos_size_params_SOURCES = test-gpos-size-params.cc
|
||||
test_gpos_size_params_CPPFLAGS = $(HBCFLAGS)
|
||||
test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc
|
||||
test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS)
|
||||
test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS)
|
||||
|
||||
COMPILED_TESTS = test-algs test-array test-iter test-meta test-number test-ot-tag test-priority-queue test-unicode-ranges test-bimap test-repacker
|
||||
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
|
||||
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
check_PROGRAMS += $(COMPILED_TESTS)
|
||||
TESTS += $(COMPILED_TESTS)
|
||||
|
||||
test_algs_SOURCES = test-algs.cc hb-static.cc
|
||||
test_algs_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_algs_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_array_SOURCES = test-array.cc
|
||||
test_array_CPPFLAGS = $(HBCFLAGS)
|
||||
test_array_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_priority_queue_SOURCES = test-priority-queue.cc hb-static.cc
|
||||
test_priority_queue_CPPFLAGS = $(HBCFLAGS)
|
||||
test_priority_queue_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_repacker_SOURCES = test-repacker.cc hb-static.cc
|
||||
test_repacker_CPPFLAGS = $(HBCFLAGS)
|
||||
test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
|
||||
|
||||
test_iter_SOURCES = test-iter.cc hb-static.cc
|
||||
test_iter_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_iter_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_meta_SOURCES = test-meta.cc hb-static.cc
|
||||
test_meta_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_meta_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_number_SOURCES = test-number.cc hb-number.cc
|
||||
test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_number_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_ot_tag_SOURCES = hb-ot-tag.cc
|
||||
test_ot_tag_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_ot_tag_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_unicode_ranges_SOURCES = test-unicode-ranges.cc
|
||||
test_unicode_ranges_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_unicode_ranges_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_bimap_SOURCES = test-bimap.cc hb-static.cc
|
||||
test_bimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_bimap_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
dist_check_SCRIPTS = \
|
||||
check-c-linkage-decls.py \
|
||||
check-externs.py \
|
||||
check-header-guards.py \
|
||||
check-includes.py \
|
||||
check-static-inits.py \
|
||||
check-symbols.py \
|
||||
$(NULL)
|
||||
TESTS += $(dist_check_SCRIPTS)
|
||||
|
||||
if !WITH_LIBSTDCXX
|
||||
dist_check_SCRIPTS += \
|
||||
check-libstdc++.py \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
srcdir="$(srcdir)" \
|
||||
builddir="$(builddir)" \
|
||||
MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
|
||||
HBSOURCES="$(HBSOURCES)" \
|
||||
HBHEADERS="$(HBHEADERS)" \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_INTROSPECTION
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
INTROSPECTION_GIRS = HarfBuzz-0.0.gir # What does the 0 mean anyway?!
|
||||
INTROSPECTION_SCANNER_ARGS = \
|
||||
-I$(srcdir) \
|
||||
--warn-all --verbose \
|
||||
--namespace=HarfBuzz \
|
||||
--nsversion=0.0 \
|
||||
--symbol-prefix=hb \
|
||||
--symbol-prefix=hb_gobject \
|
||||
--identifier-prefix=hb_ \
|
||||
--pkg-export=harfbuzz-gobject \
|
||||
--c-include=hb-gobject.h
|
||||
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
|
||||
INTROSPECTION_SCANNER_ENV = CC="$(CC)"
|
||||
|
||||
HarfBuzz-0.0.gir: libharfbuzz.la libharfbuzz-gobject.la
|
||||
HarfBuzz_0_0_gir_INCLUDES = GObject-2.0
|
||||
HarfBuzz_0_0_gir_CFLAGS = \
|
||||
$(INCLUDES) \
|
||||
$(HBCFLAGS) \
|
||||
-DHB_NO_SINGLE_HEADER_ERROR \
|
||||
-DHAVE_GOBJECT \
|
||||
-DHB_EXTERN= \
|
||||
$(NULL)
|
||||
HarfBuzz_0_0_gir_LIBS = \
|
||||
libharfbuzz.la \
|
||||
libharfbuzz-gobject.la \
|
||||
$(NULL)
|
||||
HarfBuzz_0_0_gir_FILES = \
|
||||
$(HBHEADERS) \
|
||||
$(HBSOURCES) \
|
||||
$(HB_GOBJECT_sources) \
|
||||
$(HB_GOBJECT_headers) \
|
||||
$(NULL)
|
||||
|
||||
girdir = $(datadir)/gir-1.0
|
||||
gir_DATA = $(INTROSPECTION_GIRS)
|
||||
|
||||
typelibdir = $(libdir)/girepository-1.0
|
||||
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
|
||||
|
||||
CLEANFILES += $(gir_DATA) $(typelib_DATA)
|
||||
|
||||
endif
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
@ -1,286 +0,0 @@
|
||||
# Base and default-included sources and headers
|
||||
|
||||
HB_BASE_sources = \
|
||||
hb-aat-layout-ankr-table.hh \
|
||||
hb-aat-layout-bsln-table.hh \
|
||||
hb-aat-layout-common.hh \
|
||||
hb-aat-layout-feat-table.hh \
|
||||
hb-aat-layout-just-table.hh \
|
||||
hb-aat-layout-kerx-table.hh \
|
||||
hb-aat-layout-morx-table.hh \
|
||||
hb-aat-layout-opbd-table.hh \
|
||||
hb-aat-layout-trak-table.hh \
|
||||
hb-aat-layout.cc \
|
||||
hb-aat-layout.hh \
|
||||
hb-aat-ltag-table.hh \
|
||||
hb-aat-map.cc \
|
||||
hb-aat-map.hh \
|
||||
hb-algs.hh \
|
||||
hb-array.hh \
|
||||
hb-atomic.hh \
|
||||
hb-bimap.hh \
|
||||
hb-blob.cc \
|
||||
hb-blob.hh \
|
||||
hb-buffer-serialize.cc \
|
||||
hb-buffer.cc \
|
||||
hb-buffer.hh \
|
||||
hb-cache.hh \
|
||||
hb-cff-interp-common.hh \
|
||||
hb-cff-interp-cs-common.hh \
|
||||
hb-cff-interp-dict-common.hh \
|
||||
hb-cff1-interp-cs.hh \
|
||||
hb-cff2-interp-cs.hh \
|
||||
hb-common.cc \
|
||||
hb-config.hh \
|
||||
hb-debug.hh \
|
||||
hb-dispatch.hh \
|
||||
hb-draw.cc \
|
||||
hb-draw.hh \
|
||||
hb-face.cc \
|
||||
hb-face.hh \
|
||||
hb-fallback-shape.cc \
|
||||
hb-font.cc \
|
||||
hb-font.hh \
|
||||
hb-iter.hh \
|
||||
hb-kern.hh \
|
||||
hb-machinery.hh \
|
||||
hb-map.cc \
|
||||
hb-map.hh \
|
||||
hb-meta.hh \
|
||||
hb-mutex.hh \
|
||||
hb-null.hh \
|
||||
hb-number.cc \
|
||||
hb-number.hh \
|
||||
hb-object.hh \
|
||||
hb-open-file.hh \
|
||||
hb-open-type.hh \
|
||||
hb-ot-cff-common.hh \
|
||||
hb-ot-cff1-std-str.hh \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-ot-cff1-table.hh \
|
||||
hb-ot-cff2-table.cc \
|
||||
hb-ot-cff2-table.hh \
|
||||
hb-ot-cmap-table.hh \
|
||||
hb-ot-color-cbdt-table.hh \
|
||||
hb-ot-color-colr-table.hh \
|
||||
hb-ot-color-cpal-table.hh \
|
||||
hb-ot-color-sbix-table.hh \
|
||||
hb-ot-color-svg-table.hh \
|
||||
hb-ot-color.cc \
|
||||
hb-ot-face-table-list.hh \
|
||||
hb-ot-face.cc \
|
||||
hb-ot-face.hh \
|
||||
hb-ot-font.cc \
|
||||
hb-ot-gasp-table.hh \
|
||||
hb-ot-glyf-table.hh \
|
||||
hb-ot-hdmx-table.hh \
|
||||
hb-ot-head-table.hh \
|
||||
hb-ot-hhea-table.hh \
|
||||
hb-ot-hmtx-table.hh \
|
||||
hb-ot-kern-table.hh \
|
||||
hb-ot-layout-base-table.hh \
|
||||
hb-ot-layout-common.hh \
|
||||
hb-ot-layout-gdef-table.hh \
|
||||
hb-ot-layout-gpos-table.hh \
|
||||
hb-ot-layout-gsub-table.hh \
|
||||
hb-ot-layout-gsubgpos.hh \
|
||||
hb-ot-layout-jstf-table.hh \
|
||||
hb-ot-layout.cc \
|
||||
hb-ot-layout.hh \
|
||||
hb-ot-map.cc \
|
||||
hb-ot-map.hh \
|
||||
hb-ot-math-table.hh \
|
||||
hb-ot-math.cc \
|
||||
hb-ot-maxp-table.hh \
|
||||
hb-ot-meta-table.hh \
|
||||
hb-ot-meta.cc \
|
||||
hb-ot-metrics.cc \
|
||||
hb-ot-metrics.hh \
|
||||
hb-ot-name-language-static.hh \
|
||||
hb-ot-name-language.hh \
|
||||
hb-ot-name-table.hh \
|
||||
hb-ot-name.cc \
|
||||
hb-ot-os2-table.hh \
|
||||
hb-ot-os2-unicode-ranges.hh \
|
||||
hb-ot-post-macroman.hh \
|
||||
hb-ot-post-table.hh \
|
||||
hb-ot-shape-complex-arabic-fallback.hh \
|
||||
hb-ot-shape-complex-arabic-joining-list.hh \
|
||||
hb-ot-shape-complex-arabic-table.hh \
|
||||
hb-ot-shape-complex-arabic-win1256.hh \
|
||||
hb-ot-shape-complex-arabic.cc \
|
||||
hb-ot-shape-complex-arabic.hh \
|
||||
hb-ot-shape-complex-default.cc \
|
||||
hb-ot-shape-complex-hangul.cc \
|
||||
hb-ot-shape-complex-hebrew.cc \
|
||||
hb-ot-shape-complex-indic-table.cc \
|
||||
hb-ot-shape-complex-indic.cc \
|
||||
hb-ot-shape-complex-indic.hh \
|
||||
hb-ot-shape-complex-khmer.cc \
|
||||
hb-ot-shape-complex-khmer.hh \
|
||||
hb-ot-shape-complex-myanmar.cc \
|
||||
hb-ot-shape-complex-myanmar.hh \
|
||||
hb-ot-shape-complex-syllabic.cc \
|
||||
hb-ot-shape-complex-syllabic.hh \
|
||||
hb-ot-shape-complex-thai.cc \
|
||||
hb-ot-shape-complex-use-table.hh \
|
||||
hb-ot-shape-complex-use.cc \
|
||||
hb-ot-shape-complex-vowel-constraints.cc \
|
||||
hb-ot-shape-complex-vowel-constraints.hh \
|
||||
hb-ot-shape-complex.hh \
|
||||
hb-ot-shape-fallback.cc \
|
||||
hb-ot-shape-fallback.hh \
|
||||
hb-ot-shape-normalize.cc \
|
||||
hb-ot-shape-normalize.hh \
|
||||
hb-ot-shape.cc \
|
||||
hb-ot-shape.hh \
|
||||
hb-ot-stat-table.hh \
|
||||
hb-ot-tag-table.hh \
|
||||
hb-ot-tag.cc \
|
||||
hb-ot-var-avar-table.hh \
|
||||
hb-ot-var-fvar-table.hh \
|
||||
hb-ot-var-gvar-table.hh \
|
||||
hb-ot-var-hvar-table.hh \
|
||||
hb-ot-var-mvar-table.hh \
|
||||
hb-ot-var.cc \
|
||||
hb-ot-vorg-table.hh \
|
||||
hb-pool.hh \
|
||||
hb-sanitize.hh \
|
||||
hb-serialize.hh \
|
||||
hb-set-digest.hh \
|
||||
hb-set.cc \
|
||||
hb-set.hh \
|
||||
hb-shape-plan.cc \
|
||||
hb-shape-plan.hh \
|
||||
hb-shape.cc \
|
||||
hb-shaper-impl.hh \
|
||||
hb-shaper-list.hh \
|
||||
hb-shaper.cc \
|
||||
hb-shaper.hh \
|
||||
hb-static.cc \
|
||||
hb-string-array.hh \
|
||||
hb-style.cc \
|
||||
hb-ucd-table.hh \
|
||||
hb-ucd.cc \
|
||||
hb-unicode-emoji-table.hh \
|
||||
hb-unicode.cc \
|
||||
hb-unicode.hh \
|
||||
hb-utf.hh \
|
||||
hb-vector.hh \
|
||||
hb-priority-queue.hh \
|
||||
hb.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_BASE_RAGEL_GENERATED_sources = \
|
||||
hb-buffer-deserialize-json.hh \
|
||||
hb-buffer-deserialize-text.hh \
|
||||
hb-number-parser.hh \
|
||||
hb-ot-shape-complex-indic-machine.hh \
|
||||
hb-ot-shape-complex-khmer-machine.hh \
|
||||
hb-ot-shape-complex-myanmar-machine.hh \
|
||||
hb-ot-shape-complex-use-machine.hh \
|
||||
$(NULL)
|
||||
HB_BASE_RAGEL_sources = \
|
||||
hb-buffer-deserialize-json.rl \
|
||||
hb-buffer-deserialize-text.rl \
|
||||
hb-number-parser.rl \
|
||||
hb-ot-shape-complex-indic-machine.rl \
|
||||
hb-ot-shape-complex-khmer-machine.rl \
|
||||
hb-ot-shape-complex-myanmar-machine.rl \
|
||||
hb-ot-shape-complex-use-machine.rl \
|
||||
$(NULL)
|
||||
|
||||
HB_BASE_headers = \
|
||||
hb-aat-layout.h \
|
||||
hb-aat.h \
|
||||
hb-blob.h \
|
||||
hb-buffer.h \
|
||||
hb-common.h \
|
||||
hb-deprecated.h \
|
||||
hb-draw.h \
|
||||
hb-face.h \
|
||||
hb-font.h \
|
||||
hb-map.h \
|
||||
hb-ot-color.h \
|
||||
hb-ot-deprecated.h \
|
||||
hb-ot-font.h \
|
||||
hb-ot-layout.h \
|
||||
hb-ot-math.h \
|
||||
hb-ot-meta.h \
|
||||
hb-ot-metrics.h \
|
||||
hb-ot-name.h \
|
||||
hb-ot-shape.h \
|
||||
hb-ot-var.h \
|
||||
hb-ot.h \
|
||||
hb-set.h \
|
||||
hb-shape-plan.h \
|
||||
hb-shape.h \
|
||||
hb-style.h \
|
||||
hb-unicode.h \
|
||||
hb-version.h \
|
||||
hb.h \
|
||||
$(NULL)
|
||||
|
||||
# Optional Sources and Headers with external deps
|
||||
|
||||
HB_FT_sources = hb-ft.cc
|
||||
HB_FT_headers = hb-ft.h
|
||||
|
||||
HB_GLIB_sources = hb-glib.cc
|
||||
HB_GLIB_headers = hb-glib.h
|
||||
|
||||
HB_GRAPHITE2_sources = hb-graphite2.cc
|
||||
HB_GRAPHITE2_headers = hb-graphite2.h
|
||||
|
||||
# System-dependent sources and headers
|
||||
|
||||
HB_CORETEXT_sources = hb-coretext.cc
|
||||
HB_CORETEXT_headers = hb-coretext.h
|
||||
|
||||
HB_DIRECTWRITE_sources = hb-directwrite.cc
|
||||
HB_DIRECTWRITE_headers = hb-directwrite.h
|
||||
|
||||
HB_GDI_sources = hb-gdi.cc
|
||||
HB_GDI_headers = hb-gdi.h
|
||||
|
||||
HB_UNISCRIBE_sources = hb-uniscribe.cc
|
||||
HB_UNISCRIBE_headers = hb-uniscribe.h
|
||||
|
||||
# Sources for libharfbuzz-gobject and libharfbuzz-icu
|
||||
HB_ICU_sources = hb-icu.cc
|
||||
HB_ICU_headers = hb-icu.h
|
||||
|
||||
# Sources for libharfbuzz-subset
|
||||
HB_SUBSET_sources = \
|
||||
hb-number.cc \
|
||||
hb-number.hh \
|
||||
hb-ot-cff1-table.cc \
|
||||
hb-ot-cff2-table.cc \
|
||||
hb-static.cc \
|
||||
hb-subset-cff-common.cc \
|
||||
hb-subset-cff-common.hh \
|
||||
hb-subset-cff1.cc \
|
||||
hb-subset-cff1.hh \
|
||||
hb-subset-cff2.cc \
|
||||
hb-subset-cff2.hh \
|
||||
hb-subset-input.cc \
|
||||
hb-subset-input.hh \
|
||||
hb-subset-plan.cc \
|
||||
hb-subset-plan.hh \
|
||||
hb-subset.cc \
|
||||
hb-subset.hh \
|
||||
hb-repacker.hh \
|
||||
$(NULL)
|
||||
|
||||
HB_SUBSET_headers = \
|
||||
hb-subset.h \
|
||||
$(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)
|
@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os
|
||||
|
||||
os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
|
||||
|
||||
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
|
||||
HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
|
||||
|
||||
stat = 0
|
||||
|
||||
for x in HBHEADERS:
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
if ('HB_BEGIN_DECLS' not in content) or ('HB_END_DECLS' not in content):
|
||||
print ('Ouch, file %s does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should' % x)
|
||||
stat = 1
|
||||
|
||||
for x in HBSOURCES:
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
if ('HB_BEGIN_DECLS' in content) or ('HB_END_DECLS' in content):
|
||||
print ('Ouch, file %s has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn\'t' % x)
|
||||
stat = 1
|
||||
|
||||
sys.exit (stat)
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os, re
|
||||
|
||||
os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
|
||||
|
||||
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
|
||||
|
||||
stat = 0
|
||||
|
||||
print ('Checking that all public symbols are exported with HB_EXTERN')
|
||||
for x in HBHEADERS:
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
for s in re.findall (r'\n.+\nhb_.+\n', content):
|
||||
if not s.startswith ('\nHB_EXTERN '):
|
||||
print ('failure on:', s)
|
||||
stat = 1
|
||||
|
||||
sys.exit (stat)
|
@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os, re
|
||||
|
||||
os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
|
||||
|
||||
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
|
||||
HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
|
||||
|
||||
stat = 0
|
||||
|
||||
for x in HBHEADERS + HBSOURCES:
|
||||
if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue
|
||||
tag = x.upper ().replace ('.', '_').replace ('-', '_')
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
if len (re.findall (tag + r'\b', content)) != 3:
|
||||
print ('Ouch, header file %s does not have correct preprocessor guards' % x)
|
||||
stat = 1
|
||||
|
||||
sys.exit (stat)
|
@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os, re
|
||||
|
||||
os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
|
||||
|
||||
HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
|
||||
HBSOURCES = [os.path.basename (x) for x in os.getenv ('HBSOURCES', '').split ()] or \
|
||||
[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))]
|
||||
|
||||
stat = 0
|
||||
|
||||
print ('Checking that public header files #include "hb-common.h" or "hb.h" first (or none)')
|
||||
for x in HBHEADERS:
|
||||
if x == 'hb.h' or x == 'hb-common.h': continue
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
first = re.findall (r'#.*include.*', content)[0]
|
||||
if first not in ['#include "hb.h"', '#include "hb-common.h"']:
|
||||
print ('failure on %s' % x)
|
||||
stat = 1
|
||||
|
||||
print ('Checking that source files #include a private header first (or none)')
|
||||
for x in HBSOURCES:
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
includes = re.findall (r'#.*include.*', content)
|
||||
if includes:
|
||||
if not len (re.findall (r'"hb.*\.hh"', includes[0])):
|
||||
print ('failure on %s' % x)
|
||||
stat = 1
|
||||
|
||||
print ('Checking that there is no #include <hb-*.h>')
|
||||
for x in HBHEADERS + HBSOURCES:
|
||||
with open (x, 'r', encoding='utf-8') as f: content = f.read ()
|
||||
if re.findall ('#.*include.*<.*hb', content):
|
||||
print ('failure on %s' % x)
|
||||
stat = 1
|
||||
|
||||
sys.exit (stat)
|
@ -1,41 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os, shutil, subprocess
|
||||
|
||||
os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
|
||||
|
||||
libs = os.getenv ('libs', '.libs')
|
||||
|
||||
ldd = shutil.which ('ldd')
|
||||
if ldd:
|
||||
ldd = [ldd]
|
||||
else:
|
||||
ldd = shutil.which ('otool')
|
||||
if ldd:
|
||||
ldd = [ldd, '-L'] # otool -L
|
||||
else:
|
||||
print ('check-libstdc++.py: \'ldd\' not found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
stat = 0
|
||||
tested = False
|
||||
|
||||
# harfbuzz-icu links to libstdc++ because icu does.
|
||||
for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']:
|
||||
for suffix in ['so', 'dylib']:
|
||||
so = os.path.join (libs, 'lib%s.%s' % (soname, suffix))
|
||||
if not os.path.exists (so): continue
|
||||
|
||||
print ('Checking that we are not linking to libstdc++ or libc++ in %s' % so)
|
||||
ldd_result = subprocess.check_output (ldd + [so])
|
||||
if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result):
|
||||
print ('Ouch, %s is linked to libstdc++ or libc++' % so)
|
||||
stat = 1
|
||||
|
||||
tested = True
|
||||
|
||||
if not tested:
|
||||
print ('check-libstdc++.py: libharfbuzz shared library not found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
sys.exit (stat)
|
@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os, shutil, subprocess, glob, re
|
||||
|
||||
builddir = os.getenv ('builddir', os.path.dirname (__file__))
|
||||
libs = os.getenv ('libs', '.libs')
|
||||
|
||||
objdump = shutil.which ('objdump')
|
||||
if not objdump:
|
||||
print ('check-static-inits.py: \'ldd\' not found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
if sys.version_info < (3, 5):
|
||||
print ('check-static-inits.py: needs python 3.5 for recursive support in glob')
|
||||
sys.exit (77)
|
||||
|
||||
OBJS = glob.glob (os.path.join (builddir, libs, '**', '*.o'), recursive=True)
|
||||
if not OBJS:
|
||||
print ('check-static-inits.py: object files not found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
stat = 0
|
||||
|
||||
for obj in OBJS:
|
||||
result = subprocess.check_output ([objdump, '-t', obj]).decode ('utf-8')
|
||||
|
||||
# Checking that no object file has static initializers
|
||||
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
|
||||
if not re.match (r'.*\b0+\b', l):
|
||||
print ('Ouch, %s has static initializers/finalizers' % obj)
|
||||
stat = 1
|
||||
|
||||
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
|
||||
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
|
||||
print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
|
||||
stat = 1
|
||||
|
||||
sys.exit (stat)
|
@ -1,73 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os, shutil, subprocess, re, difflib
|
||||
|
||||
os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
|
||||
|
||||
builddir = os.getenv ('builddir', os.path.dirname (__file__))
|
||||
libs = os.getenv ('libs', '.libs')
|
||||
|
||||
IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
|
||||
'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
|
||||
'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path'])
|
||||
|
||||
nm = shutil.which ('nm')
|
||||
if not nm:
|
||||
print ('check-symbols.py: \'nm\' not found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
cxxflit = shutil.which ('c++filt')
|
||||
|
||||
tested = False
|
||||
stat = 0
|
||||
|
||||
for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']:
|
||||
for suffix in ['so', 'dylib']:
|
||||
so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
|
||||
if not os.path.exists (so): continue
|
||||
|
||||
# On macOS, C symbols are prefixed with _
|
||||
symprefix = '_' if suffix == 'dylib' else ''
|
||||
|
||||
EXPORTED_SYMBOLS = [s.split ()[2]
|
||||
for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output ([nm, so]).decode ('utf-8'), re.MULTILINE)
|
||||
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
|
||||
|
||||
# run again c++flit also if is available
|
||||
if cxxflit:
|
||||
EXPORTED_SYMBOLS = subprocess.check_output (
|
||||
[cxxflit], input='\n'.join (EXPORTED_SYMBOLS).encode ()
|
||||
).decode ('utf-8').splitlines ()
|
||||
|
||||
prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
|
||||
|
||||
print ('Checking that %s does not expose internal symbols' % so)
|
||||
suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)]
|
||||
if suspicious_symbols:
|
||||
print ('Ouch, internal symbols exposed:', suspicious_symbols)
|
||||
stat = 1
|
||||
|
||||
def_path = os.path.join (builddir, soname + '.def')
|
||||
if not os.path.exists (def_path):
|
||||
print ('\'%s\' not found; skipping' % def_path)
|
||||
else:
|
||||
print ('Checking that %s has the same symbol list as %s' % (so, def_path))
|
||||
with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read ()
|
||||
diff_result = list (difflib.context_diff (
|
||||
def_file.splitlines (),
|
||||
['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] +
|
||||
# cheat: copy the last line from the def file!
|
||||
[def_file.splitlines ()[-1]]
|
||||
))
|
||||
|
||||
if diff_result:
|
||||
print ('\n'.join (diff_result))
|
||||
stat = 1
|
||||
|
||||
tested = True
|
||||
|
||||
if not tested:
|
||||
print ('check-symbols.sh: no shared libraries found; skipping test')
|
||||
sys.exit (77)
|
||||
|
||||
sys.exit (stat)
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int alloc_state = 0;
|
||||
|
||||
__attribute__((no_sanitize("integer")))
|
||||
static int fastrand ()
|
||||
{
|
||||
if (!alloc_state) return 1;
|
||||
/* Based on https://software.intel.com/content/www/us/en/develop/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor.html */
|
||||
alloc_state = (214013 * alloc_state + 2531011);
|
||||
return (alloc_state >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
void* hb_malloc_impl (size_t size)
|
||||
{
|
||||
return (fastrand () % 16) ? malloc (size) : NULL;
|
||||
}
|
||||
|
||||
void* hb_calloc_impl (size_t nmemb, size_t size)
|
||||
{
|
||||
return (fastrand () % 16) ? calloc (nmemb, size) : NULL;
|
||||
}
|
||||
|
||||
void* hb_realloc_impl (void *ptr, size_t size)
|
||||
{
|
||||
return (fastrand () % 16) ? realloc (ptr, size) : NULL;
|
||||
}
|
||||
|
||||
void hb_free_impl (void *ptr)
|
||||
{
|
||||
return free (ptr);
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser ()
|
||||
parser.add_argument ('input')
|
||||
parser.add_argument ('output')
|
||||
args = parser.parse_args ()
|
||||
|
||||
with open (args.input, 'r') as inp, open (args.output, 'w') as out:
|
||||
for l in inp.readlines ():
|
||||
l = re.sub ('_t_get_type', '_get_type', l)
|
||||
l = re.sub ('_T \(', ' (', l)
|
||||
out.write (l)
|
@ -1,106 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""usage: ./gen-arabic-joining-table.py ArabicShaping.txt Scripts.txt
|
||||
|
||||
Input files:
|
||||
* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
|
||||
"""
|
||||
|
||||
import os.path, sys
|
||||
|
||||
if len (sys.argv) != 3:
|
||||
sys.exit (__doc__)
|
||||
|
||||
files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
|
||||
|
||||
headers = [[f.readline (), f.readline ()] for f in files]
|
||||
while files[0].readline ().find ('##################') < 0:
|
||||
pass
|
||||
|
||||
def read (f):
|
||||
mapping = {}
|
||||
for line in f:
|
||||
|
||||
j = line.find ('#')
|
||||
if j >= 0:
|
||||
line = line[:j]
|
||||
|
||||
fields = [x.strip () for x in line.split (';')]
|
||||
if len (fields) == 1:
|
||||
continue
|
||||
|
||||
uu = fields[0].split ('..')
|
||||
start = int (uu[0], 16)
|
||||
if len (uu) == 1:
|
||||
end = start
|
||||
else:
|
||||
end = int (uu[1], 16)
|
||||
|
||||
t = fields[1]
|
||||
|
||||
for u in range (start, end + 1):
|
||||
mapping[u] = t
|
||||
|
||||
return mapping
|
||||
|
||||
def read_joining_uu (f):
|
||||
values = set ()
|
||||
for line in f:
|
||||
|
||||
if line[0] == '#':
|
||||
continue
|
||||
|
||||
fields = [x.strip () for x in line.split (';')]
|
||||
if len (fields) == 1:
|
||||
continue
|
||||
if fields[2] in {'T', 'U'}:
|
||||
continue
|
||||
|
||||
values.add (int (fields[0], 16))
|
||||
|
||||
return sorted (values)
|
||||
|
||||
def print_has_arabic_joining (scripts, joining_uu):
|
||||
|
||||
print ("static bool")
|
||||
print ("has_arabic_joining (hb_script_t script)")
|
||||
print ("{")
|
||||
print (" /* List of scripts that have data in arabic-table. */")
|
||||
print (" switch ((int) script)")
|
||||
print (" {")
|
||||
|
||||
for script in sorted ({scripts[u] for u in joining_uu if scripts[u] not in {'Common', 'Inherited'}}):
|
||||
print (" case HB_SCRIPT_{}:".format (script.upper ()))
|
||||
|
||||
print (" return true;")
|
||||
print ()
|
||||
print (" default:")
|
||||
print (" return false;")
|
||||
print (" }")
|
||||
print ("}")
|
||||
print ()
|
||||
|
||||
print ("/* == Start of generated function == */")
|
||||
print ("/*")
|
||||
print (" * The following function is generated by running:")
|
||||
print (" *")
|
||||
print (" * ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt")
|
||||
print (" *")
|
||||
print (" * on files with these headers:")
|
||||
print (" *")
|
||||
for h in headers:
|
||||
for l in h:
|
||||
print (" * %s" % (l.strip ()))
|
||||
print (" */")
|
||||
print ()
|
||||
print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH")
|
||||
print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH")
|
||||
print ()
|
||||
|
||||
print_has_arabic_joining (read (files[1]), read_joining_uu (files[0]))
|
||||
|
||||
print ()
|
||||
print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */")
|
||||
print ()
|
||||
print ("/* == End of generated function == */")
|
@ -1,271 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""usage: ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt
|
||||
|
||||
Input files:
|
||||
* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
|
||||
* https://unicode.org/Public/UCD/latest/ucd/Blocks.txt
|
||||
"""
|
||||
|
||||
import os.path, sys
|
||||
|
||||
if len (sys.argv) != 4:
|
||||
sys.exit (__doc__)
|
||||
|
||||
files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
|
||||
|
||||
headers = [[files[0].readline (), files[0].readline ()], [files[2].readline (), files[2].readline ()]]
|
||||
headers.append (["UnicodeData.txt does not have a header."])
|
||||
while files[0].readline ().find ('##################') < 0:
|
||||
pass
|
||||
|
||||
blocks = {}
|
||||
def read_blocks(f):
|
||||
global blocks
|
||||
for line in f:
|
||||
|
||||
j = line.find ('#')
|
||||
if j >= 0:
|
||||
line = line[:j]
|
||||
|
||||
fields = [x.strip () for x in line.split (';')]
|
||||
if len (fields) == 1:
|
||||
continue
|
||||
|
||||
uu = fields[0].split ('..')
|
||||
start = int (uu[0], 16)
|
||||
if len (uu) == 1:
|
||||
end = start
|
||||
else:
|
||||
end = int (uu[1], 16)
|
||||
|
||||
t = fields[1]
|
||||
|
||||
for u in range (start, end + 1):
|
||||
blocks[u] = t
|
||||
|
||||
def print_joining_table(f):
|
||||
|
||||
values = {}
|
||||
for line in f:
|
||||
|
||||
if line[0] == '#':
|
||||
continue
|
||||
|
||||
fields = [x.strip () for x in line.split (';')]
|
||||
if len (fields) == 1:
|
||||
continue
|
||||
|
||||
u = int (fields[0], 16)
|
||||
|
||||
if fields[3] in ["ALAPH", "DALATH RISH"]:
|
||||
value = "JOINING_GROUP_" + fields[3].replace(' ', '_')
|
||||
else:
|
||||
value = "JOINING_TYPE_" + fields[2]
|
||||
values[u] = value
|
||||
|
||||
short_value = {}
|
||||
for value in sorted (set ([v for v in values.values ()] + ['JOINING_TYPE_X'])):
|
||||
short = ''.join(x[0] for x in value.split('_')[2:])
|
||||
assert short not in short_value.values()
|
||||
short_value[value] = short
|
||||
|
||||
print ()
|
||||
for value,short in short_value.items():
|
||||
print ("#define %s %s" % (short, value))
|
||||
|
||||
uu = sorted(values.keys())
|
||||
num = len(values)
|
||||
all_blocks = set([blocks[u] for u in uu])
|
||||
|
||||
last = -100000
|
||||
ranges = []
|
||||
for u in uu:
|
||||
if u - last <= 1+16*5:
|
||||
ranges[-1][-1] = u
|
||||
else:
|
||||
ranges.append([u,u])
|
||||
last = u
|
||||
|
||||
print ()
|
||||
print ("static const uint8_t joining_table[] =")
|
||||
print ("{")
|
||||
last_block = None
|
||||
offset = 0
|
||||
for start,end in ranges:
|
||||
|
||||
print ()
|
||||
print ("#define joining_offset_0x%04xu %d" % (start, offset))
|
||||
|
||||
for u in range(start, end+1):
|
||||
|
||||
block = blocks.get(u, last_block)
|
||||
value = values.get(u, "JOINING_TYPE_X")
|
||||
|
||||
if block != last_block or u == start:
|
||||
if u != start:
|
||||
print ()
|
||||
if block in all_blocks:
|
||||
print ("\n /* %s */" % block)
|
||||
else:
|
||||
print ("\n /* FILLER */")
|
||||
last_block = block
|
||||
if u % 32 != 0:
|
||||
print ()
|
||||
print (" /* %04X */" % (u//32*32), " " * (u % 32), end="")
|
||||
|
||||
if u % 32 == 0:
|
||||
print ()
|
||||
print (" /* %04X */ " % u, end="")
|
||||
print ("%s," % short_value[value], end="")
|
||||
print ()
|
||||
|
||||
offset += end - start + 1
|
||||
print ()
|
||||
occupancy = num * 100. / offset
|
||||
print ("}; /* Table items: %d; occupancy: %d%% */" % (offset, occupancy))
|
||||
print ()
|
||||
|
||||
page_bits = 12
|
||||
print ()
|
||||
print ("static unsigned int")
|
||||
print ("joining_type (hb_codepoint_t u)")
|
||||
print ("{")
|
||||
print (" switch (u >> %d)" % page_bits)
|
||||
print (" {")
|
||||
pages = set([u>>page_bits for u in [s for s,e in ranges]+[e for s,e in ranges]])
|
||||
for p in sorted(pages):
|
||||
print (" case 0x%0Xu:" % p)
|
||||
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<hb_codepoint_t> (u, 0x%04Xu, 0x%04Xu)) return joining_table[u - 0x%04Xu + %s];" % (start, end, start, offset))
|
||||
print (" break;")
|
||||
print ("")
|
||||
print (" default:")
|
||||
print (" break;")
|
||||
print (" }")
|
||||
print (" return X;")
|
||||
print ("}")
|
||||
print ()
|
||||
for value,short in short_value.items():
|
||||
print ("#undef %s" % (short))
|
||||
print ()
|
||||
|
||||
def print_shaping_table(f):
|
||||
|
||||
shapes = {}
|
||||
ligatures = {}
|
||||
names = {}
|
||||
for line in f:
|
||||
|
||||
fields = [x.strip () for x in line.split (';')]
|
||||
if fields[5][0:1] != '<':
|
||||
continue
|
||||
|
||||
items = fields[5].split (' ')
|
||||
shape, items = items[0][1:-1], tuple (int (x, 16) for x in items[1:])
|
||||
|
||||
if not shape in ['initial', 'medial', 'isolated', 'final']:
|
||||
continue
|
||||
|
||||
c = int (fields[0], 16)
|
||||
if len (items) != 1:
|
||||
# We only care about lam-alef ligatures
|
||||
if len (items) != 2 or items[0] != 0x0644 or items[1] not in [0x0622, 0x0623, 0x0625, 0x0627]:
|
||||
continue
|
||||
|
||||
# Save ligature
|
||||
names[c] = fields[1]
|
||||
if items not in ligatures:
|
||||
ligatures[items] = {}
|
||||
ligatures[items][shape] = c
|
||||
else:
|
||||
# Save shape
|
||||
if items[0] not in names:
|
||||
names[items[0]] = fields[1]
|
||||
else:
|
||||
names[items[0]] = os.path.commonprefix ([names[items[0]], fields[1]]).strip ()
|
||||
if items[0] not in shapes:
|
||||
shapes[items[0]] = {}
|
||||
shapes[items[0]][shape] = c
|
||||
|
||||
print ()
|
||||
print ("static const uint16_t shaping_table[][4] =")
|
||||
print ("{")
|
||||
|
||||
keys = shapes.keys ()
|
||||
min_u, max_u = min (keys), max (keys)
|
||||
for u in range (min_u, max_u + 1):
|
||||
s = [shapes[u][shape] if u in shapes and shape in shapes[u] else 0
|
||||
for shape in ['initial', 'medial', 'final', 'isolated']]
|
||||
value = ', '.join ("0x%04Xu" % c for c in s)
|
||||
print (" {%s}, /* U+%04X %s */" % (value, u, names[u] if u in names else ""))
|
||||
|
||||
print ("};")
|
||||
print ()
|
||||
print ("#define SHAPING_TABLE_FIRST 0x%04Xu" % min_u)
|
||||
print ("#define SHAPING_TABLE_LAST 0x%04Xu" % max_u)
|
||||
print ()
|
||||
|
||||
ligas = {}
|
||||
for pair in ligatures.keys ():
|
||||
for shape in ligatures[pair]:
|
||||
c = ligatures[pair][shape]
|
||||
if shape == 'isolated':
|
||||
liga = (shapes[pair[0]]['initial'], shapes[pair[1]]['final'])
|
||||
elif shape == 'final':
|
||||
liga = (shapes[pair[0]]['medial'], shapes[pair[1]]['final'])
|
||||
else:
|
||||
raise Exception ("Unexpected shape", shape)
|
||||
if liga[0] not in ligas:
|
||||
ligas[liga[0]] = []
|
||||
ligas[liga[0]].append ((liga[1], c))
|
||||
max_i = max (len (ligas[l]) for l in ligas)
|
||||
print ()
|
||||
print ("static const struct ligature_set_t {")
|
||||
print (" uint16_t first;")
|
||||
print (" struct ligature_pairs_t {")
|
||||
print (" uint16_t second;")
|
||||
print (" uint16_t ligature;")
|
||||
print (" } ligatures[%d];" % max_i)
|
||||
print ("} ligature_table[] =")
|
||||
print ("{")
|
||||
for first in sorted (ligas.keys ()):
|
||||
|
||||
print (" { 0x%04Xu, {" % (first))
|
||||
for liga in ligas[first]:
|
||||
print (" { 0x%04Xu, 0x%04Xu }, /* %s */" % (liga[0], liga[1], names[liga[1]]))
|
||||
print (" }},")
|
||||
|
||||
print ("};")
|
||||
print ()
|
||||
|
||||
|
||||
|
||||
print ("/* == Start of generated table == */")
|
||||
print ("/*")
|
||||
print (" * The following table is generated by running:")
|
||||
print (" *")
|
||||
print (" * ./gen-arabic-table.py ArabicShaping.txt UnicodeData.txt Blocks.txt")
|
||||
print (" *")
|
||||
print (" * on files with these headers:")
|
||||
print (" *")
|
||||
for h in headers:
|
||||
for l in h:
|
||||
print (" * %s" % (l.strip()))
|
||||
print (" */")
|
||||
print ()
|
||||
print ("#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
|
||||
print ("#define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH")
|
||||
print ()
|
||||
|
||||
read_blocks (files[2])
|
||||
print_joining_table (files[0])
|
||||
print_shaping_table (files[1])
|
||||
|
||||
print ()
|
||||
print ("#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH */")
|
||||
print ()
|
||||
print ("/* == End of generated table == */")
|
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]"
|
||||
|
||||
import os, re, sys
|
||||
|
||||
if len (sys.argv) < 3:
|
||||
sys.exit(__doc__)
|
||||
|
||||
output_file = sys.argv[1]
|
||||
header_paths = sys.argv[2:]
|
||||
|
||||
headers_content = []
|
||||
for h in header_paths:
|
||||
if h.endswith (".h"):
|
||||
with open (h, encoding='utf-8') as f: headers_content.append (f.read ())
|
||||
|
||||
symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))
|
||||
if '--experimental-api' not in sys.argv:
|
||||
# Move these to harfbuzz-sections.txt when got stable
|
||||
experimental_symbols = \
|
||||
"""hb_font_draw_glyph
|
||||
hb_draw_funcs_t
|
||||
hb_draw_close_path_func_t
|
||||
hb_draw_cubic_to_func_t
|
||||
hb_draw_line_to_func_t
|
||||
hb_draw_move_to_func_t
|
||||
hb_draw_quadratic_to_func_t
|
||||
hb_draw_funcs_create
|
||||
hb_draw_funcs_destroy
|
||||
hb_draw_funcs_is_immutable
|
||||
hb_draw_funcs_make_immutable
|
||||
hb_draw_funcs_reference
|
||||
hb_draw_funcs_set_close_path_func
|
||||
hb_draw_funcs_set_cubic_to_func
|
||||
hb_draw_funcs_set_line_to_func
|
||||
hb_draw_funcs_set_move_to_func
|
||||
hb_draw_funcs_set_quadratic_to_func
|
||||
hb_style_get_value
|
||||
hb_font_get_var_coords_design""".splitlines ()
|
||||
symbols = [x for x in symbols if x not in experimental_symbols]
|
||||
symbols = "\n".join (symbols)
|
||||
|
||||
result = symbols if os.getenv ('PLAIN_LIST', '') else """EXPORTS
|
||||
%s
|
||||
LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('src/', '').replace ('.def', ''))
|
||||
|
||||
with open (output_file, "w") as f: f.write (result)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user