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:
w00845693 2023-11-29 15:22:28 +08:00
parent c11ddb09fb
commit b452025fb8
2886 changed files with 851 additions and 188750 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
comment: off
coverage:
status:
project:
default:
threshold: 1%

View File

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

View File

@ -1,11 +0,0 @@
### 该问题是怎么引起的?
### 重现步骤
### 报错信息

View File

@ -1,12 +0,0 @@
### 相关的Issue
### 原因(目的、解决的问题等)
### 描述(做了什么,变更了什么)
### 测试用例(新增、改动、可能影响的功能)

View File

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

View File

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

View File

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

View File

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

@ -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
View 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"
}
}

View File

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

View File

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

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

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

View File

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

2466
NEWS

File diff suppressed because it is too large Load Diff

15
README
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

@ -1,7 +0,0 @@
Bradley Grainger
Kenichi Ishibashi
Ivan Kuckir <https://photopea.com/>
Ryan Lortie
Jeff Muizelaar
suzuki toshiya
Philip Withnall

28
TODO
View File

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

View File

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

View 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

View 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

View 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;

View File

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

View File

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

View File

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

View File

@ -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&mdash;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>

View File

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

View File

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

View File

@ -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> "&#xFFFD;". You can change this with
</para>
<programlisting language="C">
hb_buffer_set_replacement_codepoint(buf, replacement);
</programlisting>
<para>
passing in the replacement Unicode code point as the
<parameter>replacement</parameter> parameter.
</para>
<para>
The invisible glyph is used to replace all output glyphs that
are invisible. By default, the standard space character
<literal>U+0020</literal> is used; you can replace this (for
example, when using a font that provides script-specific
spaces) with
</para>
<programlisting language="C">
hb_buffer_set_invisible_glyph(buf, replacement_glyph);
</programlisting>
<para>
Do note that in the <parameter>replacement_glyph</parameter>
parameter, you must provide the glyph ID of the replacement you
wish to use, not the Unicode code point.
</para>
<para>
HarfBuzz supports a few additional flags you might want to set
on your buffer under certain circumstances. The
<literal>HB_BUFFER_FLAG_BOT</literal> and
<literal>HB_BUFFER_FLAG_EOT</literal> flags tell HarfBuzz
that the buffer represents the beginning or end (respectively)
of a text element (such as a paragraph or other block). Knowing
this allows HarfBuzz to apply certain contextual font features
when shaping, such as initial or final variants in connected
scripts.
</para>
<para>
<literal>HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES</literal>
tells HarfBuzz not to hide glyphs with the
<literal>Default_Ignorable</literal> property in Unicode. This
property designates control characters and other non-printing
code points, such as joiners and variation selectors. Normally
HarfBuzz replaces them in the output buffer with zero-width
space glyphs (using the "invisible glyph" property discussed
above); setting this flag causes them to be printed, which can
be helpful for troubleshooting.
</para>
<para>
Conversely, setting the
<literal>HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES</literal> flag
tells HarfBuzz to remove <literal>Default_Ignorable</literal>
glyphs from the output buffer entirely. Finally, setting the
<literal>HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE</literal>
flag tells HarfBuzz not to insert the dotted-circle glyph
(<literal>U+25CC</literal>, "&#x25CC;"), which is normally
inserted into buffer output when broken character sequences are
encountered (such as combining marks that are not attached to a
base character).
</para>
</section>
<section id="customizing-unicode-functions">
<title>Customizing Unicode functions</title>
<para>
HarfBuzz requires some simple functions for accessing
information from the Unicode Character Database (such as the
<literal>General_Category</literal> (gc) and
<literal>Script</literal> (sc) properties) that is useful
for shaping, as well as some useful operations like composing and
decomposing code points.
</para>
<para>
HarfBuzz includes its own internal, lightweight set of Unicode
functions. At build time, it is also possible to compile support
for some other options, such as the Unicode functions provided
by GLib or the International Components for Unicode (ICU)
library. Generally, this option is only of interest for client
programs that have specific integration requirements or that do
a significant amount of customization.
</para>
<para>
If your program has access to other Unicode functions, however,
such as through a system library or application framework, you
might prefer to use those instead of the built-in
options. HarfBuzz supports this by implementing its Unicode
functions as a set of virtual methods that you can replace —
without otherwise affecting HarfBuzz's functionality.
</para>
<para>
The Unicode functions are specified in a structure called
<literal>unicode_funcs</literal> which is attached to each
buffer. But even though <literal>unicode_funcs</literal> is
associated with a <type>hb_buffer_t</type>, the functions
themselves are called by other HarfBuzz APIs that access
buffers, so it would be unwise for you to hook different
functions into different buffers.
</para>
<para>
In addition, you can mark your <literal>unicode_funcs</literal>
as immutable by calling
<function>hb_unicode_funcs_make_immutable (ufuncs)</function>.
This is especially useful if your code is a
library or framework that will have its own client programs. By
marking your Unicode function choices as immutable, you prevent
your own client programs from changing the
<literal>unicode_funcs</literal> configuration and introducing
inconsistencies and errors downstream.
</para>
<para>
You can retrieve the Unicode-functions configuration for
your buffer by calling <function>hb_buffer_get_unicode_funcs()</function>:
</para>
<programlisting language="C">
hb_unicode_funcs_t *ufunctions;
ufunctions = hb_buffer_get_unicode_funcs(buf);
</programlisting>
<para>
The current version of <literal>unicode_funcs</literal> uses six functions:
</para>
<itemizedlist>
<listitem>
<para>
<function>hb_unicode_combining_class_func_t</function>:
returns the Canonical Combining Class of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_general_category_func_t</function>:
returns the General Category (gc) of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_mirroring_func_t</function>: returns
the Mirroring Glyph code point (for bi-directional
replacement) of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_script_func_t</function>: returns the
Script (sc) property of a code point.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_compose_func_t</function>: returns the
canonical composition of a sequence of two code points.
</para>
</listitem>
<listitem>
<para>
<function>hb_unicode_decompose_func_t</function>: returns
the canonical decomposition of a code point.
</para>
</listitem>
</itemizedlist>
<para>
Note, however, that future HarfBuzz releases may alter this set.
</para>
<para>
Each Unicode function has a corresponding setter, with which you
can assign a callback to your replacement function. For example,
to replace
<function>hb_unicode_general_category_func_t</function>, you can call
</para>
<programlisting language="C">
hb_unicode_funcs_set_general_category_func (*ufuncs, func, *user_data, destroy)
</programlisting>
<para>
Virtualizing this set of Unicode functions is primarily intended
to improve portability. There is no need for every client
program to make the effort to replace the default options, so if
you are unsure, do not feel any pressure to customize
<literal>unicode_funcs</literal>.
</para>
</section>
</chapter>

View File

@ -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 &mdash; such as a ligature or conjunct form
&mdash; 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 &mdash;
even though the two original, underlying letters remain separate
graphemes.
</para>
<para>
HarfBuzz is concerned with clusters, <emphasis>not</emphasis>
with graphemes &mdash; 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 &mdash;
such as reordering, composition, decomposition, and substitution
&mdash; 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
&quot;merge&quot;. 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 &mdash; 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 &mdash;
including marks and modifiers &mdash; 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>

View File

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

View File

@ -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 &lt;hb.h&gt;
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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;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 &lt; 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>

View File

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

View File

@ -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&ndash;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>

View File

@ -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
&mdash; 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 &lt;hb-glib.h&gt;
...
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 &lt;hb-ft.h&gt;
...
FT_New_Face(ft_library, font_path, index, &amp;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 &mdash; 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 &mdash; even to the point of
duplicating known shaping bugs or deviations from the
specification &mdash; 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> &mdash; a handle to the underlying logical
font &mdash; 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>

View File

@ -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 its extremely inefficient to do otherwise.
</para>
<para>
In HarfBuzz, several structs, like <literal>hb_glyph_info_t</literal> and
<literal>hb_glyph_position_t</literal>, fall into that efficiency-sensitive
category and are non-opaque.
</para>
<para>
For all non-opaque structs where future extensibility may be
necessary, reserved members are included to hold space for
possible future members. As such, its important to provide
<function>equal()</function>, and <function>hash()</function>
methods for such structs, allowing users of the API do
effectively deal with the type without having to
adapt their code to future changes.
</para>
<para>
Important value types provided by HarfBuzz include the structs
for working with Unicode code points, glyphs, and tags for font
tables and features, as well as the enums for many Unicode and
OpenType properties.
</para>
</section>
<section id="object-model-object-types">
<title>Objects in HarfBuzz</title>
<para>
<emphasis>Object types:</emphasis> Opaque struct types are used
for what HarfBuzz loosely calls "objects." This doesnt have
much to do with the terminology from object-oriented programming
(OOP), although some of the concepts are similar.
</para>
<para>
In HarfBuzz, all object types provide certain
lifecycle-management APIs. Objects are reference-counted, and
constructed with various <function>create()</function> methods, referenced via
<function>reference()</function> and dereferenced using
<function>destroy()</function>.
</para>
<para>
For example,
the <literal>hb_buffer_t</literal> object has
<function>hb_buffer_create()</function> as its constructor,
<function>hb_buffer_reference()</function> to reference, and
<function>hb_buffer_destroy()</function> to dereference.
</para>
<para>
After construction, each object's properties are accessible only
through the setter and getter functions described in the API
Reference manual.
</para>
<para>
Key object types provided by HarfBuzz include:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
<emphasis>blobs</emphasis>, which act as low-level wrappers around binary
data. Blobs are typically used to hold the contents of a
binary font file.
</para>
</listitem>
<listitem>
<para>
<emphasis>faces</emphasis>, which represent typefaces from a
font file, but without specific parameters (such as size) set.
</para>
</listitem>
<listitem>
<para>
<emphasis>fonts</emphasis>, which represent instances of a
face with all of their parameters specified.
</para>
</listitem>
<listitem>
<para>
<emphasis>buffers</emphasis>, which hold Unicode code points
for characters (before shaping) and the shaped glyph output
(after shaping).
</para>
</listitem>
<listitem>
<para>
<emphasis>shape plans</emphasis>, which store the settings
that HarfBuzz will use when shaping a particular text
segment. Shape plans are not generally used by client
programs directly, but as we will see in a later chapter,
they are still valuable to understand.
</para>
</listitem>
</itemizedlist>
</section>
<section id="object-model-lifecycle">
<title>Object lifecycle management</title>
<para>
Each object type in HarfBuzz provides a
<function>create()</function> method. Some object types provide
additional variants of <function>create()</function> to handle
special cases or to speed up common tasks; those variants are
documented in the API reference. For example,
<function>hb_blob_create_from_file()</function> constructs a new
blob directly from the contents of a file.
</para>
<para>
All objects are created with an initial reference count of
<literal>1</literal>. Client programs can increase the reference
count on an object by calling its
<function>reference()</function> method. Whenever a client
program is finished with an object, it should call its
corresponding <function>destroy()</function> method. The destroy
method will decrease the reference count on the object and,
whenever the reference count reaches zero, it will also destroy
the object and free all of the associated memory.
</para>
<para>
All of HarfBuzz's object-lifecycle-management APIs are
thread-safe (unless you compiled HarfBuzz from source with the
<literal>HB_NO_MT</literal> configuration flag), even when the
object as a whole is not thread-safe.
It is also permissible to <function>reference()</function> or to
<function>destroy()</function> the <literal>NULL</literal>
value.
</para>
<para>
Some objects are thread-safe after they have been constructed
and set up. The general pattern is to
<function>create()</function> the object, make a few
<function>set_*()</function> calls to set up the
object, and then use it without further modification.
</para>
<para>
To ensure that such an object is not modified, client programs
can explicitly mark an object as immutable. HarfBuzz provides
<function>make_immutable()</function> methods to mark an object
as immutable and <function>is_immutable()</function> methods to
test whether or not an object is immutable. Attempts to use
setter functions on immutable objects will fail silently; see the API
Reference manual for specifics.
</para>
<para>
Note also that there are no "make mutable" methods. If client
programs need to alter an object previously marked as immutable,
they will need to make a duplicate of the original.
</para>
<para>
Finally, object constructors (and, indeed, as much of the
shaping API as possible) will never return
<literal>NULL</literal>. Instead, if there is an allocation
error, each constructor will return an “empty” object
singleton.
</para>
<para>
These empty-object singletons are inert and safe (although
typically useless) to pass around. This design choice avoids
having to check for <literal>NULL</literal> pointers all
throughout the code.
</para>
<para>
In addition, this “empty” object singleton can also be accessed
using the <function>get_empty()</function> method of the object
type in question.
</para>
</section>
<section id="object-model-user-data">
<title>User data</title>
<para>
To better integrate with client programs, HarfBuzz's objects
offer a "user data" mechanism that can be used to attach
arbitrary data to the object. User-data attachment can be
useful for tying the lifecycles of various pieces of data
together, or for creating language bindings.
</para>
<para>
Each object type has a <function>set_user_data()</function>
method and a <function>get_user_data()</function> method. The
<function>set_user_data()</function> methods take a client-provided
<literal>key</literal> and a pointer,
<literal>user_data</literal>, pointing to the data itself. Once
the key-data pair has been attached to the object, the
<function>get_user_data()</function> method can be called with
the key, returning the <function>user_data</function> pointer.
</para>
<para>
The <function>set_user_data()</function> methods also support an
optional <function>destroy</function> callback. Client programs
can set the <function>destroy</function> callback and receive
notification from HarfBuzz whenever the object is destructed.
</para>
<para>
Finally, each <function>set_user_data()</function> method allows
the client program to set a <literal>replace</literal> Boolean
indicating whether or not the function call should replace any
existing <literal>user_data</literal>
associated with the specified key.
</para>
</section>
<section id="object-model-blobs">
<title>Blobs</title>
<para>
While most of HarfBuzz's object types are specific to the
shaping process, <emphasis>blobs</emphasis> are somewhat
different.
</para>
<para>
Blobs are an abstraction 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>

View File

@ -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, &amp;glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(buf, &amp;glyph_count);
</programlisting>
<para>
The glyph information array holds a <type>hb_glyph_info_t</type>
for each output glyph, which has two fields:
<parameter>codepoint</parameter> and
<parameter>cluster</parameter>. Whereas, in the input buffer,
the <parameter>codepoint</parameter> field contained the Unicode
code point, it now contains the glyph ID of the corresponding
glyph in the font. The <parameter>cluster</parameter> field is
an integer that you can use to help identify when shaping has
reordered, split, or combined code points; we will say more
about that in the next chapter.
</para>
<para>
The glyph positions array holds a corresponding
<type>hb_glyph_position_t</type> for each output glyph,
containing four fields: <parameter>x_advance</parameter>,
<parameter>y_advance</parameter>,
<parameter>x_offset</parameter>, and
<parameter>y_offset</parameter>. The advances tell you how far
you need to move the drawing point after drawing this glyph,
depending on whether you are setting horizontal text (in which
case you will have x advances) or vertical text (for which you
will have y advances). The x and y offsets tell you where to
move to start drawing the glyph; usually you will have both and
x and a y offset, regardless of the text direction.
</para>
<para>
Most of the time, you will rely on a font-rendering library or
other graphics library to do the actual drawing of glyphs, so
you will need to iterate through the glyphs in the buffer and
pass the corresponding values off.
</para>
</section>
<section id="shaping-opentype-features">
<title>OpenType features</title>
<para>
OpenType features enable fonts to include smart behavior,
implemented as "lookup" rules stored in the GSUB and GPOS
tables. The OpenType specification defines a long list of
standard features that fonts can use for these behaviors; each
feature has a four-character reserved name and a well-defined
semantic meaning.
</para>
<para>
Some OpenType features are defined for the purpose of supporting
complex-script shaping, and are automatically activated, but
only when a buffer's script property is set to a script that the
feature supports.
</para>
<para>
Other features are more generic and can apply to several (or
any) script, and shaping engines are expected to implement
them. By default, HarfBuzz activates several of these features
on every text run. They include <literal>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>

View File

@ -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&mdash;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>

View File

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

View File

@ -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 &quot;a&quot; as glyph ID 1, but
many others do not. In order to retrieve the right glyph
from the font to display &quot;a&quot;, 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 &quot;f, i&quot; letter
sequence to appear in print as the single ligature glyph
&quot;&quot;.
</para>
<para>
Whether you should render an &quot;f, i&quot; sequence
as <literal>fi</literal> or as &quot;&quot; does not
depend on the input text. Instead, it depends on the whether
or not the font includes an &quot;&quot; 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 &quot;&quot; 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 &quot;TTA&quot; (ட)
letter is followed by the vowel sign &quot;U&quot; (ு), the pair
must be replaced by the single glyph &quot;டு&quot;. The
sequence of Unicode characters &quot;ட,ு&quot; needs to be
substituted with a single &quot;டு&quot; glyph from the
font.
</para>
<para>
But &quot;டு&quot; 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
&quot;zhe&quot; (ж) with a breve accent, like so: &quot;ӂ&quot;.
</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 &quot;ж&quot; and &quot;˘&quot;
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&mdash;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>
(&quot;bidi&quot; 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 &quot;a
<emphasis>huge</emphasis> breakfast&quot;, and you expect
&quot;huge&quot; 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&mdash;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&mdash;&quot;HarfBuzz&quot; is
the Persian for &quot;open type&quot;.
</para>
</section>
</chapter>

View File

@ -1 +0,0 @@
@HB_VERSION@

400
git.mk
View File

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

Binary file not shown.

View File

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

@ -0,0 +1,4 @@
version_control: github
src_repo: harfbuzz/harfbuzz
tag_prefix: "^"
seperator: "."

476
huawei_harfbuzz.patch Normal file
View 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 &not_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
View 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())

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,923 +0,0 @@
شازده کوچولو
اثر آنتوان دو سن‌تگزوپه‌ری
برگردان احمد شاملو
اهدانام‌چه
به لئون ورث Leon Werth
از بچه‌ها عذر می‌خواهم که این کتاب را به یکی از بزرگ‌ترها هدیه کرده‌ام. برای این کار یک دلیل حسابی دارم: این «بزرگ‌تر» به‌ترین دوست من تو همه دنیا است. یک دلیل دیگرم هم آن که این «بزرگ‌تر» همه چیز را می‌تواند بفهمد حتا کتاب‌هایی را که برای بچه‌ها نوشته باشند. عذر سومم این است که این «بزرگ‌تر» تو فرانسه زندگی می‌کند و آن‌جا گشنگی و تشنگی می‌کشد و سخت محتاج دلجویی است. اگر همه‌ی این عذرها کافی نباشد اجازه می‌خواهم این کتاب را تقدیم آن بچه‌ای کنم که این آدم‌بزرگ یک روزی بوده. آخر هر آدم بزرگی هم روزی روزگاری بچه‌ای بوده (گیرم کم‌تر کسی از آن‌ها این را به یاد می‌آورد). پس من هم اهدانام‌چه‌ام را به این شکل تصحیح می‌کنم:
به لئون ورث
موقعی که پسربچه بود
آنتوان دو سن‌تگزوپه‌ری
من هم برگردان فارسی این شعر بزرگ را به دو بچه‌ی دوست‌داشتنی دیگر تقدیم می‌کنم: دکتر جهانگیر کازرونی و دکتر محمدجواد گلبن
احمد شاملو
۱
یک بار شش سالم که بود تو کتابی به اسم قصه‌های واقعی -که درباره‌ی جنگل بِکر نوشته شده بود- تصویر محشری دیدم از یک مار بوآ که داشت حیوانی را می‌بلعید. آن تصویر یک چنین چیزی بود:
یک مار بوآ که دارد حیوانی را می‌بلعد
تو کتاب آمده بود که: «مارهای بوآ شکارشان را همین جور درسته قورت می‌دهند. بی این که بجوندش. بعد دیگر نمی‌توانند از جا بجنبند و تمام شش ماهی را که هضمش طول می‌کشد می‌گیرند می‌خوابند».
این را که خواندم، راجع به چیزهایی که تو جنگل اتفاق می‌افتد کلی فکر کردم و دست آخر توانستم با یک مداد رنگی اولین نقاشیم را از کار درآرم. یعنی نقاشی شماره‌ی یکم را که این جوری بود:
نقاشی شماره‌ی یکم — مار شبیه به کلاه
شاهکارم را نشان بزرگ‌تر ها دادم و پرسیدم از دیدنش ترس‌تان بر می‌دارد؟
جوابم دادند: -چرا کلاه باید آدم را بترساند؟
نقاشی من کلاه نبود، یک مار بوآ بود که داشت یک فیل را هضم می‌کرد. آن وقت برای فهم بزرگ‌ترها برداشتم توی شکم بوآ را کشیدم. آخر همیشه باید به آن‌ها توضیحات داد. نقاشی دومم این جوری بود:
نقاشی دوم — مار و فیل درونش
بزرگ‌ترها بم گفتند کشیدن مار بوآی باز یا بسته را بگذارم کنار و عوضش حواسم را بیش‌تر جمع جغرافی و تاریخ و حساب و دستور زبان کنم. و این جوری شد که تو شش سالگی دور کار ظریف نقاشی را قلم گرفتم. از این که نقاشی شماره‌ی یک و نقاشی شماره‌ی دو ام یخ‌شان نگرفت دلسرد شده بودم. بزرگ‌ترها اگر به خودشان باشد هیچ وقت نمی‌توانند از چیزی سر درآرند. برای بچه‌ها هم خسته کننده است که همین جور مدام هر چیزی را به آن‌ها توضیح بدهند.
ناچار شدم برای خودم کار دیگری پیدا کنم و این بود که رفتم خلبانی یاد گرفتم. بگویی نگویی تا حالا به همه جای دنیا پرواز کرده ام و راستی راستی جغرافی خیلی بم خدمت کرده. می‌توانم به یک نظر چین و آریزونا را از هم تمیز بدهم. اگر آدم تو دل شب سرگردان شده باشد جغرافی خیلی به دادش می‌رسد.
از این راه است که من تو زندگیم با گروه گروه آدم‌های حسابی برخورد داشته‌ام. پیش خیلی از بزرگ‌ترها زندگی کرده‌ام و آن‌ها را از خیلی نزدیک دیده‌ام گیرم این موضوع باعث نشده در باره‌ی آن‌ها عقیده‌ی بهتری پیدا کنم.
هر وقت یکی‌شان را گیر آورده‌ام که یک خرده روشن بین به نظرم آمده با نقاشی شماره‌ی یکم که هنوز هم دارمش محکش زده‌ام ببینم راستی راستی چیزی بارش هست یا نه. اما او هم طبق معمول در جوابم در آمده که: «این یک کلاه است». آن وقت دیگر من هم نه از مارهای بوآ باش اختلاط کرده‌ام نه از جنگل‌های بکر دست نخورده نه از ستاره‌ها. خودم را تا حد او آورده‌ام پایین و باش از بریج و گلف و سیاست و انواع کرات حرف زده‌ام. او هم از این که با یک چنین شخص معقولی آشنایی به هم رسانده سخت خوش‌وقت شده.
۲
این جوری بود که روزگارم تو تنهایی می‌گذشت بی این که راستی راستی یکی را داشته باشم که باش دو کلمه حرف بزنم، تااین که زد و شش سال پیش در کویر صحرا حادثه‌یی برایم اتفاق افتاد؛ یک چیز موتور هواپیمایم شکسته بود و چون نه تعمیرکاری همراهم بود نه مسافری یکه و تنها دست به کار شدم تا از پس چنان تعمیر مشکلی برآیم. مساله‌ی مرگ و زندگی بود. آبی که داشتم زورکی هشت روز را کفاف می‌داد.
شب اول را هزار میل دورتر از هر آبادی مسکونی رو ماسه‌ها به روز آوردم پرت افتاده‌تر از هر کشتی شکسته‌یی که وسط اقیانوس به تخته پاره‌یی چسبیده باشد. پس لابد می‌توانید حدس بزنید چه جور هاج و واج ماندم وقتی کله‌ی آفتاب به شنیدن صدای ظریف عجیبی که گفت: «بی زحمت یک برّه برام بکش!» از خواب پریدم.
-ها؟
-یک برّه برام بکش...
چنان از جا جستم که انگار صاعقه بم زده. خوب که چشم‌هام را مالیدم و نگاه کردم آدم کوچولوی بسیار عجیبی را دیدم که با وقار تمام تو نخ من بود. این به‌ترین شکلی است که بعد ها توانستم از او در آرم، گیرم البته آن‌چه من کشیده‌ام کجا و خود او کجا! تقصیر من چیست؟ بزرگ‌تر ها تو شش سالگی از نقاشی دل‌سردم کردند و جز بوآی باز و بسته یاد نگرفتم چیزی بکشم.
با چشم‌هایی که از تعجب گرد شده بود به این حضور ناگهانی خیره شدم. یادتان نرود که من از نزدیک‌ترین آبادی مسکونی هزار میل فاصله داشتم و این آدمی‌زاد کوچولوی من هم اصلا به نظر نمی‌آمد که راه گم کرده باشد یا از خستگی دم مرگ باشد یا از گشنگی دم مرگ باشد یا از تشنگی دم مرگ باشد یا از وحشت دم مرگ باشد. هیچ چیزش به بچه‌یی نمی‌بُرد که هزار میل دور از هر آبادی مسکونی تو دل صحرا گم شده باشد.
این بهترین شکلی است که بعدها از او در آوردم.
وقتی بالاخره صدام در آمد، گفتم:
-آخه... تو این جا چه می‌کنی؟
و آن وقت او خیلی آرام، مثل یک چیز خیلی جدی، دوباره در آمد که:
-بی زحمت واسه‌ی من یک برّه بکش.
آدم وقتی تحت تاثیر شدید رازی قرار گرفت جرات نافرمانی نمی‌کند. گرچه تو آن نقطه‌ی هزار میل دورتر از هر آبادی مسکونی و با قرار داشتن در معرض خطر مرگ این نکته در نظرم بی معنی جلوه کرد باز کاغذ و خودنویسی از جیبم در آوردم اما تازه یادم آمد که آن‌چه من یاد گرفته‌ام بیش‌تر جغرافیا و تاریخ و حساب و دستور زبان است، و با کج خلقی مختصری به آن موجود کوچولو گفتم نقاشی بلد نیستم.
بم جواب داد: -عیب ندارد، یک بَرّه برام بکش.
از آن‌جایی که هیچ وقت تو عمرم بَرّه نکشیده بودم یکی از آن دو تا نقاشی‌ای را که بلد بودم برایش کشیدم. آن بوآی بسته را. ولی چه یکه‌ای خوردم وقتی آن موجود کوچولو در آمد که: -نه! نه! فیلِ تو شکم یک بوآ نمی‌خواهم. بوآ خیلی خطرناک است فیل جا تنگ کن. خانه‌ی من خیلی کوچولوست، من یک بره لازم دارم. برام یک بره بکش.بره‌ی مریض
-خب، کشیدم.
با دقت نگاهش کرد و گفت:
-نه! این که همین حالاش هم حسابی مریض است. یکی دیگر بکش.قوچ
-کشیدم.
لبخند با نمکی زد و در نهایت گذشت گفت:
-خودت که می‌بینی... این بره نیست، قوچ است. شاخ دارد نه...بره‌ی پیر
باز نقاشی را عوض کردم.
آن را هم مثل قبلی ها رد کرد:
-این یکی خیلی پیر است... من یک بره می‌خواهم که مدت ها عمر کند...
باری چون عجله داشتم که موتورم را پیاده کنم رو بی حوصلگی جعبه‌ای کشیدم که دیواره‌اش سه تا سوراخ داشت، و از دهنم پرید که:جعبه
-این یک جعبه است. بره‌ای که می‌خواهی این تو است.
و چه قدر تعجب کردم از این که دیدم داور کوچولوی من قیافه‌اش از هم باز شد و گفت:
-آها... این درست همان چیزی است که می‌خواستم! فکر می‌کنی این بره خیلی علف بخواهد؟
-چطور مگر؟
-آخر جای من خیلی تنگ است...
-هر چه باشد حتماً بسش است. بره‌یی که بت داده‌ام خیلی کوچولوست.
-آن قدرهاهم کوچولو نیست... اِه! گرفته خوابیده...
و این جوری بود که من با شهریار کوچولو آشنا شدم.
۳
خیلی طول کشید تا توانستم بفهمم از کجا آمده. شهریار کوچولو که مدام مرا سوال پیچ می‌کرد خودش انگار هیچ وقت سوال‌های مرا نمی‌شنید. فقط چیزهایی که جسته گریخته از دهنش می‌پرید کم کم همه چیز را به من آشکار کرد. مثلا اول بار که هواپیمای مرا دید (راستی من هواپیما نقاشی نمی‌کنم، سختم است.) ازم پرسید:
-این چیز چیه؟
-این «چیز» نیست: این پرواز می‌کند. هواپیماست. هواپیمای من است.
و از این که به‌اش می‌فهماندم من کسی‌ام که پرواز می‌کنم به خود می‌بالیدم.
حیرت زده گفت: -چی؟ تو از آسمان افتاده‌ای؟
با فروتنی گفتم: -آره.
گفت: -اوه، این دیگر خیلی عجیب است!
و چنان قهقهه‌ی ملوسی سر داد که مرا حسابی از جا در برد. راستش من دلم می‌خواهد دیگران گرفتاری‌هایم را جدی بگیرند.
خنده‌هایش را که کرد گفت: -خب، پس تو هم از آسمان می‌آیی! اهل کدام سیاره‌ای؟...
بفهمی نفهمی نور مبهمی به معمای حضورش تابید. یکهو پرسیدم:
-پس تو از یک سیاره‌ی دیگر آمده‌ای؟
آرام سرش را تکان داد بی این که چشم از هواپیما بردارد.
اما جوابم را نداد، تو نخ هواپیما رفته بود و آرام آرام سر تکان می‌داد.
گفت: -هر چه باشد با این نباید از جای خیلی دوری آمده باشی...
مدت درازی تو خیال فرو رفت، بعد بره‌اش را از جیب در آورد و محو تماشای آن گنج گرانبها شد.تصویری از شهریار کوچولو بر روی زمین
فکر می‌کنید از این نیمچه اعتراف «سیاره‌ی دیگر»ِ او چه هیجانی به من دست داد؟ زیر پاش نشستم که حرف بیشتری از زبانش بکشم:
-تو از کجا می‌آیی آقا کوچولوی من؟ خانه‌ات کجاست؟ بره‌ی مرا می‌خواهی کجا ببری؟
مدتی در سکوت به فکر فرورفت و بعد در جوابم گفت:
-حسن جعبه‌ای که بم داده‌ای این است که شب‌ها می‌تواند خانه‌اش بشود.
-معلوم است... اما اگر بچه‌ی خوبی باشی یک ریسمان هم بِت می‌دهم که روزها ببندیش. یک ریسمان با یک میخ طویله...
انگار از پیش‌نهادم جا خورد، چون که گفت:
-ببندمش؟ چه فکر ها!
-آخر اگر نبندیش راه می‌افتد می‌رود گم می‌شود.
دوست کوچولوی من دوباره غش غش خنده را سر داد:
-مگر کجا می‌تواند برود؟
-خدا می‌داند. راستِ شکمش را می‌گیرد و می‌رود...
-بگذار برود...اوه، خانه‌ی من آن‌قدر کوچک است!
و شاید با یک خرده اندوه در آمد که:
-یک‌راست هم که بگیرد برود جای دوری نمی‌رود...
۴
به این ترتیب از یک موضوع خیلی مهم دیگر هم سر در آوردم: این که سیاره‌ی او کمی از یک خانه‌ی معمولی بزرگ‌تر بود.این نکته آن‌قدرها به حیرتم نینداخت. می‌دانستم گذشته از سیاره‌های بزرگی مثل زمین و کیوان و تیر و ناهید که هرکدام برای خودشان اسمی دارند، صدها سیاره‌ی دیگر هم هست که بعضی‌شان از بس کوچکند با دوربین نجومی هم به هزار زحمت دیده می‌شوند و هرگاه اخترشناسی یکی‌شان را کشف کند به جای اسم شماره‌ای به‌اش می‌دهد. مثلا اسمش را می‌گذارد «اخترک ۳۲۵۱».
دلایل قاطعی دارم که ثابت می‌کند شهریار کوچولو از اخترک ب۶۱۲ آمده‌بود.
شهریار کوچولو بر اخترکِ ب۶۱۲
این اخترک را فقط یک بار به سال ۱۹۰۹ یک اخترشناس ترک توانسته بود ببیند اخترشناسِ ترک در حالِ دیدنِ اخترکِ ب۶۱۲که تو یک کنگره‌ی بین‌المللی نجوم هم با کشفش هیاهوی زیادی به راه انداخت اما واسه خاطر لباسی که تنش بود هیچ کس حرفش را باور نکرد. اخترشناسِ ترک در کنگره‌ی بین‌المللیِ نجوم، با لباس قدیمیآدم بزرگ‌ها این جوری‌اند!
بختِ اخترک ب۶۱۲ زد و، ترک مستبدی ملتش را به ضرب دگنک وادار به پوشیدن لباس اروپایی‌ها کرد. اخترشناس به سال ۱۹۲۰ دوباره، و این بار با سر و وضع آراسته برای کشفش ارائه‌ی دلیل کرد و این بار همه جانب او را گرفتند.اخترشناسِ ترک در کنگره‌ی بین‌المللیِ نجوم، با لباس جدید
به خاطر آدم بزرگ‌هاست که من این جزئیات را در باب اخترکِ ب۶۱۲ برای‌تان نقل می‌کنم یا شماره‌اش را می‌گویم چون که آن‌ها عاشق عدد و رقم‌اند. وقتی با آن‌ها از یک دوست تازه‌تان حرف بزنید هیچ وقت ازتان درباره‌ی چیزهای اساسی‌اش سوال نمی‌کنند که هیج وقت نمی‌پرسند «آهنگ صداش چه‌طور است؟ چه بازی‌هایی را بیشتر دوست دارد؟ پروانه جمع می‌کند یا نه؟» -می‌پرسند: «چند سالش است؟ چند تا برادر دارد؟ وزنش چه‌قدر است؟ پدرش چه‌قدر حقوق می‌گیرد؟» و تازه بعد از این سوال‌ها است که خیال می‌کنند طرف را شناخته‌اند.
اگر به آدم بزرگ‌ها بگویید یک خانه‌ی قشنگ دیدم از آجر قرمز که جلو پنجره‌هاش غرقِ شمعدانی و بامش پر از کبوتر بود محال است بتوانند مجسمش کنند. باید حتماً به‌شان گفت یک خانه‌ی صد میلیون تومنی دیدم تا صداشان بلند بشود که: -وای چه قشنگ!
یا مثلا اگر به‌شان بگویید «دلیل وجودِ شهریارِ کوچولو این که تودل‌برو بود و می‌خندید و دلش یک بره می‌خواست و بره خواستن، خودش بهترین دلیل وجود داشتن هر کسی است» شانه بالا می‌اندازند و باتان مثل بچ‌ه‌ها رفتار می‌کنند! اما اگر به‌شان بگویید «سیاره‌ای که ازش آمده‌بود اخترک ب۶۱۲ است» بی‌معطلی قبول می‌کنند و دیگر هزار جور چیز ازتان نمی‌پرسند. این جوری‌اند دیگر. نباید ازشان دل‌خور شد. بچه‌ها باید نسبت به آدم بزرگ‌ها گذشت داشته باشند.
اما البته ماها که مفهوم حقیقی زندگی را درک می‌کنیم می‌خندیم به ریش هرچه عدد و رقم است! چیزی که من دلم می‌خواست این بود که این ماجرا را مثل قصه‌ی پریا نقل کنم. دلم می‌خواست بگویم: «یکی بود یکی نبود. روزی روزگاری یه شهریار کوچولو بود که تو اخترکی زندگی می‌کرد همه‌اش یه خورده از خودش بزرگ‌تر و واسه خودش پیِ دوستِ هم‌زبونی می‌گشت...»، آن هایی که مفهوم حقیقی زندگی را درک کرده‌اند واقعیت قضیه را با این لحن بیشتر حس می‌کنند. آخر من دوست ندارم کسی کتابم را سرسری بخواند. خدا می‌داند با نقل این خاطرات چه بار غمی روی دلم می‌نشیند. شش سالی می‌شود که دوستم با بَرّه‌اش رفته. این که این جا می‌کوشم او را وصف کنم برای آن است که از خاطرم نرود. فراموش کردن یک دوست خیلی غم‌انگیز است. همه کس که دوستی ندارد. من هم می‌توانم مثل آدم بزرگ‌ها بشوم که فقط اعداد و ارقام چشم‌شان را می‌گیرد. و باز به همین دلیل است که رفته‌ام یک جعبه رنگ و چند تا مداد خریده‌ام. تو سن و سال من واسه کسی که جز کشیدنِ یک بوآی باز یا یک بوآی بسته هیچ کار دیگری نکرده -و تازه آن هم در شش سالگی- دوباره به نقاشی رو کردن از آن حرف‌هاست! البته تا آن‌جا که بتوانم سعی می‌کنم چیزهایی که می‌کشم تا حد ممکن شبیه باشد. گیرم به موفقیت خودم اطمینان چندانی ندارم. یکیش شبیه از آب در می‌آید یکیش نه. سرِ قدّ و قواره‌اش هم حرف است. یک جا زیادی بلند درش آورده‌ام یک جا زیادی کوتاه. از رنگ لباسش هم مطمئن نیستم. خب، رو حدس و گمان پیش رفته‌ام؛ کاچی به زِ هیچی. و دست آخر گفته باشم که تو بعضِ جزئیات مهم‌ترش هم دچار اشتباه شده‌ام. اما در این مورد دیگر باید ببخشید: دوستم زیر بار هیچ جور شرح و توصیفی نمی‌رفت. شاید مرا هم مثل خودش می‌پنداشت. اما از بختِ بد، دیدن بره‌ها از پشتِ جعبه از من بر نمی‌آید. نکند من هم یک خرده به آدم بزرگ‌ها رفته‌ام؟ «باید پیر شده باشم».
۵
هر روزی که می‌گذشت از اخترک و از فکرِ عزیمت و از سفر و این حرف‌ها چیزهای تازه‌ای دست‌گیرم می‌شد که همه‌اش معلولِ بازتاب‌هایِ اتفاقی بود. و از همین راه بود که روز سوم از ماجرایِ تلخِ بائوباب ها سردرآوردم.
این بار هم بَرّه باعثش شد، چون شهریار کوچولو که انگار سخت دودل مانده‌بود ناگهان ازم پرسید:
-بَرّه‌ها بته‌ها را هم می‌خورند دیگر، مگر نه؟
-آره. همین جور است.
-آخ! چه خوشحال شدم!
نتوانستم بفهمم این موضوع که بَرّه‌ها بوته‌ها را هم می‌خورند اهمیتش کجاست اما شهریار کوچولو درآمد که:
-پس لابد بائوباب ها را هم می‌خورند دیگر؟
یک گله فیل که در اخترکِ ب۶۱۲ روی هم چیده شده‌اندمن برایش توضیح دادم که بائوباب بُتّه نیست. درخت است و از ساختمان یک معبد هم گنده‌تر، و اگر یک گَلّه فیل هم با خودش ببرد حتا یک درخت بائوباب را هم نمی‌توانند بخورند.
از فکر یک گَلّه فیل به خنده افتاد و گفت: -باید چیدشان روی هم.
اما با فرزانگی تمام متذکر شد که: -بائوباب هم از بُتِّگی شروع می‌کند به بزرگ شدن.
-درست است. اما نگفتی چرا دلت می‌خواهد بره‌هایت نهال‌های بائوباب را بخورند؟
گفت: -دِ! معلوم است!
و این را چنان گفت که انگار موضوع از آفتاب هم روشن‌تر است؛ منتها من برای این که به تنهایی از این راز سر در آرم ناچار شدم حسابی کَلّه را به کار بیندازم.
راستش این که تو اخترکِ شهریار کوچولو هم مثل سیارات دیگر هم گیاهِ خوب به هم می‌رسید هم گیاهِ بد. یعنی هم تخمِ خوب گیاه‌های خوب به هم می‌رسید، هم تخمِ بدِ گیاه‌هایِ بد. اما تخم گیاه‌ها نامریی‌اند. آن‌ها تو حرمِ تاریک خاک به خواب می‌روند تا یکی‌شان هوس بیدار شدن به سرش بزند. آن وقت کش و قوسی می‌آید و اول با کم رویی شاخکِ باریکِ خوشگل و بی‌آزاری به طرف خورشید می‌دواند. اگر این شاخک شاخکِ تربچه‌ای گلِ سرخی چیزی باشد می‌شود گذاشت برای خودش رشد کند اما اگر گیاهِ بدی باشد آدم باید به مجردی که دستش را خواند ریشه‌کنش کند.
باری، تو سیاره‌ی شهریار کوچولو گیاه تخمه‌های وحشتناکی به هم می‌رسید. یعنی تخم درختِ بائوباب که خاکِ سیاره حسابی ازشان لطمه خورده بود. بائوباب هم اگر دیر به‌اش برسند دیگر هیچ جور نمی‌شود حریفش شد: تمام سیاره را می‌گیرد و با ریشه‌هایش سوراخ سوراخش می‌کند و اگر سیاره خیلی کوچولو باشد و بائوباب‌ها خیلی زیاد باشند پاک از هم متلاشیش می‌کنند.
شهریار کوچولو در حال نظافت ِ اخترکششهریار کوچولو بعدها یک روز به من گفت: «این، یک امر انضباطی است. صبح به صبح بعد از نظافتِ خود باید با دفت تمام به نظافتِ اخترک پرداخت. آدم باید خودش را مجبور کند که به مجردِ تشخیص دادن بائوباب‌ها از بته‌های گلِ سرخ که تا کوچولواَند عین هم‌اَند با دقت ریشه‌کن‌شان بکند. کار کسل‌کننده‌ای هست اما هیچ مشکل نیست.»
یک روز هم بم توصیه کرد سعی کنم هر جور شده یک نقاشی حسابی از کار درآرم که بتواند قضیه را به بچه‌های سیاره‌ی من هم حالی کند. گفت اگر یک روز بروند سفر ممکن است به دردشان بخورد. پاره‌ای وقت‌ها پشت گوش انداختن کار ایرادی ندارد اما اگر پای بائوباب در میان باشد گاوِ آدم می‌زاید. اخترکی را سراغ دارم که یک تنبل‌باشی ساکنش بود و برای کندن سه تا نهال بائوباب امروز و فردا کرد...».
آن وقت من با استفاده از چیزهایی که گفت شکل آن اخترک را کشیدم.
اخترکِ تنبل‌باشی با سه درختِ بائوباب
هیچ دوست ندارم اندرزگویی کنم. اما خطر بائوباب‌ها آن‌قدر کم شناخته شده و سر راهِ کسی که تو چنان اخترکی سرگیدان بشود آن قدر خطر به کمین نشسته که این مرتبه را از رویه‌ی همیشگی خودم دست بر می‌دارم و می‌گویم: «بچه‌ها! هوای بائوباب‌ها را داشته باشید!»
اگر من سرِ این نقاشی این همه به خودم فشار آورده‌ام فقط برای آن بوده که دوستانم را متوجه خطری کنم که از مدت‌ها پیش بیخ گوش‌شان بوده و مثلِ خودِ من ازش غافل بوده‌اند. درسی که با این نقاشی داده‌ام به زحمتش می‌ارزد. حالا ممکن است شما از خودتان بپرسید: «پس چرا هیچ کدام از بقیه‌ی نقاشی‌های این کتاب هیبتِ تصویرِ بائوباب‌ها را ندارد؟» -خب، جوابش خیلی ساده است: من زور خودم را زده‌ام اما نتوانسته‌ام از کار درشان بیاورم. اما عکس بائوباب‌ها را که می‌کشیدم احساس می‌کردم قضیه خیلی فوریت دارد و به این دلیل شور بَرَم داشته بود.
۶
آخ، شهریار کوچولو! این جوری بود که من کَم کَمَک از زندگیِ محدود و دل‌گیر تو سر درآوردم. تا مدت‌ها تنها سرگرمیِ تو تماشای زیباییِ غروب آفتاب بوده. به این نکته‌ی تازه صبح روز چهارم بود که پی بردم؛ یعنی وقتی که به من گفتی:
-غروب آفتاب را خیلی دوست دارم. برویم فرورفتن آفتاب را تماشا کنیم...شهریار کوچولو در اخترکش مشغولِ تماشای غروبِ آفتاب
-هوم، حالاها باید صبر کنی...
-واسه چی صبر کنم؟
-صبر کنی که آفتاب غروب کند.
اول سخت حیرت کردی بعد از خودت خنده‌ات گرفت و برگشتی به من گفتی:
-همه‌اش خیال می‌کنم تو اخترکِ خودمم!
-راستش موقعی که تو آمریکا ظهر باشد همه می‌دانند تو فرانسه تازه آفتاب دارد غروب می‌کند. کافی است آدم بتواند در یک دقیقه خودش را برساند به فرانسه تا بتواند غروب آفتاب را تماشا کند. متاسفانه فرانسه کجا این‌جا کجا! اما رو اخترک تو که به آن کوچکی است همین‌قدر که چند قدمی صندلیت را جلو بکشی می‌توانی هرقدر دلت خواست غروب تماشا کنی.
-یک روز چهل و سه بار غروب آفتاب را تماشا کردم!
و کمی بعد گفت:
-خودت که می‌دانی... وقتی آدم خیلی دلش گرفته باشد از تماشای غروب لذت می‌برد.
-پس خدا می‌داند آن روز چهل و سه غروبه چه‌قدر دلت گرفته بوده.
اما مسافر کوچولو جوابم را نداد.
۷
روز پنجم باز سرِ گوسفند از یک راز دیگر زندگی شهریار کوچولو سر در آوردم. مثل چیزی که مدت‌ه‌ا تو دلش به‌اش فکر کرده باشد یک‌هو بی مقدمه از من پرسید:
-گوسفندی که بُتّه ها را بخورد گل ها را هم می‌خورد؟
-گوسفند هرچه گیرش بیاید می‌خورد.
-حتا گل‌هایی را هم که خار دارند؟
-آره، حتا گل‌هایی را هم که خار دارند.
-پس خارها فایده‌شان چیست؟
من چه می‌دانستم؟ یکی از آن: سخت گرفتار باز کردن یک مهره‌ی سفتِ موتور بودم. از این که یواش یواش بو می‌بردم خرابیِ کار به آن سادگی‌ها هم که خیال می‌کردم نیست برج زهرمار شده‌بودم و ذخیره‌ی آبم هم که داشت ته می‌کشید بیش‌تر به وحشتم می‌انداخت.
-پس خارها فایده‌شان چسیت؟
شهریار کوچولو وقتی سوالی را می‌کشید وسط دیگر به این مفتی‌ها دست بر نمی‌داشت. مهره پاک کلافه‌ام کرده بود. همین جور سرسری پراندم که:
-خارها به درد هیچ کوفتی نمی‌خورند. آن‌ها فقط نشانه‌ی بدجنسی گل‌ها هستند.
-دِ!
و پس از لحظه‌یی سکوت با یک جور کینه درآمد که:
-حرفت را باور نمی‌کنم! گل‌ها ضعیفند. بی شیله‌پیله‌اند. سعی می‌کنند یک جوری تهِ دل خودشان را قرص کنند. این است که خیال می‌کنند با آن خارها چیزِ ترسناکِ وحشت‌آوری می‌شوند...
لام تا کام به‌اش جواب ندادم. در آن لحظه داشتم تو دلم می‌گفتم: «اگر این مهره‌ی لعنتی همین جور بخواهد لج کند با یک ضربه‌ی چکش حسابش را می‌رسم.» اما شهریار کوچولو دوباره افکارم را به هم ریخت:
-تو فکر می‌کنی گل‌ها...
من باز همان جور بی‌توجه گفتم:
-ای داد بیداد! ای داد بیداد! نه، من هیچ کوفتی فکر نمی‌کنم! آخر من گرفتار هزار مساله‌ی مهم‌تر از آنم!
هاج و واج نگاهم کرد و گفت:
-مساله‌ی مهم!
مرا می‌دید که چکش به دست با دست و بالِ سیاه روی چیزی که خیلی هم به نظرش زشت می‌آمد خم شده‌ام.
-مثل آدم بزرگ‌ها حرف می‌زنی!
از شنیدنِ این حرف خجل شدم اما او همین جور بی‌رحمانه می‌گفت:
-تو همه چیز را به هم می‌ریزی... همه چیز را قاتی می‌کنی!
حسابی از کوره در رفته‌بود.
موهای طلایی طلائیش تو باد می‌جنبید.
-اخترکی را سراغ دارم که یک آقا سرخ روئه توش زندگی می‌کند. او هیچ وقت یک گل را بو نکرده، هیچ وقت یک ستاره‌را تماشا نکرده هیچ وقت کسی را دوست نداشته هیچ وقت جز جمع زدن عددها کاری نکرده. او هم مثل تو صبح تا شب کارش همین است که بگوید: «من یک آدم مهمم! یک آدم مهمم!» این را بگوید و از غرور به خودش باد کند. اما خیال کرده: او آدم نیست، یک قارچ است!
-یک چی؟
-یک قارچ!گلِ سرخ
حالا دیگر رنگش از فرط خشم مثل گچ سفید شده‌بود:
-کرورها سال است که گل‌ها خار می‌سازند و با وجود این کرورها سال است که برّه‌ها گل‌ها را می‌خورند. آن وقت هیچ مهم نیست آدم بداند پس چرا گل‌ها واسه ساختنِ خارهایی که هیچ وقتِ خدا به هیچ دردی نمی‌خورند این قدر به خودشان زحمت می‌دهند؟ جنگ میان برّه‌ها و گل‌ها هیچ مهم نیست؟ این موضوع از آن جمع زدن‌های آقا سرخ‌روئه‌یِ شکم‌گنده مهم‌تر و جدی‌تر نیست؟ اگر من گلی را بشناسم که تو همه‌ی دنیا تک است و جز رو اخترک خودم هیچ جای دیگر پیدا نمیشه و ممکن است یک روز صبح یک برّه کوچولو، مفت و مسلم، بی این که بفهمد چه‌کار دارد می‌کند به یک ضرب پاک از میان ببردش چی؟ یعنی این هم هیچ اهمیتی ندارد؟ اگر کسی گلی را دوست داشته باشد که تو کرورها و کرورها ستاره فقط یک دانه ازش هست واسه احساس وشبختی همین قدر بس است که نگاهی به آن همه ستاره بیندازد و با خودش بگوید: «گل من یک جایی میان آن ستاره‌هاست»، اما اگر برّه گل را بخورد برایش مثل این است که یکهو تمام آن ستاره‌ها پِتّی کنند و خاموش بشوند. یعنی این هم هیچ اهمیتی ندارد؟
دیگر نتوانست چیزی بگوید و ناگهان هِق هِق کنان زد زیر گریه.
حالا دیگر شب شده‌بود. اسباب و ابزارم را کنار انداخته‌بودم. دیگر چکش و مهره و تشنگی و مرگ به نظرم مضحک می‌آمد. رو ستاره‌ای، رو سیاره‌ای، رو سیاره‌ی من، زمین، شهریارِ کوچولویی بود که احتیاج به دلداری داشت! به آغوشش گرفتم مثل گهواره تابش دادم به‌اش گفتم: «گلی که تو دوست داری تو خطر نیست. خودم واسه گوسفندت یک پوزه‌بند می‌کشم... خودم واسه گفت یک تجیر می‌کشم... خودم...» بیش از این نمی‌دانستم چه بگویم. خودم را سخت چُلمَن و بی دست و پا حس می‌کردم. نمی‌دانستم چه‌طور باید خودم را به‌اش برسانم یا به‌اش بپیوندم...p چه دیار اسرارآمیزی است دیار اشک!
۸
راه شناختن آن گل را خیلی زود پیدا کردم:
تو اخترکِ شهریار کوچولو همیشه یک مشت گل‌های خیلی ساده در می‌آمده. گل‌هایی با یک ردیف گلبرگ که جای چندانی نمی‌گرفته، دست و پاگیرِ کسی نمی‌شده. صبحی سر و کله‌شان میان علف‌ها پیدا می‌شده شب از میان می‌رفته‌اند. اما این یکی یک روز از دانه‌ای جوانه زده بود که خدا می‌دانست از کجا آمده رود و شهریار کوچولو با جان و دل از این شاخکِ نازکی که به هیچ کدام از شاخک‌های دیگر نمی‌رفت مواظبت کرده‌بود. بعید بنود که این هم نوعِ تازه‌ای از بائوباب باشد اما بته خیلی زود از رشد بازماند و دست‌به‌کارِ آوردن گل شد. شهریار کوچولو که موقعِ نیش زدن آن غنچه‌ی بزرگ حاضر و ناظر بود به دلش افتاد که باید چیز معجزه‌آسایی از آن بیرون بیاید. اما گل تو پناهِ خوابگاهِ سبزش سر فرصت دست اندکار خودآرایی بود تا هرچه زیباتر جلوه‌کند. رنگ‌هایش را با وسواس تمام انتخاب می‌کرد سر صبر لباس می‌پوشید و گلبرگ‌ها را یکی یکی به خودش می‌بست. دلش نمی‌خواست مثل شقایق‌ها با جامه‌ی مچاله و پر چروک بیرون بیاید.
شهریار کوچولو و گلِ سرخنمی‌خواست جز در اوج درخشندگی زیبائیش رو نشان بدهد!...
هوه، بله عشوه‌گری تمام عیار بود! آرایشِ پر راز و رمزش روزها و روزها طول کشید تا آن که سرانجام یک روز صبح درست با بر آمدن آفتاب نقاب از چهره برداشت و با این که با آن همه دقت و ظرافت روی آرایش و پیرایش خودش کار کرده بود خمیازه‌کشان گفت:
-اوه، تازه همین حالا از خواب پا شده‌ام... عذر می‌خواهم که موهام این جور آشفته‌است...
شهریار کوچولو نتوانست جلو خودش را بگیرد و از ستایش او خودداری کند:
-وای چه‌قدر زیبائید!
گل به نرمی گفت:
-چرا که نه؟ من و آفتاب تو یک لحظه به دنیا آمدیم...
شهریار کوچولو شستش خبردار شد که طرف آن‌قدرها هم اهل شکسته‌نفسی نیست اما راستی که چه‌قدر هیجان انگیز بود!
-به نظرم وقت خوردن ناشتایی است. بی زحمت برایم فکری بکنید.
و شهریار کوچولوی مشوش و در هم یک آبپاش آب خنک آورده به گل داده‌بود.شهریار کوچولو در حالِ تماشای گلِ سرخ
با این حساب، هنوزهیچی نشده با آن خودپسندیش که بفهمی‌نفهمی از ضعفش آب می‌خورد دل او را شکسته بود. مثلا یک روز که داشت راجع به چهارتا خارش حرف می‌زد یک‌هو در آمده بود که:ببر و گلِ سرخ
-نکند ببرها با آن چنگال‌های تیزشان بیایند سراغم!
شهریار کوچولو ازش ایراد گرفته‌بود که:
-تو اخترک من ببر به هم نمی‌رسد. تازه ببرها که علف‌خوار نیستند.
گل به گلایه جواب داده بود:
-من که علف نیستم.
و شهریار کوچولو گفته بود:
-عذر می‌خواهم...
-من از ببرها هیچ ترسی ندارم اما از جریان هوا وحشت می‌کنم. تو دستگاه‌تان تجیر به هم نمی‌رسد؟شهریار کوچولو در حالِ پوشاندنِ گلِ سرخ
شهریار کوچولو تو دلش گفت: «وحشت از جریان هوا... این که واسه یک گیاه تعریفی ندارد... چه مرموز است این گل!»
-شب مرا بگذارید زیر یک سرپوش. این جا هواش خیلی سرد است. چه جای بدی افتادم! جایی که پیش از این بودم...شهریار کوچولو در حالِ گذاشتنِ سرپوش روی گلِ سرخ
اما حرفش را خورده بود. آخر، آمدنا هنوز به شکل دانه بود. امکان نداشت توانسته‌باشد دنیاهای دیگری را بشناسد. شرم‌سار از این که گذاشته بود سر به هم بافتن دروغی به این آشکاری مچش گیربیفتد دو سه بار سرفه کرده بود تا اهمالِ شهریار کوچولو را به‌اش یادآور شود:
-تجیر کو پس؟
-داشتم می‌رفتم اما شما داشتید صحبت می‌کردید!
و با وجود این زورکی بنا کرده‌بود به سرفه کردن تا او احساس پشیمانی کند.
به این ترتیب شهریار کوچولو با همه‌ی حسن نیّتی که از عشقش آب می‌خورد همان اول کار به او بد گمان شده‌بود. حرف‌های بی سر و تهش را جدی گرفته‌بود و سخت احساس شوربختی می‌کرد.
یک روز دردِدل کنان به من گفت: -حقش بود به حرف‌هاش گوش نمی‌دادم. هیچ وقت نباید به حرف گل‌ها گوش داد. گل را فقط باید بوئید و تماشا کرد. گلِ من تمامِ اخترکم را معطر می‌کرد گیرم من بلد نبودم چه‌جوری از آن لذت ببرم. قضیه‌ی چنگال‌های ببر که آن جور دَمَغم کرده‌بود می‌بایست دلم را نرم کرده باشد...»
یک روز دیگر هم به من گفت: «آن روزها نتوانستم چیزی بفهمم. من بایست روی کرد و کارِ او در باره‌اش قضاوت می‌کردم نه روی گفتارش... عطرآگینم می‌کرد. دلم را روشن می‌کرد. نمی‌بایست ازش بگریزم. می‌بایست به مهر و محبتی که پشتِ آن کلک‌های معصومانه‌اش پنهان بود پی می‌بردم. گل‌ها پُرَند از این جور تضادها. اما خب دیگر، من خام‌تر از آن بودم که راهِ دوست داشتنش را بدانم!».
۹
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرنده‌های وحشی استفاده کرد.
گمان کنم شهریار کوچولو برای فرارش از مهاجرت پرنده‌های وحشی استفاده کرد.
صبح روز حرکت، اخترکش را آن جور که باید مرتب کرد، آتش‌فشان‌های فعالش را با دقت پاک و دوده‌گیری کرد: شهریار کوچولو در حالِ پاک کردنِ آتش‌فشان.دو تا آتش‌فشان فعال داشت که برای گرم کردن ناشتایی خیلی خوب بود. یک آتش‌فشان خاموش هم داشت. منتها به قول خودش «آدم کف دستش را که بو نکرده!» این بود که آتش‌فشان خاموش را هم پاک کرد. آتش‌فشان که پاک باشد مرتب و یک هوا می‌سوزد و یک‌هو گُر نمی‌زند. آتش‌فشان هم عین‌هو بخاری یک‌هو اَلُو می‌زند. البته ما رو سیاره‌مان زمین کوچک‌تر از آن هستیم که آتش‌فشان‌هامان را پاک و دوده‌گیری کنیم و برای همین است که گاهی آن جور اسباب زحمت‌مان می‌شوند.
شهریار کوچولو با دل‌ِگرفته آخرین نهال‌های بائوباب را هم ریشه‌کن کرد. فکر می‌کرد دیگر هیچ وقت نباید برگردد. اما آن روز صبح گرچه از این کارهای معمولیِ هر روزه کُلّی لذت برد موقعی که آخرین آب را پای گل داد و خواست بگذاردش زیرِ سرپوش چیزی نمانده‌بود که اشکش سرازیر شود.
به گل گفت: -خدا نگهدار!
اما او جوابش را نداد.
دوباره گفت: -خدا نگهدار!
گل سرفه‌کرد، گیرم این سرفه اثر چائیدن نبود. بالاخره به زبان آمد و گفت:
-من سبک مغز بودم. ازت عذر می‌خواهم. سعی کن خوشبخت باشی.
از این که به سرکوفت و سرزنش‌های همیشگی برنخورد حیرت کرد و سرپوش به دست هاج‌وواج ماند. از این محبتِ آرام سر در نمی‌آورد.
گل به‌اش گفت: -خب دیگر، دوستت دارم. اگر تو روحت هم از این موضوع خبردار نشد تقصیر من است. باشد، زیاد مهم نیست. اما تو هم مثل من بی‌عقل بودی... سعی کن خوشبخت بشوی... این سرپوش را هم بگذار کنار، دیگر به دردم نمی‌خورد.
-آخر، باد...
-آن قدرهاهم سَرمائو نیستم... هوای خنک شب برای سلامتیم خوب است. خدانکرده گُلم آخر.
-آخر حیوانات...
-اگر خواسته‌باشم با شب‌پره‌ها آشنا بشوم جز این که دو سه تا کرمِ حشره را تحمل کنم چاره‌ای ندارم. شب‌پره باید خیلی قشنگ باشد. جز آن کی به دیدنم می‌آید؟ تو که می‌روی به آن دور دورها. از بابتِ درنده‌ها هم هیچ کَکَم نمی‌گزد: «من هم برای خودم چنگ و پنجه‌ای دارم».
و با سادگی تمام چهارتا خارش را نشان داد. بعد گفت:
-دست‌دست نکن دیگر! این کارت خلق آدم را تنگ می‌کند. حالا که تصمیم گرفته‌ای بروی برو!
و این را گفت، چون که نمی‌خواست شهریار کوچولو گریه‌اش را ببیند. گلی بود تا این حد خودپسند...
۱۰
خودش را در منطقه‌ی اخترک‌های ۳۲۵، ۳۲۶، ۳۲۷، ۳۲۸، ۳۲۹ و ۳۳۰ دید. این بود که هم برای سرگرمی و هم برای چیزیادگرفتن بنا کرد یکی‌یکی‌شان را سیاحت کردن.
اخترکِ اول مسکن پادشاهی بود که با شنلی از مخمل ارغوانی قاقم بر اورنگی بسیار ساده و در عین حال پرشکوه نشسته بود و همین که چشمش به شهریار کوچولو افتاد داد زد:
-خب، این هم رعیت!
شهریار کوچولو از خودش پرسید: -او که تا حالا هیچ وقت مرا ندیده چه جوری می‌تواند بشناسدم؟
دیگر اینش را نخوانده‌بود که دنیابرای پادشاهان به نحو عجیبی ساده شده و تمام مردم فقط یک مشت رعیت به حساب می‌آیند.
پادشاه در سیاره‌اش
پادشاه که می‌دید بالاخره شاهِ کسی شده و از این بابت کبکش خروس می‌خواند گفت: -بیا جلو بهتر ببینیمت. شهریار کوچولو با چشم پیِ جایی گشت که بنشیند اما شنلِ قاقمِ حضرتِ پادشاهی تمام اخترک را دربرگرفته‌بود. ناچار همان طور سر پا ماند و چون سخت خسته بود به دهن‌دره افتاد.
شاه به‌اش گفت: -خمیازه کشیدن در حضرتِ سلطان از نزاکت به دور است. این کار را برایت قدغن می‌کنم. شهریار کوچولو که سخت خجل شده‌بود در آمد که:
-نمی‌توانم جلوِ خودم را بگیرم. راه درازی طی‌کرده‌ام و هیچ هم نخوابیده‌ام...
پادشاه گفت: -خب خب، پس بِت امر می‌کنم خمیازه بکشی. سال‌هاست خمیازه‌کشیدن کسی را ندیده‌ام برایم تازگی دارد. یاالله باز هم خمیازه بکش. این یک امر است.
شهریار کوچولو گفت: -آخر این جوری من دست و پایم را گم می‌کنم... دیگر نمی‌توانم.
شاه گفت: -هوم! هوم! خب، پس من به‌ات امر می‌کنم که گاهی خمیازه بکشی گاهی نه.
تند و نامفهوم حرف می‌زد و انگار خلقش حسابی تنگ بود.
پادشاه فقط دربند این بود که مطیع فرمانش باشند. در مورد نافرمانی‌ها هم هیچ نرمشی از خودش نشان نمی‌داد. یک پادشاهِ تمام عیار بود گیرم چون زیادی خوب بود اوامری که صادر می‌کرد اوامری بود منطقی. مثلا خیلی راحت در آمد که: «اگر من به یکی از سردارانم امر کنم تبدیل به یکی از این مرغ‌های دریایی بشود و یارو اطاعت نکند تقسیر او نیست که، تقصیر خودم است».
شهریار کوچولو در نهایت ادب پرسید: -اجازه می‌فرمایید بنشینم؟
پادشاه که در نهایتِ شکوه و جلال چینی از شنل قاقمش را جمع می‌کرد گفت: -به‌ات امر می‌کنیم بنشینی.
منتها شهریار کوچولو مانده‌بود حیران: آخر آن اخترک کوچک‌تر از آن بود که تصورش را بشود کرد. واقعا این پادشاه به چی سلطنت می‌کرد؟ گفت: -قربان عفو می‌فرمایید که ازتان سوال می‌کنم...
پادشاه با عجله گفت: -به‌ات امر می‌کنیم از ما سوال کنی.
-شما قربان به چی سلطنت می‌فرمایید؟
پادشاه خیلی ساده گفت: -به همه چی.
-به همه‌چی؟
پادشاه با حرکتی قاطع به اخترک خودش و اخترک‌های دیگر و باقی ستاره‌ها اشاره کرد.
شهریار کوچولو پرسید: -یعنی به همه‌ی این ها؟
شاه جواب داد: -به همه‌ی این ها.
آخر او فقط یک پادشاه معمولی نبود که، یک پادشاهِ جهانی بود.
-آن وقت ستاره‌ها هم سربه‌فرمان‌تانند؟
پادشاه گفت: -البته که هستند. همه‌شان بی‌درنگ هر فرمانی را اطاعت می‌کنند. ما نافرمانی را مطلقا تحمل نمی‌کنیم.
یک چنین قدرتی شهریار کوچولو را به شدت متعجب کرد. اگر خودش چنین قدرتی می‌داشت بی این که حتا صندلیش را یک ذره تکان بدهد روزی چهل و چهار بار که هیچ روزی هفتاد بار و حتا صدبار و دویست‌بار غروب آفتاب را تماشا می‌کرد! و چون بفهمی نفهمی از یادآوریِ اخترکش که به امان خدا ول‌کرده‌بود غصه‌اش شد جراتی به خودش داد که از پادشاه درخواست محبتی بکند:
-دلم می‌خواست یک غروب آفتاب تماشا کنم... در حقم التفات بفرمایید امر کنید خورشید غروب کند.
-اگر ما به یک سردار امر کنیم مثل شب‌پره از این گل به آن گل بپرد یا قصه‌ی سوزناکی بنویسد یا به شکل مرغ دریایی در آید و او امریه را اجرا نکند کدام یکی‌مان مقصریم، ما یا او؟
شهریار کوچولو نه گذاشت، نه برداشت، گفت: -شما.
پادشاه گفت: -حرف ندارد. باید از هر کسی چیزی را توقع داشت که ازش ساخته باشد. قدرت باید پیش از هر چیز به عقل متکی باشد. اگر تو به ملتت فرمان بدهی که بروند خودشان را بیندازند تو دریا انقلاب می‌کنند. حق داریم توقع اطاعت داشته باشیم چون اوامرمان عاقلانه است.
شهریار کوچولو که هیچ وقت چیزی را که پرسیده بود فراموش نمی‌کرد گفت: -غروب آفتاب من چی؟
-تو هم به غروب آفتابت می‌رسی. امریه‌اش را صادر می‌کنیم. منتها با شَمِّ حکمرانی‌مان منتظریم زمینه‌اش فراهم بشود.
شهریار کوچولو پرسید: -کِی فراهم می‌شود؟
پادشاه بعد از آن که تقویم کَت و کلفتی را نگاه کرد جواب داد:
-هوم! هوم! حدودِ... حدودِ... غروب. حدودِ ساعت هفت و چهل دقیقه... و آن وقت تو با چشم‌های خودت می‌بینی که چه‌طور فرمان ما اجرا می‌شود!
شهریار کوچولو خمیازه کشید. از این که تماشای آفتاب غروب از کیسه‌اش رفته‌بود تاسف می‌خورد. از آن گذشته دلش هم کمی گرفته‌بود. این بود که به پادشاه گفت:
-من دیگر این‌جا کاری ندارم. می‌خواهم بروم.
شاه که دلش برای داشتن یک رعیت غنج می‌زد گفت:
-نرو! نرو! وزیرت می‌کنیم.
-وزیرِ چی؟
-وزیرِ دادگستری!
-آخر این جا کسی نیست که محاکمه بشود.
پادشاه گفت: -معلوم نیست. ما که هنوز گشتی دور قلمرومان نزده‌ایم. خیلی پیر شده‌ایم، برای کالسکه جا نداریم. پیاده‌روی هم خسته‌مان می‌کند.
شهریار کوچولو که خم شده‌بود تا نگاهی هم به آن طرف اخترک بیندازد گفت: -بَه! من نگاه کرده‌ام، آن طرف هم دیارالبشری نیست.
پادشاه به‌اش جواب داد: -خب، پس خودت را محاکمه کن. این کار مشکل‌تر هم هست. محاکمه کردن خود از محاکمه‌کردن دیگران خیلی مشکل تر است. اگر توانستی در مورد خودت قضاوت درستی بکنی معلوم می‌شود یک فرزانه‌ی تمام عیاری.
شهریار کوچولو گفت: -من هر جا باشم می‌توانم خودم را محاکمه کنم، چه احتیاجی است این جا بمانم؟ پادشاه گفت: -هوم! هوم! فکر می‌کنیم یک جایی تو اخترک ما یک موش پیر هست. صدایش را شب ها می‌شنویم. می‌توانی او را به محاکمه بکشی و گاه‌گاهی هم به اعدام محکومش کنی. در این صورت زندگی او به عدالت تو بستگی پیدا می‌کند. گیرم تو هر دفعه عفوش می‌کنی تا همیشه زیر چاق داشته باشیش. آخر یکی بیش‌تر نیست که.
شهریار کوچولو جواب داد: -من از حکم اعدام خوشم نمی‌آید. فکر می‌کنم دیگر باید بروم.
پادشاه گفت: -نه!
اما شهریار کوچولو که آماده‌ی حرکت شده بود و ضمنا هم هیچ دلش نمی‌خواست اسباب ناراحتی سلطان پیر بشود گفت:
-اگر اعلی‌حضرت مایلند اوامرشان دقیقا اجرا بشود می‌توانند فرمان خردمندانه‌ای در مورد بنده صادر بفرمایند. مثلا می‌توانند به بنده امر کنند ظرف یک دقیقه راه بیفتم. تصور می‌کنم زمینه‌اش هم آماده باشد...
چون پادشاه جوابی نداد شهریار کوچولو اول دو دل ماند اما بعد آهی کشید و به راه افتاد.
آن‌وقت پادشاه با شتاب فریاد زد: -سفیر خودمان فرمودیمت!
حالت بسیار شکوهمندی داشت.
شهریار کوچولو همان طور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند!
۱۱
اخترک دوم مسکن آدم خود پسندی بود.
خود پسند چشمش که به شهریار کوچولو افتاد از همان دور داد زد: -به‌به! این هم یک ستایشگر که دارد می‌آید مرا ببیند!
خودپسند در سیاره‌اش
آخر برای خودپسندها دیگران فقط یک مشت ستایش‌گرند.
شهریار کوچولو گفت: -سلام! چه کلاه عجیب غریبی سرتان گذاشته‌اید!
خود پسند جواب داد: -مال اظهار تشکر است. منظورم موقعی است که هلهله‌ی ستایشگرهایم بلند می‌شود. گیرم متاسفانه تنابنده‌ای گذارش به این طرف‌ها نمی‌افتد.
شهریار کوچولو که چیزی حالیش نشده بود گفت:
-چی؟
خودپسند گفت: -دست‌هایت را بزن به هم دیگر.
شهریار کوچولو دست زد و خودپسند کلاهش را برداشت و متواضعانه از او تشکر کرد.
شهریار کوچولو با خودش گفت: «دیدنِ این تفریحش خیلی بیش‌تر از دیدنِ پادشاه‌است». و دوباره بنا کرد دست‌زدن و خودپسند با برداشتن کلاه بنا کرد تشکر کردن.
پس از پنج دقیقه‌ای شهریار کوچولو که از این بازی یک‌نواخت خسته شده بود پرسید: -چه کار باید کرد که کلاه از سرت بیفتد؟
اما خودپسند حرفش را نشنید. آخر آن‌ها جز ستایش خودشان چیزی را نمی‌شنوند.
از شهریار کوچولو پرسید: -تو راستی راستی به من با چشم ستایش و تحسین نگاه می‌کنی؟
-ستایش و تحسین یعنی چه؟
-یعنی قبول این که من خوش‌قیافه‌ترین و خوش‌پوش‌ترین و ثروت‌مندترین و باهوش‌ترین مرد این اخترکم.
-آخر روی این اخترک که فقط خودتی و کلاهت.
-با وجود این ستایشم کن. این لطف را در حق من بکن.
شهریار کوچولو نیم‌چه شانه‌ای بالا انداخت و گفت: -خب، ستایشت کردم. اما آخر واقعا چیِ این برایت جالب است؟
شهریار کوچولو به راه افتاد و همان طور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند!
۱۲
تو اخترک بعدی می‌خواره‌ای می‌نشست. دیدار کوتاه بود اما شهریار کوچولو را به غم بزرگی فرو برد.
می‌خواره در سیاره‌اش
به می‌خواره که صُم‌بُکم پشت یک مشت بطری خالی و یک مشت بطری پر نشسته بود گفت: -چه کار داری می‌کنی؟
می‌خواره با لحن غم‌زده‌ای جواب داد: -مِی می‌زنم.
شهریار کوچولو پرسید: -مِی می‌زنی که چی؟
می‌خواره جواب داد: -که فراموش کنم.
شهریار کوچولو که حالا دیگر دلش برای او می‌سوخت پرسید: -چی را فراموش کنی؟
می‌خواره همان طور که سرش را می‌انداخت پایین گفت: -سر شکستگیم را.
شهریار کوچولو که دلش می‌خواست دردی از او دوا کند پرسید: -سرشکستگی از چی؟
می‌خواره جواب داد: -سرشکستگیِ می‌خواره بودنم را.
این را گفت و قال را کند و به کلی خاموش شد. و شهریار کوچولو مات و مبهوت راهش را گرفت و رفت و همان جور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی‌راستی چه‌قدر عجیبند!
۱۳
اخترک چهارم اخترک مرد تجارت‌پیشه بود. این بابا چنان مشغول و گرفتار بود که با ورود شهریار کوچولو حتا سرش را هم بلند نکرد.
مردِ تجارت‌پیشه در سیاره‌اش
شهریار کوچولو گفت: -سلام. آتش‌سیگارتان خاموش شده.
-سه و دو می‌کند پنج. پنج و هفت دوازده و سه پانزده. سلام. پانزده و هفت بیست و دو. بیست و دو و شش بیست و هشت. وقت ندارم روشنش کنم. بیست و شش و پنج سی و یک. اوف! پس جمعش می‌کند پانصدویک میلیون و ششصد و بیست و دو هزار هفتصد و سی و یک.
-پانصد میلیون چی؟
-ها؟ هنوز این جایی تو؟ پانصد و یک میلیون چیز. چه می‌دانم، آن قدر کار سرم ریخته که!... من یک مرد جدی هستم و با حرف‌های هشت‌من‌نه‌شاهی سر و کار ندارم!... دو و پنج هفت...
شهریار کوچولو که وقتی چیزی می‌پرسید دیگر تا جوابش را نمی‌گرفت دست بردار نبود دوباره پرسید:
-پانصد و یک میلیون چی؟
تاجر پیشه سرش را بلند کرد:
-تو این پنجاه و چهار سالی که ساکن این اخترکم همه‌اش سه بار گرفتار مودماغ شده‌ام. اولیش بیست و دو سال پیش یک سوسک بود که خدا می‌داند از کدام جهنم پیدایش شد. صدای وحشت‌ناکی از خودش در می‌آورد که باعث شد تو یک جمع چهار جا اشتباه کنم. دفعه‌ی دوم یازده سال پیش بود که استخوان درد بی‌چاره‌ام کرد. من ورزش نمی‌کنم. وقت یللی‌تللی هم ندارم. آدمی هستم جدی... این هم بار سومش!... کجا بودم؟ پانصد و یک میلیون و...
-این همه میلیون چی؟
تاجرپیشه فهمید که نباید امید خلاصی داشته باشد. گفت: -میلیون‌ها از این چیزهای کوچولویی که پاره‌ای وقت‌ها تو هوا دیده می‌شود.
-مگس؟
-نه بابا. این چیزهای کوچولوی براق.
-زنبور عسل؟
-نه بابا! همین چیزهای کوچولوی طلایی که وِلِنگارها را به عالم هپروت می‌برد. گیرم من شخصا آدمی هستم جدی که وقتم را صرف خیال‌بافی نمی‌کنم.
-آها، ستاره؟
-خودش است: ستاره.
-خب پانصد میلیون ستاره به چه دردت می‌خورد؟
-پانصد و یک میلیون و ششصد و بیست و دو هزار و هفتصد و سی و یکی. من جدیّم و دقیق.
-خب، به چه دردت می‌خورند؟
-به چه دردم می‌خورند؟
-ها.
-هیچی تصاحب‌شان می‌کنم.
-ستاره‌ها را؟
-آره خب.
-آخر من به یک پادشاهی برخوردم که...
-پادشاه‌ها تصاحب نمی‌کنند بل‌که به‌اش «سلطنت» می‌کنند. این دو تا با هم خیلی فرق دارد.
-خب، حالا تو آن‌ها را تصاحب می‌کنی که چی بشود؟
-که دارا بشوم.
-خب دارا شدن به چه کارت می‌خورد؟
-به این کار که، اگر کسی ستاره‌ای پیدا کرد من ازش بخرم.
شهریار کوچولو با خودش گفت: «این بابا هم منطقش یک خرده به منطق آن دائم‌الخمره می‌بَرَد.» با وجود این باز ازش پرسید:
-چه جوری می‌شود یک ستاره را صاحب شد؟
تاجرپیشه بی درنگ با اَخم و تَخم پرسید: -این ستاره‌ها مال کی‌اند؟
-چه می‌دانم؟ مال هیچ کس.
-پس مال منند، چون من اول به این فکر افتادم.
-همین کافی است؟
-البته که کافی است. اگر تو یک جواهر پیدا کنی که مال هیچ کس نباشد می‌شود مال تو. اگر جزیره‌ای کشف کنی که مال هیچ کس نباشد می‌شود مال تو. اگر فکری به کله‌ات بزند که تا آن موقع به سر کسی نزده به اسم خودت ثبتش می‌کنی و می‌شود مال تو. من هم ستاره‌ها را برای این صاحب شده‌ام که پیش از من هیچ کس به فکر نیفتاده بود آن‌ها را مالک بشود.
شهریار کوچولو گفت: -این ها همه‌اش درست. منتها چه کارشان می‌کنی؟
تاجر پیشه گفت: -اداره‌شان می‌کنم، همین جور می‌شمارم‌شان و می‌شمارم‌شان. البته کار مشکلی است ولی خب دیگر، من آدمی هستم بسیار جدی.
شهریار کوچولو که هنوز این حرف تو کَتَش نرفته‌بود گفت:
-اگر من یک شال گردن ابریشمی داشته باشم می‌توانم بپیچم دور گردنم با خودم ببرمش. اگر یک گل داشته باشم می‌توانم بچینم با خودم ببرمش. اما تو که نمی‌توانی ستاره‌ها را بچینی!
-نه. اما می‌توانم بگذارم‌شان تو بانک.
-اینی که گفتی یعنی چه؟
-یعنی این که تعداد ستاره‌هایم را رو یک تکه کاغذ می‌نویسم می‌گذارم تو کشو درش را قفل می‌کنم.
-همه‌اش همین؟
-آره همین کافی است.
شهریار کوچولو فکر کرد «جالب است. یک خرده هم شاعرانه است. اما کاری نیست که آن قدرها جدیش بشود گرفت». آخر تعبیر او از چیزهای جدی با تعبیر آدم‌های بزرگ فرق می‌کرد.
باز گفت: -من یک گل دارم که هر روز آبش می‌دهم. سه تا هم آتش‌فشان دارم که هفته‌ای یک بار پاک و دوده‌گیری‌شان می‌کنم. آخر آتش‌فشان خاموشه را هم پاک می‌کنم. آدم کفِ دستش را که بو نکرده! رو این حساب، هم برای آتش‌فشان‌ها و هم برای گل این که من صاحب‌شان باشم فایده دارد. تو چه فایده‌ای به حال ستاره‌ها داری؟
تاجرپیشه دهن باز کرد که جوابی بدهد اما چیزی پیدا نکرد. و شهریار کوچولو راهش را گرفت و رفت و همان جور که می‌رفت تو دلش می‌گفت: -این آدم بزرگ‌ها راستی راستی چه‌قدر عجیبند!
۱۴
اخترکِ پنجم چیز غریبی بود. از همه‌ی اخترک‌های دیگر کوچک‌تر بود، یعنی فقط به اندازه‌ی یک فانوس پایه‌دار و یک فانوس‌بان جا داشت.
فانوس‌بان در حالِ روشن کردنِ فانوس در سیاره‌اش
شهریار کوچولو از این راز سر در نیاورد که یک جا میان آسمان خدا تو اخترکی که نه خانه‌ای روش هست نه آدمی، حکمت وجودی یک فانوس و یک فانوس‌بان چه می‌تواند باشد. با وجود این تو دلش گفت:
-خیلی احتمال دارد که این بابا عقلش پاره‌سنگ ببرد. اما به هر حال از پادشاه و خودپسند و تاجرپیشه و مسته کم عقل‌تر نیست. دست کم کاری که می‌کند یک معنایی دارد. فانوسش را که روشن می‌کند عین‌هو مثل این است که یک ستاره‌ی دیگر یا یک گل به دنیا می‌آورد و خاموشش که می‌کند پنداری گل یا ستاره‌ای را می‌خواباند. سرگرمی زیبایی است و چیزی که زیبا باشد بی گفت‌وگو مفید هم هست.
وقتی رو اخترک پایین آمد با ادب فراوان به فانوس‌بان سلام کرد:
-سلام. واسه چی فانوس را خاموش کردی؟
-دستور است. صبح به خیر!
-دستور چیه؟
-این است که فانوسم را خاموش کنم. شب خوش!
و دوباره فانوس را روشن کرد.
-پس چرا روشنش کردی باز؟
فانوس‌بان جواب داد: -خب دستور است دیگر.
شهریار کوچولو گفت: -اصلا سر در نمیارم.
فانوس‌بان گفت: -چیز سر در آوردنی‌یی توش نیست که. دستور دستور است. روز بخیر!
و باز فانوس را خاموش کرد.
بعد با دستمال شطرنجی قرمزی عرق پیشانیش را خشکاند و گفت:
-کار جان‌فرسایی دارم. پیش‌تر ها معقول بود: صبح خاموشش می‌کردم و شب که می‌شد روشنش می‌کردم. باقی روز را فرصت داشتم که استراحت کنم و باقی شب را هم می‌توانستم بگیرم بخوابم...
-بعدش دستور عوض شد؟
فانوس‌بان گفت: -دستور عوض نشد و بدبختی من هم از همین جاست: سیاره سال به سال گردشش تندتر و تندتر شده اما دستور همان جور به قوت خودش باقی مانده است.
-خب؟
-حالا که سیاره دقیقه‌ای یک بار دور خودش می‌گردد دیگر من یک ثانیه هم فرصت استراحت ندارم: دقیقه‌ای یک بار فانوس را روشن می‌کنم یک بار خاموش.
-چه عجیب است! تو اخترک تو شبانه روز همه‌اش یک دقیقه طول می‌کشد!
فانوس‌بان گفت: -هیچ هم عجیب نیست. الان یک ماه تمام است که ما داریم با هم اختلاط می‌کنیم.
-یک ماه؟
-آره. سی دقیقه. سی روز! شب خوش!
و دوباره فانوس را روشن کرد.
شهریار کوچولو به فانوس‌بان نگاه کرد و حس کرد این مرد را که تا این حد به دستور وفادار است دوست می‌دارد. یادِ آفتاب‌غروب‌هایی افتاد که آن وقت‌ها خودش با جابه‌جا کردن صندلیش دنبال می‌کرد. برای این که دستی زیر بال دوستش کرده باشد گفت:
-می‌دانی؟ یک راهی بلدم که می‌توانی هر وقت دلت بخواهد استراحت کنی.
فانوس‌بان گفت: -آرزوش را دارم.
آخر آدم می‌تواند هم به دستور وفادار بماند هم تنبلی کند.
شهریار کوچولو دنبال حرفش را گرفت و گفت:
-تو، اخترکت آن‌قدر کوچولوست که با سه تا شلنگ برداشتن می‌توانی یک بار دور بزنیش. اگر آن اندازه که لازم است یواش راه بروی می‌توانی کاری کنی که مدام تو آفتاب بمانی. پس هر وقت خواستی استراحت کنی شروع می‌کنی به راه‌رفتن... به این ترتیب روز هرقدر که بخواهی برایت کِش می‌آید.
فانوس‌بان گفت: -این کار گرهی از بدبختی من وا نمی‌کند. تنها چیزی که تو زندگی آرزویش را دارم یک چرت خواب است.
شهریار کوچولو گفت: -این یکی را دیگر باید بگذاری در کوزه.
فانوس‌بان گفت: -آره. باید بگذارمش در کوزه... صبح بخیر!
و فانوس را خاموش کرد.
شهریار کوچولو میان راه با خودش گفت: گرچه آن‌های دیگر، یعنی خودپسنده و تاجره اگر این را می‌دیدند دستش می‌انداختند و تحقیرش می‌کردند، هر چه نباشد کار این یکی به نظر من کم‌تر از کار آن‌ها بی‌معنی و مضحک است. شاید به خاطر این که دست کم این یکی به چیزی جز خودش مشغول است.
از حسرت آهی کشید و همان طور با خودش گفت:
-این تنها کسی بود که من می‌توانستم باش دوست بشوم. گیرم اخترکش راستی راستی خیلی کوچولو است و دو نفر روش جا نمی‌گیرند.
چیزی که جرات اعترافش را نداشت حسرت او بود به این اخترک کوچولویی که، بخصوص، به هزار و چهارصد و چهل بار غروب آفتاب در هر بیست و چهار ساعت برکت پیدا کرده بود.
۱۵
اخترک ششم اخترکی بود ده بار فراخ‌تر، و آقاپیره‌ای توش بود که کتاب‌های کَت‌وکلفت می‌نوشت.
جغرافی‌دان در سیاره‌اش
همین که چشمش به شهریار کوچولو افتاد با خودش گفت:
-خب، این هم یک کاشف!
شهریار کوچولو لب میز نشست و نفس نفس زد. نه این که راه زیادی طی کرده بود؟
آقا پیره به‌اش گفت: -از کجا می‌آیی؟
شهریار کوچولو گفت: -این کتاب به این کلفتی چی است؟ شما این‌جا چه‌کار می‌کنید؟
آقا پیره گفت: -من جغرافی‌دانم.
-جغرافی‌دان چه باشد؟
-جغرافی‌دان به دانشمندی می‌گویند که جای دریاها و رودخانه‌ها و شهرها و کوه‌ها و بیابان‌ها را می‌داند.
شهریار کوچولو گفت: -محشر است. یک کار درست و حسابی است.
و به اخترک جغرافی‌دان، این سو و آن‌سو نگاهی انداخت. تا آن وقت اخترکی به این عظمت ندیده‌بود.
-اخترک‌تان خیلی قشنگ است. اقیانوس هم دارد؟
جغرافی‌دان گفت: -از کجا بدانم؟
شهریار کوچولو گفت: -عجب! (بد جوری جا خورده بود) کوه چه‌طور؟
جغرافی‌دان گفت: -از کجا بدانم؟
-شهر، رودخانه، بیابان؟
جغرافی‌دان گفت: از این‌ها هم خبری ندارم.
-آخر شما جغرافی‌دانید؟
جغرافی‌دان گفت: -درست است ولی کاشف که نیستم. من حتا یک نفر کاشف هم ندارم. کار جغرافی‌دان نیست که دوره‌بیفتد برود شهرها و رودخانه‌ها و کوه‌ها و دریاها و اقیانوس‌ها و بیابان‌ها را بشمرد. مقام جغرافی‌دان برتر از آن است که دوره بیفتد و ول‌بگردد. اصلا از اتاق کارش پا بیرون نمی‌گذارد بلکه کاشف‌ها را آن تو می‌پذیرد ازشان سوالات می‌کند و از خاطرات‌شان یادداشت بر می‌دارد و اگر خاطرات یکی از آن‌ها به نظرش جالب آمد دستور می‌دهد روی خُلقیات آن کاشف تحقیقاتی صورت بگیرد.
-برای چه؟
-برای این که اگر کاشفی گنده‌گو باشد کار کتاب‌های جغرافیا را به فاجعه می‌کشاند. هکذا کاشفی که اهل پیاله باشد.
-آن دیگر چرا؟
b-چون آدم‌های دائم‌الخمر همه چیز را دوتا می‌بینند. آن وقت جغرافی‌دان برمی‌دارد جایی که یک کوه
بیشتر نیست می‌نویسد دو کوه.
شهریار کوچولو گفت: -پس من یک بابایی را می‌شناسم که کاشف هجوی از آب در می‌آید.
-بعید نیست. بنابراین، بعد از آن که کاملا ثابت شد پالان کاشف کج نیست تحقیقاتی هم روی کشفی که کرده انجام می‌گیرد.
-یعنی می‌روند می‌بینند؟
-نه، این کار گرفتاریش زیاد است. از خود کاشف می‌خواهند دلیل بیاورد. مثلا اگر پای کشف یک کوه بزرگ در میان بود ازش می‌خواهند سنگ‌های گنده‌ای از آن کوه رو کند.
جغرافی‌دان ناگهان به هیجان در آمد و گفت: -راستی تو داری از راه دوری می‌آیی! تو کاشفی! باید چند و چون اخترکت را برای من بگویی.
و با این حرف دفتر و دستکش را باز کرد و مدادش را تراشید. معمولا خاطرات کاشف‌ها را اول بامداد یادداشت می‌کنند و دست نگه می‌دارند تا دلیل اقامه کند، آن وقت با جوهر می‌نویسند.
گفت: -خب؟
شهریار کوچولو گفت: -اخترک من چیز چندان جالبی ندارد. آخر خیلی کوچک است. سه تا آتش‌فشان دارم که دوتاش فعال است یکیش خاموش. اما، خب دیگر، آدم کف دستش را که بو نکرده.
جغرافی‌دان هم گفت: -آدم چه می‌داند چه پیش می‌آید.
-یک گل هم دارم.
-نه، نه، ما دیگر گل ها را یادداشت نمی‌کنیم.
-چرا؟ گل که زیباتر است.
-برای این که گل‌ها فانی‌اند.
-فانی یعنی چی؟
جغرافی‌دان گفت: -کتاب‌های جغرافیا از کتاب‌های دیگر گران‌بهاترست و هیچ وقت هم از اعتبار نمی‌افتد. بسیار به ندرت ممکن است یک کوه جا عوض کند. بسیار به ندرت ممکن است آب یک اقیانوس خالی شود. ما فقط چیزهای پایدار را می‌نویسیم.
شهریار کوچولو تو حرف او دوید و گفت: -اما آتش‌فشان‌های خاموش می‌توانند از نو بیدار بشوند. فانی را نگفتید یعنی چه؟
جغرافی‌دان گفت: -آتش‌فشان چه روشن باشد چه خاموش برای ما فرقی نمی‌کند. آن‌چه به حساب می‌آید خود کوه است که تغییر پیدا نمی‌کند.
شهریار کوچولو که تو تمام عمرش وقتی چیزی از کسی می‌پرسید دیگر دست بردار نبود دوباره سوال کرد: -فانی یعنی چه؟
-یعنی چیزی که در آینده تهدید به نابودی شود.
-گل من هم در آینده نابود می‌شود؟
-البته که می‌شود.
شهریار کوچولو در دل گفت: «گل من فانی است و جلو دنیا برای دفاع از خودش جز چهارتا خار هیچی ندارد، و آن وقت مرا بگو که او را توی اخترکم تک و تنها رها کرده‌ام!»
این اولین باری بود که دچار پریشانی و اندوه می‌شد اما توانست به خودش مسلط بشود. پرسید: -شما به من دیدن کجا را توصیه می‌کنید؟
جغرافی‌دان به‌اش جواب داد: -سیاره‌ی زمین. شهرت خوبی دارد...
و شهریار کوچولو هم چنان که به گلش فکر می‌کرد به راه افتاد.
۱۶
لاجرم، زمین، سیاره‌ی هفتم شد.
زمین، فلان و بهمان سیاره نیست. رو پهنه‌ی زمین یک‌صد و یازده پادشاه (البته بامحاسبه‌ی پادشاهان سیاه‌پوست)، هفت هزار جغرافی‌دان، نه‌صد هزار تاجرپیشه، پانزده کرور می‌خواره و شش‌صد و بیست و دو کرور خودپسند و به عبارت دیگر حدود دو میلیارد آدم بزرگ زندگی می‌کند. برای آن‌که از حجم زمین مقیاسی به دست‌تان بدهم بگذارید به‌تان بگویم که پیش از اختراع برق مجبور بودند در مجموع شش قاره‌ی زمین وسایل زندگیِ لشکری جانانه شامل یکصد و شصت و دو هزار و پانصد و یازده نفر فانوس‌بان را تامین کنند.
روشن شدن فانوس‌ها از دور خیلی باشکوه بود. حرکات این لشکر مثل حرکات یک باله‌ی تو اپرا مرتب و منظم بود. اول از همه نوبت فانوس‌بان‌های زلاندنو و استرالیا بود. این‌ها که فانوس‌هاشان را روشن می‌کردند، می‌رفتند می‌گرفتند می‌خوابیدند آن وقت نوبت فانوس‌بان‌های چین و سیبری می‌رسید که به رقص درآیند. بعد، این‌ها با تردستی تمام به پشت صحنه می‌خزیدند و جا را برای فانوس‌بان‌های ترکیه و هفت پَرکَنِه‌ی هند خالی می کردند. بعد نوبت به فانوس‌بان‌های آمریکای‌جنوبی می‌شد. و آخر سر هم نوبت فانوس‌بان‌های افریقا و اروپا می‌رسد و بعد نوبت فانوس‌بان‌های آمریکای شمالی بود. و هیچ وقتِ خدا هم هیچ‌کدام این‌ها در ترتیب ورودشان به صحنه دچار اشتباه نمی‌شدند. چه شکوهی داشت! میان این جمع عظیم فقط نگه‌بانِ تنها فانوسِ قطب شمال و همکارش نگه‌بانِ تنها فانوسِ قطب جنوب بودند که عمری به بطالت و بی‌هودگی می‌گذراندند: آخر آن‌ها سالی به سالی همه‌اش دو بار کار می‌کردند.
۱۷
آدمی که اهل اظهار لحیه باشد بفهمی نفهمی می‌افتد به چاخان کردن. من هم تو تعریف قضیه‌ی فانوس‌بان‌ها برای شما آن‌قدرهاروراست نبودم. می‌ترسم به آن‌هایی که زمین ما را نمی‌سناسند تصور نادرستی داده باشم. انسان‌ها رو پهنه‌ی زمین جای خیلی کمی را اشغال می‌کنند. اگر همه‌ی دو میلیارد نفری که رو کره‌ی زمین زندگی می‌کنند بلند بشوند و مثل موقعی که به تظاهرات می‌روند یک خورده جمع و جور بایستند راحت و بی‌درپسر تو میدانی به مساحت بیست میل در بیست میل جا می‌گیرند. همه‌ی جامعه‌ی بشری را می‌شود یک‌جا روی کوچک‌ترین جزیره‌ی اقیانوس آرام کُپه کرد.
البته گفت‌وگو ندارد که آدم بزرگ‌ها حرف‌تان را باور نمی‌کنند. آخر تصور آن‌ها این است که کلی جا اشغال کرده‌اند، نه این‌که مثل بائوباب‌ها خودشان را خیلی مهم می‌بینند؟ بنابراین به‌شان پیش‌نهاد می‌کنید که بنشینند حساب کنند. آن‌ها هم که عاشق اعداد و ارقامند، پس این پیش‌نهاد حسابی کیفورشان می‌کند. اما شما را به خدا بی‌خودی وقت خودتان را سر این جریمه‌ی مدرسه به هدر ندهید. این کار دو قاز هم نمی‌ارزد. به من که اطمینان دارید. شهریار کوچولو پاش که به زمین رسید از این که دیارالبشری دیده نمی‌شد سخت هاج و واج ماند.
شهریار کوچولو وسطِ کویر
تازه داشت از این فکر که شاید سیاره را عوضی گرفته ترسش بر می‌داشت که چنبره‌ی مهتابی رنگی رو ماسه‌ها جابه‌جا شد.شهریار کوچولو و مار
شهریار کوچولو همین‌جوری سلام کرد.
مار گفت: -سلام.
شهریار کوچولو پرسید: -رو چه سیاره‌ای پایین آمده‌ام؟
مار جواب داد: -رو زمین تو قاره‌ی آفریقا.
-عجب! پس رو زمین انسان به هم نمی‌رسد؟
مار گفت: -این‌جا کویر است. تو کویر کسی زندگی نمی‌کند. زمین بسیار وسیع است.
شهریار کوچولو رو سنگی نشست و به آسمان نگاه کرد. گفت: -به خودم می‌گویم ستاره‌ها واسه این روشنند که هرکسی بتواند یک روز مال خودش را پیدا کند!... اخترک مرا نگاه! درست بالا سرمان است... اما چه‌قدر دور است!
مار گفت: -قشنگ است. این‌جا آمده‌ای چه کار؟
شهریار کوچولو گفت: -با یک گل بگومگویم شده.
مار گفت: -عجب!
و هر دوشان خاموش ماندند.
دست آخر شهریار کوچولو درآمد که: -آدم‌ها کجاند؟ آدم تو کویر یک خرده احساس تنهایی می‌کند.
مار گفت: -پیش آدم‌ها هم احساس تنهایی می‌کنی.
شهریار کوچولو مدت درازی تو نخ او رفت و آخر سر به‌اش گفت: -تو چه جانور بامزه‌ای هستی! مثل یک انگشت، باریکی.
مار گفت: -عوضش از انگشت هر پادشاهی مقتدرترم.
شهریار کوچولو لب‌خندی زد و گفت: -نه چندان... پا هم که نداری. حتا راه هم نمی‌تونی بری...
-من می‌تونم تو را به چنان جای دوری ببرم که با هیچ کشتی‌یی هم نتونی بری.
مار این را گفت و دور قوزک پای شهریار کوچولو پیچید. عین یک خلخال طلا. و باز درآمد که: -هر کسی را لمس کنم به خاکی که ازش درآمده بر می‌گردانم اما تو پاکی و از یک سیّاره‌ی دیگر آمده‌ای...
شهریار کوچولو جوابی بش نداد.
-تو رو این زمین خارایی آن‌قدر ضعیفی که به حالت رحمم می‌آید. روزی‌روزگاری اگر دلت خیلی هوای اخترکت را کرد بیا من کمکت کنم... من می‌توانم...
شهریار کوچولو گفت: -آره تا تهش را خواندم. اما راستی تو چرا همه‌ی حرف‌هایت را به صورت معما درمی‌آری؟
مار گفت: -حلّال همه‌ی معماهام من.
و هر دوشان خاموش شدند.
۱۸
شهریار کوچولو کویر را از پاشنه درکرد و جز یک گل به هیچی برنخورد: یک گل سه گل‌برگه. یک گلِ ناچیز.
یک گُل وسطِ کویر
شهریار کوچولو گفت: -سلام.
گل گفت: -سلام.
شهریار کوچولو با ادب پرسید: -آدم‌ها کجاند؟
گل روزی روزگاری عبور کاروانی را دیده‌بود. این بود که گفت: -آدم‌ها؟ گمان کنم ازشان شش هفت تایی باشد. سال‌ها پیش دیدم‌شان. منتها خدا می‌داند کجا می‌شود پیداشان کرد. باد این‌ور و آن‌ور می‌بَرَدشان؛ نه این که ریشه ندارند؟ بی‌ریشگی هم حسابی اسباب دردسرشان شده.
شهریار کوچولو گفت: -خداحافظ.
گل گفت: -خداحافظ.
۱۹
از کوه بلندی بالا رفت.
شهریار کوچولو بر قله‌ی کوهِ بلند
تنها کوه‌هایی که به عمرش دیده بود سه تا آتش‌فشان‌های اخترک خودش بود که تا سر زانویش می‌رسید و از آن یکی که خاموش بود جای چارپایه استفاده می‌کرد. این بود که با خودش گفت: «از سر یک کوه به این بلندی می‌توانم به یک نظر همه‌ی سیاره و همه‌ی آدم‌ها را ببینم...» اما جز نوکِ تیزِ صخره‌های نوک‌تیز چیزی ندید.
همین جوری گفت: -سلام.
طنین به‌اش جواب داد: -سلام... سلام... سلام...
شهریار کوچولو گفت: -کی هستید شما؟
طنین به‌اش جواب داد: -کی هستید شما... کی هستید شما... کی هستید شما...
گفت: -با من دوست بشوید. من تک و تنهام.
طنین به‌اش جواب داد: -من تک و تنهام... من تک و تنهام... من تک و تنهام...
آن‌وقت با خودش فکر کرد: «چه سیاره‌ی عجیبی! خشک‌ِخشک و تیزِتیز و شورِشور. این آدم‌هاش که یک ذره قوه‌ی تخیل ندارند و هر چه را بشنوند عینا تکرار می‌کنند... تو اخترک خودم گلی داشتم که همیشه اول او حرف می‌زد...»
۲۰
اما سرانجام، بعد از مدت‌ها راه رفتن از میان ریگ‌ها و صخره‌ها و برف‌ها به جاده‌ای برخورد. و هر جاده‌ای یک‌راست می‌رود سراغ آدم‌ها.
گفت: -سلام.
و مخاطبش گلستان پرگلی بود.
شهریار کوچولو در گلستانِ پرگل
گل‌ها گفتند: -سلام.
شهریار کوچولو رفت تو بحرشان. همه‌شان عین گل خودش بودند. حیرت‌زده ازشان پرسید: -شماها کی هستید؟
گفتند: -ما گل سرخیم.
آهی کشید و سخت احساس شوربختی کرد. گلش به او گفته بود که از نوع او تو تمام عالم فقط همان یکی هست و حالا پنج‌هزارتا گل، همه مثل هم، فقط تو یک گلستان! فکر کرد: «اگر گل من این را می‌دید بدجور از رو می‌رفت. پشت سر هم بنا می‌کرد سرفه‌کردن و، برای این‌که از هُوشدن نجات پیدا کند خودش را به مردن می‌زد و من هم مجبور می‌شدم وانمود کنم به پرستاریش، وگرنه برای سرشکسته کردنِ من هم شده بود راستی راستی می‌مرد...» و باز تو دلش گفت: «مرا باش که فقط بایک دانه گل خودم را دولت‌مندِ عالم خیال می‌کردم در صورتی‌که آن‌چه دارم فقط یک گل معمولی است. با آن گل و آن سه تا آتش‌فشان که تا سرِ زانومَند و شاید هم یکی‌شان تا ابد خاموش بماند شهریارِ چندان پُرشوکتی به حساب نمی‌آیم.»
شهریار کوچولو در حالِ احساسِ شوربختی
رو سبزه‌ها دراز شد و حالا گریه نکن کی گریه‌کن.
۲۱
آن وقت بود که سر و کله‌ی روباه پیدا شد.
شهریار کوچولو و روباه
روباه گفت: -سلام.
شهریار کوچولو برگشت اما کسی را ندید. با وجود این با ادب تمام گفت: -سلام.
صداگفت: -من این‌جام، زیر درخت سیب...
شهریار کوچولو گفت: -کی هستی تو؟ عجب خوشگلی!
روباه گفت: -یک روباهم من.
شهریار کوچولو گفت: -بیا با من بازی کن. نمی‌دانی چه قدر دلم گرفته...
روباه گفت: -نمی‌توانم بات بازی کنم. هنوز اهلیم نکرده‌اند آخر.
شهریار کوچولو آهی کشید و گفت: -معذرت می‌خواهم.
اما فکری کرد و پرسید: -اهلی کردن یعنی چه؟
روباه گفت: -تو اهل این‌جا نیستی. پی چی می‌گردی؟
شهریار کوچولو گفت: -پی آدم‌ها می‌گردم. نگفتی اهلی کردن یعنی چه؟
روباه گفت: -آدم‌ها تفنگ دارند و شکار می‌کنند. اینش اسباب دلخوری است! اما مرغ و ماکیان هم پرورش می‌دهند و خیرشان فقط همین است. تو پی مرغ می‌کردی؟
شهریار کوچولو گفت: -نَه، پیِ دوست می‌گردم. اهلی کردن یعنی چی؟
روباه گفت: -یک چیزی است که پاک فراموش شده. معنیش ایجاد علاقه کردن است.
-ایجاد علاقه کردن؟
روباه گفت: -معلوم است. تو الان واسه من یک پسر بچه‌ای مثل صد هزار پسر بچه‌ی دیگر. نه من هیچ احتیاجی به تو دارم نه تو هیچ احتیاجی به من. من هم واسه تو یک روباهم مثل صد هزار روباه دیگر. اما اگر منو اهلی کردی هر دوتامان به هم احتیاج پیدا می‌کنیم. تو واسه من میان همه‌ی عالم موجود یگانه‌ای می‌شوی من واسه تو.
شهریار کوچولو گفت: -کم‌کم دارد دستگیرم می‌شود. یک گلی هست که گمانم مرا اهلی کرده باشد.
روباه گفت: -بعید نیست. رو این کره‌ی زمین هزار جور چیز می‌شود دید.
شهریار کوچولو گفت: -اوه نه! آن رو کره‌ی زمین نیست.
روباه که انگار حسابی حیرت کرده بود گفت: -رو یک سیاره‌ی دیگر است؟
-آره.
شکارچی-تو آن سیاره شکارچی هم هست؟
-نه.
-محشر است! مرغ و ماکیان چه‌طور؟
-نه.
روباه آه‌کشان گفت: -همیشه‌ی خدا یک پای بساط لنگ است!
اما پی حرفش را گرفت و گفت: -زندگی یک‌نواختی دارم. من مرغ‌ها را شکار می‌کنم آدم‌ها مرا. همه‌ی مرغ‌ها عین همند همه‌ی آدم‌ها هم عین همند. این وضع یک خرده خلقم را تنگ می‌کند. اما اگر تو منو اهلی کنی انگار که زندگیم را چراغان کرده باشی. آن وقت صدای پایی را می‌شناسم که باهر صدای پای دیگر فرق می‌کند: صدای پای دیگران مرا وادار می‌کند تو هفت تا سوراخ قایم بشوم اما صدای پای تو مثل نغمه‌ای مرا از سوراخم می‌کشد بیرون. تازه، نگاه کن آن‌جا آن گندم‌زار را می‌بینی؟ برای من که نان بخور نیستم گندم چیز بی‌فایده‌ای است. پس گندم‌زار هم مرا به یاد چیزی نمی‌اندازد. اسباب تاسف است. اما تو موهات رنگ طلا است. پس وقتی اهلیم کردی محشر می‌شود! گندم که طلایی رنگ است مرا به یاد تو می‌اندازد و صدای باد را هم که تو گندم‌زار می‌پیچد دوست خواهم داشت...
خاموش شد و مدت درازی شهریار کوچولو را نگاه کرد. آن وقت گفت: -اگر دلت می‌خواهد منو اهلی کن!
شهریار کوچولو جواب داد: -دلم که خیلی می‌خواهد، اما وقتِ چندانی ندارم. باید بروم دوستانی پیدا کنم و از کلی چیزها سر در آرم.
روباه گفت: -آدم فقط از چیزهایی که اهلی کند می‌تواند سر در آرد. انسان‌ها دیگر برای سر در آوردن از چیزها وقت ندارند. همه چیز را همین جور حاضر آماده از دکان‌ها می‌خرند. اما چون دکانی نیست که دوست معامله کند آدم‌ها مانده‌اند بی‌دوست... تو اگر دوست می‌خواهی خب منو اهلی کن!
شهریار کوچولو پرسید: -راهش چیست؟
روباه جواب داد: -باید خیلی خیلی حوصله کنی. اولش یک خرده دورتر از من می‌گیری این جوری میان علف‌ها می‌نشینی. من زیر چشمی نگاهت می‌کنم و تو لام‌تاکام هیچی نمی‌گویی، چون تقصیر همه‌ی سؤِتفاهم‌ها زیر سر زبان است. عوضش می‌توانی هر روز یک خرده نزدیک‌تر بنشینی.
روباه در حالِ انتظارفردای آن روز دوباره شهریار کوچولو آمد.
روباه گفت: -کاش سر همان ساعت دیروز آمده بودی. اگر مثلا سر ساعت چهار بعد از ظهر بیایی من از ساعت سه تو دلم قند آب می‌شود و هر چه ساعت جلوتر برود بیش‌تر احساس شادی و خوشبختی می‌کنم. ساعت چهار که شد دلم بنا می‌کند شور زدن و نگران شدن. آن وقت است که قدرِ خوشبختی را می‌فهمم! اما اگر تو وقت و بی وقت بیایی من از کجا بدانم چه ساعتی باید دلم را برای دیدارت آماده کنم؟... هر چیزی برای خودش قاعده‌ای دارد.
شهریار کوچولو گفت: -قاعده یعنی چه؟
روباه گفت: -این هم از آن چیزهایی است که پاک از خاطرها رفته. این همان چیزی است که باعث می‌شود فلان روز با باقی روزها و فلان ساعت با باقی ساعت‌ها فرق کند. مثلا شکارچی‌های ما میان خودشان رسمی دارند و آن این است که پنج‌شنبه‌ها را با دخترهای ده می‌روند رقص. پس پنج‌شنبه‌ها بَرّه‌کشانِ من است: برای خودم گردش‌کنان می‌روم تا دم مُوِستان. حالا اگر شکارچی‌ها وقت و بی وقت می‌رقصیدند همه‌ی روزها شبیه هم می‌شد و منِ بیچاره دیگر فرصت و فراغتی نداشتم.
به این ترتیب شهریار کوچولو روباه را اهلی کرد.
لحظه‌ی جدایی که نزدیک شد روباه گفت: -آخ! نمی‌توانم جلو اشکم را بگیرم.
شهریار کوچولو گفت: -تقصیر خودت است. من که بدت را نمی‌خواستم، خودت خواستی اهلیت کنم.
روباه گفت: -همین طور است.
شهریار کوچولو گفت: -آخر اشکت دارد سرازیر می‌شود!
روباه گفت: -همین طور است.
-پس این ماجرا فایده‌ای به حال تو نداشته.
روباه گفت: -چرا، واسه خاطرِ رنگ گندم.
بعد گفت: -برو یک بار دیگر گل‌ها را ببین تا بفهمی که گلِ خودت تو عالم تک است. برگشتنا با هم وداع می‌کنیم و من به عنوان هدیه رازی را به‌ات می‌گویم.
شهریار کوچولو بار دیگر به تماشای گل‌ها رفت و به آن‌ها گفت: -شما سرِ سوزنی به گل من نمی‌مانید و هنوز هیچی نیستید. نه کسی شما را اهلی کرده نه شما کسی را. درست همان جوری هستید که روباه من بود: روباهی بود مثل صدهزار روباه دیگر. او را دوست خودم کردم و حالا تو همه‌ی عالم تک است.
گل‌ها حسابی از رو رفتند.
شهریار کوچولو دوباره درآمد که: -خوشگلید اما خالی هستید. برای‌تان نمی‌شود مُرد. گفت‌وگو ندارد که گلِ مرا هم فلان ره‌گذر می‌بیند مثل شما. اما او به تنهایی از همه‌ی شما سر است چون فقط اوست که آبش داده‌ام، چون فقط اوست که زیر حبابش گذاشته‌ام، چون فقط اوست که با تجیر برایش حفاظ درست کرده‌ام، چون فقط اوست که حشراتش را کشته‌ام (جز دو سه‌تایی که می‌بایست شب‌پره بشوند)، چون فقط اوست که پای گِلِه‌گزاری‌ها یا خودنمایی‌ها و حتا گاهی پای بُغ کردن و هیچی نگفتن‌هاش نشسته‌ام، چون او گلِ من است.
و برگشت پیش روباه.
گفت: -خدانگه‌دار!
روباه گفت: -خدانگه‌دار!... و اما رازی که گفتم خیلی ساده است:
جز با دل هیچی را چنان که باید نمی‌شود دید. نهاد و گوهر را چشمِ سَر نمی‌بیند.
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -نهاد و گوهر را چشمِ سَر نمی‌بیند.
-ارزش گل تو به قدرِ عمری است که به پاش صرف کرده‌ای.
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -به قدر عمری است که به پاش صرف کرده‌ام.
روباه گفت: -انسان‌ها این حقیقت را فراموش کرده‌اند اما تو نباید فراموشش کنی. تو تا زنده‌ای نسبت به چیزی که اهلی کرده‌ای مسئولی. تو مسئول گُلِتی...
شهریار کوچولو برای آن که یادش بماند تکرار کرد: -من مسئول گُلمَم.
۲۲
شهریار کوچولو گفت: -سلام.
سوزن‌بان گفت: -سلام.
شهریار کوچولو گفت: -تو چه کار می‌کنی این‌جا؟
سوزن‌بان گفت: -مسافرها را به دسته‌های هزارتایی تقسیم می‌کنم و قطارهایی را که می‌بَرَدشان گاهی به سمت راست می‌فرستم گاهی به سمت چپ. و همان دم سریع‌السیری با چراغ‌های روشن و غرّشی رعدوار اتاقک سوزن‌بانی را به لرزه انداخت.
-عجب عجله‌ای دارند! پیِ چی می‌روند؟
سوزن‌بان گفت: -از خودِ آتش‌کارِ لکوموتیف هم بپرسی نمی‌داند!
سریع‌السیر دیگری با چراغ‌های روشن غرّید و در جهت مخالف گذشت .
شهریار کوچولو پرسید: -برگشتند که؟
سوزن‌بان گفت: -این‌ها اولی‌ها نیستند. آن‌ها رفتند این‌ها برمی‌گردند.
-جایی را که بودند خوش نداشتند؟
سوزن‌بان گفت: -آدمی‌زاد هیچ وقت جایی را که هست خوش ندارد.
و رعدِ سریع‌السیرِ نورانیِ ثالثی غرّید.
شهریار کوچولو پرسید: -این‌ها دارند مسافرهای اولی را دنبال می‌کنند؟
سوزن‌بان گفت: -این‌ها هیچ چیزی را دنبال نمی‌کنند. آن تو یا خواب‌شان می‌بَرَد یا دهن‌دره می‌کنند. فقط بچه‌هاند که دماغ‌شان را فشار می‌دهند به شیشه‌ها.
شهریار کوچولو گفت: -فقط بچه‌هاند که می‌دانند پیِ چی می‌گردند. بچه‌هاند که کُلّی وقت صرف یک عروسک پارچه‌ای می‌کنند و عروسک برای‌شان آن قدر اهمیت به هم می‌رساند که اگر یکی آن را ازشان کِش برود می‌زنند زیر گریه...
سوزن‌بان گفت: -بخت، یارِ بچه‌هاست.
۲۳
شهریار کوچولو گفت: -سلام!
پیله‌ور گفت: -سلام.
این بابا فروشنده‌ی حَب‌های ضد تشنگی بود. خریدار هفته‌ای یک حب می‌انداخت بالا و دیگر تشنگی بی تشنگی.
شهریار کوچولو پرسید: -این‌ها را می‌فروشی که چی؟
پیله‌ور گفت: -باعث صرفه‌جویی کُلّی وقت است. کارشناس‌های خبره نشسته‌اند دقیقا حساب کرده‌اند که با خوردن این حب‌ها هفته‌ای پنجاه و سه دقیقه وقت صرفه‌جویی می‌شود.
-خب، آن وقت آن پنجاه و سه دقیقه را چه کار می‌کنند؟
ـ هر چی دل‌شان خواست...
چشمه
شهریار کوچولو تو دلش گفت: «من اگر پنجاه و سه دقیقه وقتِ زیادی داشته باشم خوش‌خوشک به طرفِ یک چشمه می‌روم...»
۲۴
هشتمین روزِ خرابی هواپیمام تو کویر بود که، در حال نوشیدنِ آخرین چک‌ّه‌ی ذخیره‌ی آبم به قضیه‌ی پیله‌وره گوش داده بودم. به شهریار کوچولو گفتم:
-خاطرات تو راستی راستی زیباند اما من هنوز از پسِ تعمیر هواپیما برنیامده‌ام، یک چکه آب هم ندارم. و راستی که من هم اگر می‌توانستم خوش‌خوشک به طرف چشمه‌ای بروم سعادتی احساس می‌کردم که نگو!
درآمد که: -دوستم روباه...
گفتم: -آقا کوچولو، دورِ روباه را قلم بگیر!
-واسه چی؟
-واسه این که تشنگی کارمان را می سازد. واسه این!
از استدلال من چیزی حالیش نشد و در جوابم گفت:
-حتا اگر آدم دَمِ مرگ باشد هم داشتن یک دوست عالی است. من که از داشتن یک دوستِ روباه خیلی خوشحالم...
به خودم گفتم نمی‌تواند میزان خطر را تخمین بزند: آخر او هیچ وقت نه تشنه‌اش می‌شود نه گشنه‌اش. یه ذره آفتاب بسش است...
اما او به من نگاه کرد و در جواب فکرم گفت: -من هم تشنه‌م است... بگردیم یک چاه پیدا کنیم...
از سرِ خستگی حرکتی کردم: -این جوری تو کویرِ برهوت رو هوا پیِ چاه گشتن احمقانه است.
و با وجود این به راه افتادیم.
پس از ساعت‌ها که در سکوت راه رفتیم شب شد و ستاره‌ها یکی یکی درآمدند. من که از زور تشنگی تب کرده بودم انگار آن‌ها را خواب می‌دیدم. حرف‌های شهریار کوچولو تو ذهنم می‌رقصید.
ازش پرسیدم: -پس تو هم تشنه‌ات هست، ها؟
اما او به سوآلِ من جواب نداد فقط در نهایت سادگی گفت: -آب ممکن است برای دلِ من هم خوب باشد...
از حرفش چیزی دستگیرم نشد اما ساکت ماندم. می‌دانستم از او نباید حرف کشید.
خسته شده بود. گرفت نشست. من هم کنارش نشستم. پس از مدتی سکوت گفت:
-قشنگیِ ستاره‌ها واسه خاطرِ گلی است که ما نمی‌بینیمش...
گفتم: -همین طور است
و بدون حرف در مهتاب غرق تماشای چین و شکن‌های شن شدم.
باز گفت: -کویر زیباست.
و حق با او بود. من همیشه عاشق کویر بوده‌ام. آدم بالای توده‌ای شن لغزان می‌نشیند، هیچی نمی‌بیند و هیچی نمی‌شنود اما با وجود این چیزی توی سکوت برق‌برق می‌زند.
شهریار کوچولو گفت: -چیزی که کویر را زیبا می‌کند این است که یک جایی یک چاه قایم کرده...
از این‌که ناگهان به راز آن درخشش اسرارآمیزِ شن پی بردم حیرت‌زده شدم. بچگی‌هام تو خانه‌ی کهنه‌سازی می‌نشستیم که معروف بود تو آن گنجی چال کرده‌اند. البته نگفته پیداست که هیچ وقت کسی آن را پیدا نکرد و شاید حتا اصلا کسی دنبالش نگشت اما فکرش همه‌ی اهل خانه را تردماغ می‌کرد: «خانه‌ی ما تهِ دلش رازی پنهان کرده بود...»
گفتم: -آره. چه خانه باشد چه ستاره، چه کویر، چیزی که اسباب زیبایی‌اش می‌شود نامریی است!
گفت: -خوشحالم که با روباه من توافق داری.
چون خوابش برده بود بغلش کردم و راه افتادم. دست و دلم می‌لرزید.انگار چیز شکستنیِ بسیار گران‌بهایی را روی دست می‌بردم. حتا به نظرم می‌آمد که تو تمام عالم چیزی شکستنی‌تر از آن هم به نظر نمی‌رسد. تو روشنی مهتاب به آن پیشانی رنگ‌پریده و آن چشم‌های بسته و آن طُرّه‌های مو که باد می‌جنباند نگاه کردم و تو دلم گفتم: «آن چه می‌بینم صورت ظاهری بیش‌تر نیست. مهم‌ترش را با چشم نمی‌شود دید...»
باز، چون دهان نیمه‌بازش طرح کم‌رنگِ نیمه‌لبخندی را داشت به خود گفتم: «چیزی که تو شهریار کوچولوی خوابیده مرا به این شدت متاثر می‌کند وفاداری اوست به یک گل: او تصویرِ گل سرخی است که مثل شعله‌ی چراغی حتا در خوابِ ناز هم که هست تو وجودش می‌درخشد...» و آن وقت او را باز هم شکننده‌تر دیدم. حس کردم باید خیلی مواظبش باشم: به شعله‌ی چراغی می‌مانست که یک وزش باد هم می‌توانست خاموشش کند.
و همان طور در حال راه رفتن بود که دمدمه‌ی سحر چاه را پیداکردم.
۲۵
شهریار کوچولو درآمد که: -آدم‌ها!... می‌چپند تو قطارهای تندرو اما نمی‌دانند دنبال چی می‌گردند. این است که بنامی‌کنند دور خودشان چرخک‌زدن.
و بعد گفت: -این هم کار نشد...
چاهی که به‌اش رسیده‌بودیم اصلا به چاه‌های کویری نمی‌مانست. چاه کویری یک چاله‌ی ساده است وسط شن‌ها. این یکی به چاه‌های واحه‌ای می‌مانست اما آن دوروبر واحه‌ای نبود و من فکر کردم دارم خواب می‌بینم.
گفتم: -عجیب است! قرقره و سطل و تناب، همه‌چیز روبه‌راه است.
خندید تناب را گرفت و قرقره را به کار انداخت
شهریار کوچولو در حالِ کشیدنِ آب از چاه
و قرقره مثل بادنمای کهنه‌ای که تا مدت‌ها پس از خوابیدنِ باد می‌نالد به ناله‌درآمد.
گفت: -می‌شنوی؟ ما داریم این چاه را از خواب بیدار می‌کنیم و او دارد برای‌مان آواز می‌خواند...
دلم نمی‌خواست او تلاش و تقلا کند. بش گفتم: -بدهش به من. برای تو زیادی سنگین است.
سطل را آرام تا طوقه‌ی چاه آوردم بالا و آن‌جا کاملا در تعادل نگهش داشتم. از حاصل کار شاد بودم. خسته و شاد. آواز قرقره را همان‌طور تو گوشم داشتم و تو آب که هنوز می‌لرزید لرزش خورشید را می‌دیدم.
گفت: -بده من، که تشنه‌ی این آبم.
ومن تازه توانستم بفهمم پی چه چیز می‌گشته!
سطل را تا لب‌هایش بالا بردم. با چشم‌های بسته نوشید. آبی بود به شیرینیِ عیدی. این آب به کُلّی چیزی بود سوایِ هرگونه خوردنی. زاییده‌ی راه رفتنِ زیر ستاره‌ها و سرود قرقره و تقلای بازوهای من بود. مثل یک چشم روشنی برای دل خوب بود. پسر بچه که بودم هم، چراغ درخت عید و موسیقیِ نماز نیمه‌شب عید کریسمس و لطف لب‌خنده‌ها عیدیی را که بم می‌دادند درست به همین شکل آن همه جلا و جلوه می‌بخشید.
گفت: -مردم سیاره‌ی تو ور می‌دارند پنج هزار تا گل را تو یک گلستان می‌کارند، و آن یک دانه‌ای را که پِیَش می‌گردند آن وسط پیدا نمی‌کنند...
گفتم: -پیدایش نمی‌کنند.
-با وجود این، چیزی که پیَش می‌گردند ممکن است فقط تو یک گل یا تو یک جرعه آب پیدا بشود...
جواب دادم: -گفت‌وگو ندارد.
باز گفت: -گیرم چشمِ سَر کور است، باید با چشم دل پی‌اش گشت.
من هم سیراب شده بودم. راحت نفس می‌کشیدم. وقتی آفتاب درمی‌آید شن به رنگ عسل است. من هم از این رنگ عسلی لذت می‌بردم. چرا می‌بایست در زحمت باشم...
شهریار کوچولو که باز گرفته بود کنار من نشسته بود با لطف بم گفت: -هِی! قولت قول باشد ها!
-کدام قول؟
-یادت است؟ یک پوزه‌بند برای بَرّه‌ام... آخر من مسئول گلمَم!
طرح‌های اولیه‌ام را از جیب درآوردم. نگاه‌شان کرد و خندان‌خندان گفت: -بائوباب‌هات یک خرده شبیه کلم شده.
ای وای! مرا بگو که آن‌قدر به بائوباب‌هام می‌نازیدم.
-روباهت... گوش‌هاش بیش‌تر به شاخ می‌ماند... زیادی درازند!
و باز زد زیر خنده.
-آقا کوچولو داری بی‌انصافی می‌کنی. من جز بوآهای بسته و بوآهای باز چیزی بلد نبودم بکشم که.
گفت: -خب، مهم نیست. عوضش بچه‌ها سرشان تو حساب است.
با مداد یک پوزه‌بند کشیدم دادم دستش و با دلِ فشرده گفتم:
-تو خیالاتی به سر داری که من ازشان بی‌خبرم...
اما جواب مرا نداد. بم گفت: -می‌دانی؟ فردا سالِ به زمین آمدنِ من است.
بعد پس از لحظه‌ای سکوت دوباره گفت: -همین نزدیکی‌ها پایین آمدم.
و سرخ شد.
و من از نو بی این که بدانم چرا غم عجیبی احساس کردم. با وجود این سوآلی به ذهنم رسید: -پس هشت روز پیش، آن روز صبح که تو تک و تنها هزار میل دورتر از هر آبادی وسطِ کویر به من برخوردی اتفاقی نبود: داشتی برمی‌گشتی به همان جایی که پایین‌آمدی...
دوباره سرخ شد
و من با دودلی به دنبال حرفم گفتم:
-شاید به مناسبت همین سال‌گرد؟...
باز سرخ شد. او هیچ وقت به سوآل‌هایی که ازش می‌شد جواب نمی‌داد اما وقتی کسی سرخ می‌شود معنیش این است که «بله»، مگر نه؟
به‌اش گفتم: -آخر، من ترسم برداشته...
اما او حرفم را برید:
-دیگر تو باید بروی به کارت برسی. باید بروی سراغ موتورت. من همین‌جا منتظرت می‌مانم. فردا عصر برگرد...
منتها من خاطر جمع نبودم. به یاد روباه افتادم: اگر آدم گذاشت اهلیش کنند بفهمی‌نفهمی خودش را به این خطر انداخته که کارش به گریه‌کردن بکشد.
۲۶
کنار چاه دیوارِ سنگی مخروبه‌ای بود. فردا عصر که از سرِ کار برگشتم از دور دیدم که آن بالا نشسته پاها را آویزان کرده،
شهریار کوچولو نشسته بر دیوارِ سنگی و مار در پایینِ آن
و شنیدم که می‌گوید:
-پس یادت نمی‌آید؟ درست این نقطه نبود ها!
لابد صدای دیگری به‌اش جوابی داد، چون شهریار کوچولو در رَدِّ حرفش گفت:
-چرا چرا! روزش که درست همین امروز است گیرم محلش این جا نیست...
راهم را به طرف دیوار ادامه دادم. هنوز نه کسی به چشم خورده بود نه صدای کسی را شنیده بودم اما شهریار کوچولو باز در جواب درآمد که:
-... آره، معلوم است. خودت می‌توانی ببینی رَدِّ پاهایم روی شن از کجا شروع می‌شود.
همان جا منتظرم باش، تاریک که شد می‌آیم.
بیست متری دیوار بودم و هنوز چیزی نمی‌دیدم. پس از مختصر مکثی دوباره گفت:
-زهرت خوب هست؟ مطمئنی درد و زجرم را کِش نمی‌دهد؟
با دل فشرده از راه ماندم اما هنوز از موضوع سر در نیاورده بودم.
گفت: -خب، حالا دیگر برو. دِ برو. می‌خواهم بیایم پایین!
آن وقت من نگاهم را به پایین به پای دیوار انداختم و از جا جستم! یکی از آن مارهای زردی که تو سی ثانیه کَلَکِ آدم را می‌کنند، به طرف شهریار کوچولو قد راست کرده بود. من همان طور که به دنبال تپانچه دست به جیبم می‌بردم پا گذاشتم به دو، اما ماره از سر و صدای من مثل فواره‌ای که بنشیند آرام روی شن جاری شد و بی آن که چندان عجله‌ای از خودش نشان دهد باصدای خفیف فلزی لای سنگ‌ها خزید.
من درست به موقع به دیوار رسیدم و طفلکی شهریار کوچولو را که رنگش مثل برف پریده بود تو هوا بغل کردم.
-این دیگر چه حکایتی است! حالا دیگر با مارها حرف می‌زنی؟
شال زردش را که مدام به گردن داشت باز کردم به شقیقه‌هایش آب زدم و جرعه‌ای به‌اش نوشاندم. اما حالا دیگر اصلا جرات نمی کردم ازش چیزی بپرسم. با وقار به من نگاه کرد و دستش را دور گردنم انداخت. حس کردم قلبش مثل قلب پرنده‌ای می‌زند که تیر خورده‌است و دارد می‌میرد.
گفت: -از این که کم و کسرِ لوازم ماشینت را پیدا کردی خوش‌حالم. حالا می‌توانی برگردی خانه‌ات...
-تو از کجا فهمیدی؟
درست همان دم لب‌واکرده‌بودم بش خبر بدهم که علی‌رغم همه‌ی نومیدی‌ها تو کارم موفق شده‌ام!
به سوآل‌های من هیچ جوابی نداد اما گفت: -آخر من هم امروز بر می‌گردم خانه‌ام...
و بعد غم‌زده درآمد که: -گیرم راه من خیلی دورتر است... خیلی سخت‌تر است...
حس می‌کردم اتفاق فوق‌العاده‌ای دارد می‌افتد. گرفتمش تو بغلم. عین یک بچه‌ی کوچولو. با وجود این به نظرم می‌آمد که او دارد به گردابی فرو می‌رود و برای نگه داشتنش از من کاری ساخته نیست... نگاه متینش به دوردست‌های دور راه کشیده بود.
گفت: بَرِّه‌ات را دارم. جعبه‌هه را هم واسه بره‌هه دارم. پوزه‌بنده را هم دارم.
و با دلِ گرفته لبخندی زد.
مدت درازی صبر کردم. حس کردم کم‌کمَک تنش دوباره دارد گرم می‌شود.
-عزیز کوچولوی من، وحشت کردی...
-امشب وحشت خیلی بیش‌تری چشم به‌راهم است.
دوباره از احساسِ واقعه‌ای جبران ناپذیر یخ زدم. این فکر که دیگر هیچ وقت غش‌غش خنده‌ی او را نخواهم شنید برایم سخت تحمل‌ناپذیر بود. خنده‌ی او برای من به چشمه‌ای در دلِ کویر می‌مانست.
-کوچولوئَکِ من، دلم می‌خواهد باز هم غش‌غشِ خنده‌ات را بشنوم.
اما به‌ام گفت: -امشب درست می‌شود یک سال و اخترَکَم درست بالای همان نقطه‌ای می‌رسد که پارسال به زمین آمدم.
-کوچولوئک، این قضیه‌ی مار و میعاد و ستاره یک خواب آشفته بیش‌تر نیست. مگر نه؟
به سوال من جوابی نداد اما گفت: -چیزی که مهم است با چشمِ سَر دیده نمی‌شود.
-مسلم است.
-در مورد گل هم همین‌طور است: اگر گلی را دوست داشته باشی که تو یک ستاره‌ی دیگر است، شب تماشای آسمان چه لطفی پیدا می‌کند: همه‌ی ستاره‌ها غرق گل می‌شوند!
-مسلم است...
-در مورد آب هم همین‌طور است. آبی که تو به من دادی به خاطر قرقره و ریسمان درست به یک موسیقی می‌مانست... یادت که هست... چه خوب بود.
-مسلم است...
-شب‌به‌شب ستاره‌ها را نگاه می‌کنی. اخترک من کوچولوتر از آن است که بتوانم جایش را نشانت بدهم. اما چه بهتر! آن هم برای تو می‌شود یکی از ستاره‌ها؛ و آن وقت تو دوست داری همه‌ی ستاره‌ها را تماشا کنی... همه‌شان می‌شوند دوست‌های تو... راستی می‌خواهم هدیه‌ای بت بدهم...
و غش غش خندید.
-آخ، کوچولوئک، کوچولوئک! من عاشقِ شنیدنِ این خنده‌ام!
-هدیه‌ی من هم درست همین است... درست مثل مورد آب.
-چی می‌خواهی بگویی؟
-همه‌ی مردم ستاره دارند اما همه‌ی ستاره‌ها یک‌جور نیست: واسه آن‌هایی که به سفر می‌روند حکم راهنما را دارند واسه بعضی دیگر فقط یک مشت روشناییِ سوسوزن‌اند. برای بعضی که اهل دانشند هر ستاره یک معما است واسه آن بابای تاجر طلا بود. اما این ستاره‌ها همه‌شان زبان به کام کشیده و خاموشند. فقط تو یکی ستاره‌هایی خواهی داشت که تنابنده‌ای مِثلش را ندارد.
-چی می‌خواهی بگویی؟
-نه این که من تو یکی از ستاره‌هام؟ نه این که من تو یکی از آن‌ها می‌خندم؟... خب، پس هر شب که به آسمان نگاه می‌کنی برایت مثل این خواهد بود که همه‌ی ستاره‌ها می‌خندند. پس تو ستاره‌هایی خواهی داشت که بلدند بخندند!
و باز خندید.
-و خاطرت که تسلا پیدا کرد (خب بالاخره آدمی‌زاد یک جوری تسلا پیدا می‌کند دیگر) از آشنایی با من خوش‌حال می‌شوی. دوست همیشگی من باقی می‌مانی و دلت می‌خواهد با من بخندی و پاره‌ای وقت‌هام واسه تفریح پنجره‌ی اتاقت را وا می‌کنی... دوستانت از این‌که می‌بینند تو به آسمان نگاه می‌کنی و می‌خندی حسابی تعجب می‌کنند آن وقت تو به‌شان می‌گویی: «آره، ستاره‌ها همیشه مرا خنده می‌اندازند!» و آن‌وقت آن‌ها یقین‌شان می‌شود که تو پاک عقلت را از دست داده‌ای. جان! می‌بینی چه کَلَکی به‌ات زده‌ام...
و باز زد زیر خنده.
-به آن می‌ماند که عوضِ ستاره یک مشت زنگوله بت داده باشم که بلدند بخندند...
دوباره خندید و بعد حالتی جدی به خودش گرفت:
-نه، من تنهات نمی‌گذارم.
شهریار کوچولو تنها
-ظاهر آدمی را پیدا می‌کنم که دارد درد می‌کشد... یک خرده هم مثل آدمی می‌شوم که دارد جان می‌کند. رو هم رفته این جوری‌ها است. نیا که این را نبینی. چه زحمتی است بی‌خود؟
-تنهات نمی‌گذارم.
اندوه‌زده بود.
-این را بیش‌تر از بابت ماره می‌گویم که، نکند یک‌هو تو را هم بگزد. مارها خیلی خبیثند. حتا واسه خنده هم ممکن است آدم را نیش بزنند.
-تنهات نمی‌گذارم.
منتها یک چیز باعث خاطر جمعیش شد:
-گر چه، بار دوم که بخواهند بگزند دیگر زهر ندارند.
شب متوجه راه افتادنش نشدم. بی سر و صدا گریخت.
وقتی خودم را به‌اش رساندم با قیافه‌ی مصمم و قدم‌های محکم پیش می‌رفت. همین قدر گفت: -اِ! این‌جایی؟
و دستم را گرفت.
اما باز بی‌قرار شد وگفت: -اشتباه کردی آمدی. رنج می‌بری. گرچه حقیقت این نیست، اما ظاهرِ یک مرده را پیدا می‌کنم.
من ساکت ماندم.
-خودت درک می‌کنی. راه خیلی دور است. نمی‌توانم این جسم را با خودم ببرم. خیلی سنگین است.
من ساکت ماندم.
-گیرم عینِ پوستِ کهنه‌ای می‌شود که دورش انداخته باشند؛ پوست کهنه که غصه ندارد، ها؟
من ساکت ماندم.
کمی دل‌سرد شد اما باز هم سعی کرد:
-خیلی با مزه می‌شود، نه؟ من هم به ستاره‌ها نگاه می‌کنم. هم‌شان به صورت چاه‌هایی در می‌آیند با قرقره‌های زنگ زده. همه‌ی ستاره‌ها بم آب می‌دهند بخورم...
من ساکت ماندم.
-خیلی با مزه می‌شود. نه؟ تو صاحب هزار کرور زنگوله می‌شوی من صاحب هزار کرور فواره...
او هم ساکت شد، چرا که داشت گریه می‌کرد...
-خب، همین جاست. بگذار چند قدم خودم تنهایی بروم.
و گرفت نشست، چرا که می‌ترسید.
شهریار کوچولو نشسته
می‌دانی؟... گلم را می‌گویم... آخر من مسئولشم. تازه چه قدر هم لطیف است و چه قدر هم ساده و بی‌شیله‌پیله. برای آن که جلو همه‌ی عالم از خودش دفاع کند همه‌اش چی دارد مگر؟ چهارتا خار پِرپِرَک!
من هم گرفتم نشستم. دیگر نمی‌توانستم سر پا بند بشوم.
گفت: -همین... همه‌اش همین و بس...
باز هم کمی دودلی نشان داد اما بالاخره پا شد و قدمی به جلو رفت. من قادر به حرکت نبودم.
کنار قوزکِ پایش جرقه‌ی زردی جست و... فقط همین! یک دم بی‌حرکت ماند. فریادی نزد. مثل درختی که بیفتد آرام‌آرام به زمین افتاد که به وجود شن از آن هم صدایی بلند نشد.
شهریار کوچولو در حالی که آرام‌آرام به زمین می‌افتد
۲۷
شش سال گذشته است و من هنوز بابت این قضیه جایی لب‌ترنکرده‌ام. دوستانم از این که مرا دوباره زنده می‌دیدند سخت شاد شدند. من غم‌زده بودم اما به آن‌ها می‌گفتم اثر خستگی است.
حالا کمی تسلای خاطر پیدا کرده‌ام. یعنی نه کاملا... اما این را خوب می‌دانم که او به اخترکش برگشته. چون آفتاب که زد پیکرش را پیدا نکردم. پیکری هم نبود که چندان وزنی داشته باشد... و شب‌ها دوست دارم به ستاره‌ها گوش بدهم. عین هزار زنگوله‌اند.
اما موضوع خیلی مهمی که هست، من پاک یادم رفت به پوزه‌بندی که برای شهریار کوچولو کشیدم تسمه‌ی چرمی اضافه کنم و او ممکن نیست بتواند آن را به پوزه‌ی بَرّه ببندد. این است که از خودم می‌پرسم: «یعنی تو اخترکش چه اتفاقی افتاده؟ نکند بره‌هه گل را چریده باشد؟...»
گاه به خودم می‌گویم: «حتما نه، شهریار کوچولو هر شب گلش را زیر حباب شیشه‌ای می‌گذارد و هوای بره‌اش را هم دارد...» آن وقت است که خیالم راحت می‌شود و ستاره‌ها همه به شیرینی می‌خندند.
گاه به خودم می‌گویم: «همین کافی است که آدم یک بار حواسش نباشد... آمدیم و یک شب حباب یادش رفت یا بَرّه شب نصف‌شبی بی‌سروصدا از جعبه زد بیرون...» آن وقت است که زنگوله‌ها همه تبدیل به اشک می‌شوند!...
یک راز خیلی خیلی بزرگ این جا هست: برای شما هم که او را دوست دارید، مثل من هیچ چیزِ عالم مهم‌تر از دانستن این نیست که تو فلان نقطه‌ای که نمی‌دانیم، فلان بره‌ای که نمی‌شماسیم گل سرخی را چریده یا نچریده...
خب. آسمان را نگاه کنید و بپرسید: «بَرّه گل را چریده یا نچریده؟» و آن وقت با چشم‌های خودتان تفاوتش را ببینید...
و محال است آدم بزرگ‌ها روح‌شان خبردار بشود که این موضوع چه قدر مهم است!
بدونِ شهریار کوچولو
در نظر من این زیباترین و حزن‌انگیزترین منظره‌ی عالم است. این همان منظره‌ی دو صفحه پیش است گیرم آن را دوباره کشیده‌ام که به‌تر نشان‌تان بدهم: «ظهور شهریار کوچولو بر زمین در این جا بود؛ و بعد در همین جا هم بود که ناپدید شد».
آن قدر به دقت این منظره را نگاه کنید که مطمئن بشوید اگر روزی تو آفریقا گذرتان به کویر صحرا افتاد حتما آن را خواهید شناخت. و اگر پاداد و گذارتان به آن جا افتاد به التماس ازتان می‌خواهم که عجله به خرج ندهید و درست زیر ستاره چند لحظه‌ای توقف کنید. آن وقت اگر بچه‌ای به طرف‌تان آمد، اگر خندید، اگر موهایش طلایی بود، اگر وقتی ازش سوالی کردید جوابی نداد، لابد حدس می‌زنید که کیست. در آن صورت لطف کنید و نگذارید من این جور افسرده خاطر بمانم:
بی درنگ بردارید به من بنویسید که او برگشته.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 == */")

View File

@ -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 == */")

View File

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