Compare commits

..

2 Commits

Author SHA1 Message Date
Behdad Esfahbod 3ce0a9841f [inplace] Adjust 2022-06-08 06:17:27 -06:00
Behdad Esfahbod 204d71514c [layout] Add (back) inplace implementation
This is a forward-port from the (8yr old) accelerate-lookups branch.
The overhead is too high though, so going to abandon it. Posting for
posterity.
2022-06-08 05:46:57 -06:00
727 changed files with 25101 additions and 73000 deletions

View File

@ -2,17 +2,15 @@
set -e
meson --cross-file=.ci/win32-cross-file.txt \
--wrap-mode=default \
--wrap-mode=forcefallback \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dfreetype=enabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
-Dcairo=enabled \
win32build \
$@

View File

@ -2,17 +2,15 @@
set -e
meson --cross-file=.ci/win64-cross-file.txt \
--wrap-mode=default \
--wrap-mode=forcefallback \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dfreetype=enabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
-Dcairo=enabled \
win64build \
$@

View File

@ -3,6 +3,8 @@
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)
@ -15,8 +17,8 @@ cp ../build/docs/html/* .
git init
git branch -m main
git config user.name "CI"
git config user.email "harfbuzz-admin@googlegroups.com"
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"

View File

@ -18,9 +18,9 @@ jobs:
xcode: "12.5.1"
steps:
- checkout
- run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection ninja
- 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 setup build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Ddocs=disabled
- 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:
@ -57,8 +57,8 @@ jobs:
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 setup build --buildtype=debugoptimized
- run: meson compile -Cbuild -j9
- 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 --num-processes=$(($(nproc)/2 + 1))
@ -69,9 +69,24 @@ jobs:
- checkout
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
- run: pip3 install meson==0.56.0
- run: meson setup build --buildtype=minsize
- 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
asan-ubsan:
docker:
@ -81,9 +96,8 @@ jobs:
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: pip3 install meson==0.56.0
- run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
- run: CC=clang CXX=clang++ 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:
docker:
@ -93,9 +107,8 @@ jobs:
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: pip3 install meson==0.56.0
- run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
- run: CC=clang CXX=clang++ 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:
docker:
@ -106,9 +119,8 @@ jobs:
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: pip3 install meson==0.56.0
# msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least
- run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true
- run: meson compile -Cbuild -j9
- run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
- run: CC=clang CXX=clang++ 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
clang-cxx2a:
docker:
@ -117,14 +129,14 @@ jobs:
- checkout
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y clang lld git binutils
- run: clang -c src/harfbuzz-subset.cc -DHB_NO_MT -Werror -std=c++2a
- 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 python3 python3-pip git g++-mingw-w64-i686 zip
- run: pip3 install meson==0.60.0
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools 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
@ -146,8 +158,8 @@ jobs:
executor: win64-executor
steps:
- checkout
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-x86-64 zip
- run: pip3 install meson==0.60.0
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-x86-64 zip
- run: pip3 install meson==0.56.0 --upgrade
- run: bash .ci/build-win64.sh
- store_artifacts:
path: harfbuzz-win64.zip
@ -186,6 +198,7 @@ workflows:
ignore: /.*/
- fedora-valgrind
- alpine
#- archlinux
- asan-ubsan
- tsan
- msan

View File

@ -1,10 +1,8 @@
comment: false
comment: off
coverage:
status:
project:
default:
informational: true
patch:
default:
informational: true
threshold: 1%
patch: off

View File

@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@ -1,25 +0,0 @@
name: arm
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
arm-none-eabi:
runs-on: ubuntu-22.04
container:
image: devkitpro/devkitarm:latest
steps:
- uses: actions/checkout@v3
- name: Configure CMake
run: |
cmake -S . -B build \
-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake
- name: Build
run: make CXX_FLAGS="-w -DHB_NO_MT"
working-directory: build

View File

@ -1,9 +1,5 @@
name: CIFuzz
on: [pull_request]
permissions:
contents: read
jobs:
Fuzzing:
runs-on: ubuntu-latest
@ -21,7 +17,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View File

@ -11,10 +11,10 @@ permissions:
jobs:
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: install dependencies
run: sudo apt-get install gcc
- name: HB_DISABLE_DEPRECATED

View File

@ -11,7 +11,7 @@ jobs:
latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- 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

View File

@ -3,7 +3,6 @@ name: linux-ci
on:
push:
branches: [ main ]
tags: ["*.*.*"]
pull_request:
branches: [ main ]
@ -12,60 +11,46 @@ permissions:
jobs:
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install \
gcc \
gobject-introspection \
gtk-doc-tools \
libcairo2-dev \
libfreetype6-dev \
libgirepository1.0-dev \
libglib2.0-dev \
libgraphite2-dev \
libicu-dev \
ninja-build \
pkg-config \
python3 \
python3-setuptools
- name: Install Python Dependencies
run: sudo pip3 install fonttools meson==0.56.0 gcovr==5.0
- name: Setup Meson
run: |
ccache --version
meson setup build \
-Dauto_features=enabled \
-Dchafa=disabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Db_coverage=true \
-Ddoc_tests=true \
-Dragel_subproject=true
- name: Build
run: meson compile -Cbuild
- name: Test
- uses: actions/checkout@v2
- name: install dependencies
run: sudo apt-get install pkg-config gcc 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.56.0 gcovr==5.0
- name: run
run: meson build -Db_coverage=true --auto-features=enabled -Dgraphite=enabled -Dchafa=disabled -Dragel_subproject=true -Doptimization=2
- name: ci
run: meson test --print-errorlogs -Cbuild
- name: Generate Documentations
- name: generate documentations
run: ninja -Cbuild harfbuzz-doc
- name: Deploy Documentations
if: github.ref_type == 'tag'
- name: deploy documentations
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: .ci/deploy-docs.sh
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
REVISION: ${{ github.sha }}
- name: Generate Coverage
# 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-xml
- name: Upload Coverage
uses: codecov/codecov-action@v3
- uses: codecov/codecov-action@v1
with:
file: build/meson-logs/coverage.xml

View File

@ -11,50 +11,20 @@ permissions:
jobs:
build:
runs-on: macos-latest
runs-on: macos-10.15
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- name: Install Dependencies
run: |
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install \
cairo \
freetype \
glib \
gobject-introspection \
graphite2 \
icu4c \
meson \
ninja \
pkg-config
- name: Install Python Dependencies
run: pip3 install fonttools gcovr==5.0
- name: Setup Meson
run: |
export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig"
ccache --version
meson setup build \
-Dauto_features=enabled \
-Ddocs=disabled \
-Dchafa=disabled \
-Dcoretext=enabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Db_coverage=true \
- name: Build
run: meson compile -Cbuild
- name: Test
- uses: actions/checkout@v2
- name: install dependencies
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config freetype glib cairo icu4c graphite2 gobject-introspection gtk-doc ninja
- run: pip3 install fonttools meson==0.56.0 gcovr==5.0
- name: run
run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Db_coverage=true -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Doptimization=2
- name: ci
run: meson test --print-errorlogs -Cbuild
- name: Generate Coverage
- name: cov
run: ninja -Cbuild coverage-xml
- name: Upload Coverage
uses: codecov/codecov-action@v3
- uses: codecov/codecov-action@v1
with:
file: build/meson-logs/coverage.xml

View File

@ -14,7 +14,6 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-2019, windows-latest]
include:
@ -27,35 +26,33 @@ jobs:
name: ${{ matrix.name }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
variant: sccache
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
with:
arch : ${{ matrix.ARCH }}
- name: Install Python Dependencies
run: |
pip install --upgrade meson ninja fonttools
- name: Setup Meson
run: |
sccache --version
meson setup build `
--wrap-mode=forcefallback `
--buildtype=release `
-Dglib=enabled `
-Dfreetype=enabled `
-Dgdi=enabled `
-Ddirectwrite=enabled
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild
- 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: Upgrade pip
run: |
python -m pip install -U pip
- 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

@ -14,7 +14,6 @@ jobs:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- MSYSTEM: MINGW32
@ -23,51 +22,47 @@ jobs:
MSYS2_ARCH: x86_64
name: ${{ matrix.MSYSTEM }}
env:
# XXX: For some reason enabling jit debugging "fixes" random python crashes
# see https://github.com/msys2/MINGW-packages/issues/11864
MSYS: "winjitdebug"
defaults:
run:
shell: msys2 {0}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup MSYS2
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
- name: Install Python Dependencies
run: |
pip install --upgrade fonttools
- name: Setup Meson
run: |
meson setup build \
--wrap-mode=nodownload \
--auto-features=enabled \
-Ddocs=disabled \
-Ddirectwrite=enabled \
-Dgdi=enabled \
-Dgraphite=enabled \
-Dchafa=disabled
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild
- 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

View File

@ -1,29 +1,28 @@
On Linux, install the development packages for FreeType, Cairo, and GLib. For
example, on Ubuntu / Debian, you would do:
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
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-devel
sudo dnf install meson pkgconfig gtk-doc gcc gcc-c++ freetype-devel glib2-devel cairo-devel
and on ArchLinux and Manjaro:
$ sudo pacman -Suy meson pkg-config ragel gcc freetype2 glib2 cairo
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 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. It is recommended to install CMake either manually
or via the Visual Studio installer when building with MSVC, using meson.
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. It is recommended to install CMake either
manually or via the Visual Studio installer when building with MSVC when building with meson.
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.
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,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.1)
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.")
@ -80,7 +80,6 @@ include (FindPythonInterp)
## Functions and headers
include (CheckFunctionExists)
include (CheckIncludeFile)
include (CheckIncludeFiles)
macro (check_funcs) # Similar to AC_CHECK_FUNCS of autotools
foreach (func_name ${ARGN})
string(TOUPPER ${func_name} definition_to_add)
@ -107,17 +106,12 @@ if (${HAVE_STDBOOL_H})
add_definitions(-DHAVE_STDBOOL_H)
endif ()
# These will be used while making pkg-config .pc files
set(PC_REQUIRES_PRIV "")
set(PC_LIBS_PRIV "")
if (NOT MSVC)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
if (CMAKE_USE_PTHREADS_INIT)
add_definitions("-DHAVE_PTHREAD")
list(APPEND THIRD_PARTY_LIBS Threads::Threads)
list(APPEND PC_LIBS_PRIV -pthread)
endif ()
endif ()
@ -213,10 +207,6 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
endif ()
if (HB_HAVE_FREETYPE)
list(APPEND PC_REQUIRES_PRIV "freetype2 >= 12.0.6")
endif ()
if (HB_HAVE_GRAPHITE2)
add_definitions(-DHAVE_GRAPHITE2)
@ -229,8 +219,6 @@ if (HB_HAVE_GRAPHITE2)
list(APPEND THIRD_PARTY_LIBS ${GRAPHITE2_LIBRARY})
list(APPEND PC_REQUIRES_PRIV "graphite2 >= 1.2.0")
mark_as_advanced(GRAPHITE2_INCLUDE_DIR GRAPHITE2_LIBRARY)
endif ()
@ -251,8 +239,6 @@ if (HB_HAVE_GLIB)
list(APPEND THIRD_PARTY_LIBS ${GLIB_LIBRARIES})
list(APPEND PC_REQUIRES_PRIV "glib-2.0 >= 2.19.1")
mark_as_advanced(GLIB_LIBRARIES GLIBCONFIG_INCLUDE_DIR GLIB_INCLUDE_DIR)
endif ()
@ -285,28 +271,24 @@ if (APPLE AND HB_HAVE_CORETEXT)
find_library(COREFOUNDATION CoreFoundation)
if (COREFOUNDATION)
list(APPEND THIRD_PARTY_LIBS ${COREFOUNDATION})
list(APPEND PC_LIBS_PRIV "-framework CoreFoundation")
endif ()
mark_as_advanced(COREFOUNDATION)
find_library(CORETEXT CoreText)
if (CORETEXT)
list(APPEND THIRD_PARTY_LIBS ${CORETEXT})
list(APPEND PC_LIBS_PRIV "-framework CoreText")
endif ()
mark_as_advanced(CORETEXT)
find_library(COREGRAPHICS CoreGraphics)
if (COREGRAPHICS)
list(APPEND THIRD_PARTY_LIBS ${COREGRAPHICS})
list(APPEND PC_LIBS_PRIV "-framework 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})
list(APPEND PC_LIBS_PRIV "-framework ApplicationServices")
endif ()
mark_as_advanced(APPLICATION_SERVICES_FRAMEWORK)
@ -317,27 +299,18 @@ 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)
list(APPEND PC_LIBS_PRIV -lgdi32)
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)
list(APPEND PC_LIBS_PRIV -lusp10 -lgdi32 -lrpcrt4)
endif ()
if (WIN32 AND HB_HAVE_DIRECTWRITE)
if (CMAKE_VERSION VERSION_GREATER 3.12)
check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H LANGUAGE CXX)
else ()
check_include_files("windows.h;dwrite_1.h" HAVE_DWRITE_1_H)
endif ()
if (NOT HAVE_DWRITE_1_H)
message(FATAL_ERROR "DirectWrite was enabled explicitly, but required header is missing")
endif ()
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)
@ -453,7 +426,7 @@ target_include_directories(harfbuzz PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/harfbuzz>")
if (HB_HAVE_FREETYPE AND TARGET freetype)
target_link_libraries(harfbuzz freetype)
target_link_libraries(harfbuzz PUBLIC freetype)
endif ()
@ -566,7 +539,7 @@ if (HB_HAVE_INTROSPECTION)
# 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}/$<CONFIG>")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
else ()
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
endif ()
@ -720,44 +693,6 @@ if (NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL)
endif ()
endif ()
# get these variables in the required format
list(REMOVE_DUPLICATES PC_REQUIRES_PRIV)
string(REPLACE ";" ", " PC_REQUIRES_PRIV "${PC_REQUIRES_PRIV}")
list(REMOVE_DUPLICATES PC_LIBS_PRIV)
string(REPLACE ";" " " PC_LIBS_PRIV "${PC_LIBS_PRIV}")
# Macro to write pkg-config .pc configuration files
macro ( make_pkgconfig_pc_file name )
file(READ "${PROJECT_SOURCE_DIR}/src/${name}.pc.in" FSTR)
string(REPLACE "%prefix%" "${CMAKE_INSTALL_PREFIX}" FSTR ${FSTR})
string(REPLACE "%exec_prefix%" "\${prefix}" FSTR ${FSTR})
if (IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
string(REPLACE "%includedir%" "${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
else ()
string(REPLACE "%includedir%" "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}" FSTR ${FSTR})
endif ()
if (IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
string(REPLACE "%libdir%" "${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
else ()
string(REPLACE "%libdir%" "\${prefix}/${CMAKE_INSTALL_LIBDIR}" FSTR ${FSTR})
endif ()
string(REPLACE "%VERSION%" "${HB_VERSION}" FSTR ${FSTR})
string(REPLACE "%requires_private%" "${PC_REQUIRES_PRIV}" FSTR ${FSTR})
string(REPLACE "%libs_private%" "${PC_LIBS_PRIV}" FSTR ${FSTR})
file(WRITE "${PROJECT_BINARY_DIR}/${name}.pc" ${FSTR})
install(
FILES "${PROJECT_BINARY_DIR}/${name}.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
COMPONENT pkgconfig
)
endmacro ( make_pkgconfig_pc_file )
if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS harfbuzz
EXPORT harfbuzzConfig
@ -766,7 +701,6 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz")
install(EXPORT harfbuzzConfig
NAMESPACE harfbuzz::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/harfbuzz
@ -778,13 +712,11 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz-icu")
endif ()
if (HB_BUILD_SUBSET)
install(TARGETS harfbuzz-subset
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
make_pkgconfig_pc_file("harfbuzz-subset")
)
endif ()
if (HB_BUILD_UTILS)
if (WIN32 AND BUILD_SHARED_LIBS)
@ -813,10 +745,9 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
make_pkgconfig_pc_file("harfbuzz-gobject")
if (HB_HAVE_INTROSPECTION)
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
else ()
set (hb_libpath "$<TARGET_FILE_DIR:harfbuzz-gobject>")
endif ()

View File

@ -100,14 +100,13 @@ 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. This is defined by the `HB_TINY` profile already
(more below).
(unused) "fallback" shaper.
## Thread-safety
By default HarfBuzz builds as a thread-safe library. The exception is that
the `HB_TINY` predefined configuration (more below) disables thread-safety.
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
@ -141,7 +140,7 @@ configurations from the command-line.
However, configuration can still be overridden from a file. To do that, add your
override instructions (mostly `undef` instructions) to a header file and define
the macro `HB_CONFIG_OVERRIDE_H` to the string containing to that header file's
name. HarfBuzz will then include that file at the appropriate place during
name. HarfBuzz will then include that file at appropriate right place during
configuration.
Up until HarfBuzz 3.1.2 the the configuration override header file's name was
@ -155,4 +154,4 @@ 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, which many clients might not need.
for CFF fonts.

20
COPYING
View File

@ -2,23 +2,19 @@ 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-2022 Google, Inc.
Copyright © 2015-2020 Ebrahim Byagowi
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,2015 Mozilla Foundation
Copyright © 2012 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2011 Martin Hosken and SIL International
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
Copyright © 1998-2005 David Turner and Werner Lemberg
Copyright © 2016 Igalia S.L.
Copyright © 2022 Matthias Clasen
Copyright © 2018,2021 Khaled Hosny
Copyright © 2018,2019,2020 Adobe, Inc
Copyright © 2013-2015 Alexei Podtelezhnikov
Copyright © 2005,2006,2020,2021 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.

View File

@ -25,6 +25,7 @@ EXTRA_DIST = \
subprojects/google-benchmark.wrap \
subprojects/ragel.wrap \
subprojects/packagefiles/ragel/meson.build \
subprojects/ttf-parser.wrap \
mingw-configure.sh \
$(NULL)

359
NEWS
View File

@ -1,362 +1,3 @@
Overview of changes leading to 7.1.0
Friday, March 3, 2023
====================================
- New experimental hb_shape_justify() API that uses font variations to expand
or shrink the text to a given advance. (Behdad Esfahbod)
- Various build and bug fixes. (Behdad Esfahbod, Garret Rieger, Qunxin Liu)
- New API:
+hb_font_set_variation()
Overview of changes leading to 7.0.1
Monday, February 20, 2023
====================================
- Various build and bug fixes.
Overview of changes leading to 7.0.0
Saturday, February 11, 2023
====================================
- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be
also used as a unified API to paint any of the glyph representations
supported by HarfBuzz (B/W outlines, color layers, or color bitmaps).
(Behdad Esfahbod, Matthias Clasen)
- New hb-cairo API for integrating with cairo graphics library. This is provided
as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen)
- Support for instancing “CFF2” table. (Behdad Esfahbod)
- Support font emboldening. (Behdad Esfahbod)
- Support feature ranges with AAT shaping. (Behdad Esfahbod)
- Experimental support to cubic curves in “glyf” table, see
https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md
for spec. (Behdad Esfahbod)
- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
- Various documentation improvements.
(Behdad Esfahbod, Matthias Clasen, Khaled Hosny)
- Significantly reduced memory use during shaping. (Behdad Esfahbod)
- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod)
- New command line utility, hb-info, for querying various font information.
(Behdad Esfahbod, Matthias Clasen)
- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold,
--font-grade, and --named-instance. (Behdad Esfahbod)
- Miscellaneous fixes and improvements.
(Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan,
Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen,
Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich)
- New API:
+HB_FONT_NO_VAR_NAMED_INSTANCE
+HB_PAINT_IMAGE_FORMAT_BGRA
+HB_PAINT_IMAGE_FORMAT_PNG
+HB_PAINT_IMAGE_FORMAT_SVG
+hb_cairo_font_face_create_for_face
+hb_cairo_font_face_create_for_font
+hb_cairo_font_face_get_face
+hb_cairo_font_face_get_font
+hb_cairo_font_face_get_scale_factor
+hb_cairo_font_face_set_font_init_func
+hb_cairo_font_face_set_scale_factor
+hb_cairo_font_init_func_t
+hb_cairo_glyphs_from_buffer
+hb_cairo_scaled_font_get_font
+hb_color_line_get_color_stops
+hb_color_line_get_color_stops_func_t
+hb_color_line_get_extend
+hb_color_line_get_extend_func_t
+hb_color_line_t
+hb_color_stop_t
+hb_draw_funcs_get_empty
+hb_draw_funcs_get_user_data
+hb_draw_funcs_set_user_data
+hb_face_collect_nominal_glyph_mapping
+hb_font_draw_glyph
+hb_font_draw_glyph_func_t
+hb_font_funcs_set_draw_glyph_func
+hb_font_funcs_set_paint_glyph_func
+hb_font_get_synthetic_bold
+hb_font_get_var_named_instance
+hb_font_paint_glyph
+hb_font_paint_glyph_func_t
+hb_font_set_synthetic_bold
+hb_map_keys
+hb_map_next
+hb_map_update
+hb_map_values
+hb_ot_color_glyph_has_paint
+hb_ot_color_has_paint
+hb_ot_layout_script_select_language2
+hb_ot_name_id_predefined_t
+hb_paint_color
+hb_paint_color_func_t
+hb_paint_composite_mode_t
+hb_paint_custom_palette_color
+hb_paint_custom_palette_color_func_t
+hb_paint_extend_t
+hb_paint_funcs_create
+hb_paint_funcs_destroy
+hb_paint_funcs_get_empty
+hb_paint_funcs_get_user_data
+hb_paint_funcs_is_immutable
+hb_paint_funcs_make_immutable
+hb_paint_funcs_reference
+hb_paint_funcs_set_color_func
+hb_paint_funcs_set_custom_palette_color_func
+hb_paint_funcs_set_image_func
+hb_paint_funcs_set_linear_gradient_func
+hb_paint_funcs_set_pop_clip_func
+hb_paint_funcs_set_pop_group_func
+hb_paint_funcs_set_pop_transform_func
+hb_paint_funcs_set_push_clip_glyph_func
+hb_paint_funcs_set_push_clip_rectangle_func
+hb_paint_funcs_set_push_group_func
+hb_paint_funcs_set_push_transform_func
+hb_paint_funcs_set_radial_gradient_func
+hb_paint_funcs_set_sweep_gradient_func
+hb_paint_funcs_set_user_data
+hb_paint_funcs_t
+hb_paint_image
+hb_paint_image_func_t
+hb_paint_linear_gradient
+hb_paint_linear_gradient_func_t
+hb_paint_pop_clip
+hb_paint_pop_clip_func_t
+hb_paint_pop_group
+hb_paint_pop_group_func_t
+hb_paint_pop_transform
+hb_paint_pop_transform_func_t
+hb_paint_push_clip_glyph
+hb_paint_push_clip_glyph_func_t
+hb_paint_push_clip_rectangle
+hb_paint_push_clip_rectangle_func_t
+hb_paint_push_group
+hb_paint_push_group_func_t
+hb_paint_push_transform
+hb_paint_push_transform_func_t
+hb_paint_radial_gradient
+hb_paint_radial_gradient_func_t
+hb_paint_sweep_gradient
+hb_paint_sweep_gradient_func_t
+hb_set_is_inverted
+hb_subset_input_keep_everything
- Deprecated API:
+hb_font_funcs_set_glyph_shape_func
+hb_font_get_glyph_shape_func_t
+hb_font_get_glyph_shape
Overview of changes leading to 6.0.0
Friday, December 16, 2022
====================================
- A new API have been added to pre-process the face and speed up future
subsetting operations on that face. Provides up to a 95% reduction in
subsetting times when the same face is subset more than once.
For more details and benchmarks, see:
https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md
(Garret Rieger, Behdad Esfahbod)
- Shaping have been speedup by skipping entire lookups when the buffer contents
don't intersect with the lookup. Shows up to a 10% speedup in shaping some
fonts. (Behdad Esfahbod)
- A new experimental feature, “Variable Composites” (enabled by passing
-Dexperimental_api=true to meson), is also featured in this release.
This technology enables drastic compression of fonts in the Chinese,
Japanese, Korean, and other writing systems, by reusing the OpenType Font
Variations technology for encoding “smart components” into the font.
The specification for these extensions to the font format can be found in:
https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md
A test variable-font with ~7160 Hangul syllables derived from the
NotoSerifKR-VF font has been built, with existing OpenType technology, as
well as with the new Variable Composites (VarComposites) technology. The
VarComposites font is over 90% smaller than the OpenType version of the font!
Both fonts can be obtained from the “smarties” repository:
https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif
When building HarfBuzz with experimental features enabled, you can test
the “smarties” font with a sample character like this:
$ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700
(Behdad Esfahbod)
- The HarfBuzz subsetter can now drop axes by pinning them to specific values
(also referred to as instancing). There are a couple of restrictions
currently:
- Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet
supported.
- Only supports the case where all axes in a font are pinned.
(Garret Rieger, Qunxin Liu)
- Miscellaneous fixes and improvements.
(Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret
Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg,
Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik)
- New API
+hb_subset_input_pin_axis_location()
+hb_subset_input_pin_axis_to_default()
+hb_subset_preprocess()
Overview of changes leading to 5.3.1
Wednesday, October 19, 2022
====================================
- Subsetter repacker fixes. (Garret Rieger)
- Adjust Grapheme clusters for Katakana voiced sound marks. (Behdad Esfahbod)
- New “hb-subset” option “--preprocess-face”. (Garret Rieger)
Overview of changes leading to 5.3.0
Saturday, October 8, 2022
"Women, Life, Freedom" #MahsaAmini
====================================
- Dont add glyphs from dropped MATH or COLR tables to the subset glyphs.
(Khaled Hosny)
- Map “rlig” to appropriate AAT feature selectors. (Jonathan Kew)
- Update USE data files to latest version. (David Corbett)
- Check “CBDT” extents first before outline tables, to help with fonts that
also include an empty “glyf” table. (Khaled Hosny)
- More work towards variable font instancing in the subsetter. (Qunxin Liu)
- Subsetter repacker improvements. (Garret Rieger)
- New API:
+hb_ot_layout_lookup_get_optical_bound()
+hb_face_builder_sort_tables()
Overview of changes leading to 5.2.0
Saturday, September 17, 2022
====================================
- Fix regressions in hb-ft font functions for FT_Faces with transformation
matrix. (Behdad Esfahbod)
- The experimental hb-repacker API now supports splitting several GPOS subtable
types when needed. (Garret Rieger)
- The HarfBuzz extensions to OpenType font format are now opt-in behind
build-time flags. (Behdad Esfahbod)
- The experimental hb-subset variable fonts instantiation API can now
instantiate more font tables and arbitrary axis locations. (Qunxin Liu)
- Unicode 15 support. (David Corbett)
- Various documentation improvements. (Behdad Esfahbod, Matthias Clasen)
- The hb-view command line tool now detects WezTerm inline images support.
(Wez Furlong)
- Fix FreeType and ICU dependency lookup with meson. (Xavier Claessens)
- New API:
+HB_SCRIPT_KAWI
+HB_SCRIPT_NAG_MUNDARI
Overview of changes leading to 5.1.0
Sunday, July 31, 2022
====================================
- More extensive buffer tracing messages. (Behdad Esfahbod)
- Fix hb-ft regression in bitmap fonts rendering. (Behdad Esfahbod)
- Support extension promotion of lookups in hb-subset-repacker. (Garret Rieger)
- A new HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL for scripts that use elongation
(e.g. Arabic) to signify where it is safe to insert tatweel glyph without
interrupting shaping. (Behdad Esfahbod)
- Add “--safe-to-insert-tatweel” to “hb-shape” tool. (Behdad Esfahbod)
- New API
+HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
+HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL
Overview of changes leading to 5.0.1
Saturday, July 23, 2022
====================================
- Fix version 2 “avar” table with hb-ft. (Behdad Esfahbod)
Overview of changes leading to 5.0.0
Saturday, July 23, 2022
====================================
- Support fonts with more than 65535 glyphs in “GDEF”, “GSUB”, and “GPOS”
tables. This is part of https://github.com/be-fonts/boring-expansion-spec to
extend OpenType in a backward-compatible way.
(Behdad Esfahbod, Garret Rieger)
- Complete support for more than 65535 glyphs in “glyf” table that started in
4.0.0 release. Part of boring-expansion-spec. (Behdad Esfahbod)
- Support version 2 of “avar” table. Part of boring-expansion-spec.
(Behdad Esfahbod)
- Fix mark attachment on multiple substitutions in some cases.
(Behdad Esfahbod)
- Fix application of “calt”, “rclt”, and “ccmp” features to better match
Uniscribe behaviour with some Arabic fonts. (Behdad Esfahbod)
- Improvement to interaction between multiple cursive attachments.
(Behdad Esfahbod)
- Improve multiple mark interactions in Hebrew. (Behdad Esfahbod)
- Implement language-specific forms in AAT shaping. (Behdad Esfahbod)
- Fix variation of “VORG” table. (Behdad Esfahbod)
- Support for specific script tags to be retained in the subsetter, and add
“--layout-scripts” option to “hb-subset” tool. (Garret Rieger)
- Accept space as delimiter for --features/--variations in command line tools.
- Improve subsetting of “COLR” table. (Qunxin Liu)
- Improved fuzzing coverage for ot-math API. (Frédéric Wang)
- Fix “kern” table version 2 (AAT) sanitization on 32-bit systems.
(Behdad Esfahbod)
- Allow negative glyph advances from “graphite2” shaper. (Stephan Bergmann)
- Implement loading (color) bitmap fonts with hb-ft. (Behdad Esfahbod)
- Fix regression in hb-ft when changing font size. (Behdad Esfahbod)
- Fix build on GCC < 7. (Kleis Auke Wolthuizen)
- Dynamically load dwrite.dll on windows if “directwrite” shaper is enabled.
(Luca Bacci)
- Provide a single-file harfbuzz-subset.cc file for easier alternate building
of hb-subset library, similar to harfbuzz.cc. (Khaled Hosny)
- New API
+HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG
+hb_language_matches()
Overview of changes leading to 4.4.1
Wednesday, June 29, 2022
====================================
- Fix test failure with some compilers.
- Fix Telugu and Kannada kerning regression.
Overview of changes leading to 4.4.0
Monday, June 27, 2022
====================================
- Caching of variable fonts shaping, in particular when using HarfBuzzs own
font loading functions (ot). Bringing performance of variable shaping in par
with non-variable fonts shaping. (Behdad Esfahbod)
- Caching of format 2 “Contextual Substitution” and “Chained Contexts
Substitution” lookups. Resulting in up to 20% speedup of lookup-heavy fonts
like Gulzar or Noto Nastaliq Urdu. (Behdad Esfahbod)
- Improved ANSI output from hb-view. (Behdad Esfahbod)
- Support for shaping legacy, pre-OpenType Windows 3.1-era, Arabic fonts that
relied on a fixed PUA encoding. (Khaled Hosny, Behdad Esfahbod)
- Sinhala script is now shaped by the USE shaper instead of “indic” one.
(Behdad Esfahbod, David Corbett)
- Thai shaper improvements. (David Corbett)
- hb-ot-name API supports approximate BCP-47 language matching, for example
asking for “en_US” in a font that has only “en” names will return them.
(Behdad Esfahbod)
- Optimized TrueType glyph shape loading. (Behdad Esfahbod)
- Fix subsetting of HarfBuzz faces created via hb_face_create_for_tables().
(Garret Rieger)
- Add 32 bit var store support to the subsetter. (Garret Rieger)
- New API
+HB_BUFFER_FLAG_DEFINED
+HB_BUFFER_SERIALIZE_FLAG_DEFINED
+hb_font_changed()
+hb_font_get_serial()
+hb_ft_hb_font_changed()
+hb_set_hash()
+hb_map_copy()
+hb_map_hash()
Overview of changes leading to 4.3.0
Friday, May 20, 2022
====================================

View File

@ -29,12 +29,6 @@ for reference.
- 32bit: `../mingw-configure.sh i686`
- 64bit: `../mingw-configure.sh x86_64`
c) Build as usual:
- make
d) Configure your wine to find system mingw libraries. See:
https://fedoraproject.org/wiki/MinGW/Configure_wine
Now you can use `hb-shape` by `(cd win32build/util && wine hb-shape.exe)`
but if you like to shape with the Microsoft Uniscribe:
@ -51,8 +45,3 @@ but if you like to shape with the Microsoft Uniscribe:
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)
When you have built that, you can test HarfBuzz's native shaper against Uniscribe
following these instructions:
https://github.com/harfbuzz/harfbuzz/issues/3671

View File

@ -17,7 +17,7 @@
- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
- [ ] Search for REPLACEME on the repository and replace it with the chosen version for the release.
- [ ] Make sure you have correct date and new version at the top of NEWS file.

View File

@ -1,20 +0,0 @@
# Security Policy
If you have discovered a security vulnerability in this project, please report it
privately. **Do not disclose it as a public issue.** This gives me time to work with you
to fix the issue before public exposure, reducing the chance that the exploit will be
used before a patch is released.
You may submit the report in the following ways:
- send an email to behdad@behdad.org and harfbuzz-admin@googlegroups.com; and/or
- send me a [private vulnerability report](https://github.com/harfbuzz/harfbuzz/security/advisories/new)
Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
This project is mostly maintained by two developers, working on a reasonable effort
basis. As such, we ask that you give us 90 days to work on a fix before public
disclosure.

View File

@ -39,7 +39,11 @@ ninja -C build
## Test with the Fuzzer
FOr fuzzing, see `test/fuzzing/README.md`.
```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

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.64])
AC_INIT([HarfBuzz],
[7.1.0],
[4.3.0],
[https://github.com/harfbuzz/harfbuzz/issues/new],
[harfbuzz],
[http://harfbuzz.org/])
@ -45,7 +45,7 @@ AC_SUBST(HB_VERSION)
# Libtool version
m4_define([hb_version_int],
m4_eval(60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro))
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)
@ -308,7 +308,7 @@ 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 FT_Get_Transform)
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)
@ -366,13 +366,17 @@ AC_ARG_WITH(directwrite,
have_directwrite=false
AC_LANG_PUSH([C++])
if test "x$with_directwrite" = "xyes" -o "x$with_directwrite" = "xauto"; then
AC_CHECK_HEADERS(dwrite_1.h, have_directwrite=true)
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)

View File

@ -29,7 +29,7 @@ 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|HB_DEPRECATED_FOR()'
--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

View File

@ -219,7 +219,7 @@ notes [fontname="Verdana",shape=box,label=<<table border="0" cellborder="0" cell
<b>Indic</b> scripts are: Bengali, Devanagari,
Gujarati, Gurmukhi, Kannada,
Malayalam, Oriya, Tamil,
Telugu
Telugu, Sinhala
</td></tr>
<tr><td align="left">
@ -240,7 +240,7 @@ Mongolian, Multani, Nandinagari, Newa, Nko, Nyiakeng Puachue Hmong,
Old Sogdian, Pahawh Hmong, Phags Pa, Psalter Pahlavi, Rejang,
</td></tr>
<tr><td align="left">
Saurashtra, Sharada, Siddham, Sinhala, Sogdian, Soyombo, Sundanese,
Saurashtra, Sharada, Siddham, Sogdian, Soyombo, Sundanese,
Syloti Nagri, Tagalog, Tagbanwa, Tai Le, Tai Tham, Tai Viet,
</td></tr>
<tr><td align="left">

View File

@ -56,9 +56,7 @@
<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-features.xml"/>
<xi:include href="xml/hb-draw.xml"/>
<xi:include href="xml/hb-paint.xml"/>
<xi:include href="xml/hb-deprecated.xml"/>
<xi:include href="xml/hb-face.xml"/>
<xi:include href="xml/hb-font.xml"/>
@ -98,7 +96,6 @@
<xi:include href="xml/hb-uniscribe.xml"/>
<xi:include href="xml/hb-gdi.xml"/>
<xi:include href="xml/hb-directwrite.xml"/>
<xi:include href="xml/hb-cairo.xml"/>
</chapter>
<chapter id="style-api">
@ -118,79 +115,73 @@
</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"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.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-7-1-0"><title>Index of new symbols in 7.1.0</title><xi:include href="xml/api-index-7.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-7-0-0"><title>Index of new symbols in 7.0.0</title><xi:include href="xml/api-index-7.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-6-0-0"><title>Index of new symbols in 6.0.0</title><xi:include href="xml/api-index-6.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-5-3-0"><title>Index of new symbols in 5.3.0</title><xi:include href="xml/api-index-5.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-5-0-0"><title>Index of new symbols in 5.0.0</title><xi:include href="xml/api-index-5.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-4-0"><title>Index of new symbols in 4.4.0</title><xi:include href="xml/api-index-4.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-3-0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-2-0"><title>Index of new symbols in 4.2.0</title><xi:include href="xml/api-index-4.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-1-0"><title>Index of new symbols in 4.1.0</title><xi:include href="xml/api-index-4.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-0-0"><title>Index of new symbols in 4.0.0</title><xi:include href="xml/api-index-4.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-4-0"><title>Index of new symbols in 3.4.0</title><xi:include href="xml/api-index-3.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-3-0"><title>Index of new symbols in 3.3.0</title><xi:include href="xml/api-index-3.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-1-0"><title>Index of new symbols in 3.1.0</title><xi:include href="xml/api-index-3.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-0-0"><title>Index of new symbols in 3.0.0</title><xi:include href="xml/api-index-3.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-1"><title>Index of new symbols in 2.9.1</title><xi:include href="xml/api-index-2.9.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-0"><title>Index of new symbols in 2.9.0</title><xi:include href="xml/api-index-2.9.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-8-2"><title>Index of new symbols in 2.8.2</title><xi:include href="xml/api-index-2.8.2.xml"><xi:fallback /></xi:include></index>
<index id="api-index-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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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-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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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>
<index id="api-index-4-3-0" role="4.3.0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-2-0" role="4.2.0"><title>Index of new symbols in 4.2.0</title><xi:include href="xml/api-index-4.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-1-0" role="4.1.0"><title>Index of new symbols in 4.1.0</title><xi:include href="xml/api-index-4.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-4-0-0" role="4.0.0"><title>Index of new symbols in 4.0.0</title><xi:include href="xml/api-index-4.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-4-0" role="3.4.0"><title>Index of new symbols in 3.4.0</title><xi:include href="xml/api-index-3.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-3-0" role="3.3.0"><title>Index of new symbols in 3.3.0</title><xi:include href="xml/api-index-3.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-1-0" role="3.1.0"><title>Index of new symbols in 3.1.0</title><xi:include href="xml/api-index-3.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-3-0-0" role="3.0.0"><title>Index of new symbols in 3.0.0</title><xi:include href="xml/api-index-3.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-1" role="2.9.1"><title>Index of new symbols in 2.9.1</title><xi:include href="xml/api-index-2.9.1.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-9-0" role="2.9.0"><title>Index of new symbols in 2.9.0</title><xi:include href="xml/api-index-2.9.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-2-8-2" role="2.8.2"><title>Index of new symbols in 2.8.2</title><xi:include href="xml/api-index-2.8.2.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-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 stable
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.

View File

@ -1,4 +1,3 @@
<SECTION>
<SUBSECTION Private>
HB_H_IN
HB_OT_H_IN
@ -27,33 +26,33 @@ hb_blob_create_from_file
hb_blob_create_from_file_or_fail
hb_blob_create_sub_blob
hb_blob_copy_writable_or_fail
hb_blob_get_empty
hb_blob_reference
hb_blob_destroy
hb_blob_set_user_data
hb_blob_get_user_data
hb_blob_make_immutable
hb_blob_is_immutable
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_allocation_successful
hb_buffer_create_similar
hb_buffer_get_empty
hb_buffer_reference
hb_buffer_get_empty
hb_buffer_destroy
hb_buffer_set_user_data
hb_buffer_get_user_data
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
@ -80,14 +79,15 @@ 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_glyph_info_get_glyph_flags
hb_buffer_get_glyph_positions
hb_buffer_has_positions
hb_buffer_set_invisible_glyph
hb_buffer_get_invisible_glyph
hb_buffer_set_not_found_glyph
hb_buffer_set_invisible_glyph
hb_buffer_get_not_found_glyph
hb_buffer_set_not_found_glyph
hb_buffer_set_replacement_codepoint
hb_buffer_get_replacement_codepoint
hb_buffer_normalize_glyphs
@ -106,11 +106,9 @@ hb_segment_properties_equal
hb_segment_properties_hash
hb_segment_properties_overlay
hb_buffer_diff
hb_buffer_message_func_t
hb_buffer_set_message_func
HB_SEGMENT_PROPERTIES_DEFAULT
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT
hb_buffer_t
hb_glyph_info_get_glyph_flags
hb_glyph_info_t
hb_glyph_flags_t
hb_glyph_position_t
@ -121,30 +119,22 @@ 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
HB_UNTAG
hb_tag_from_string
hb_tag_to_string
hb_direction_from_string
hb_direction_to_string
HB_DIRECTION_REVERSE
HB_DIRECTION_IS_BACKWARD
HB_DIRECTION_IS_FORWARD
HB_DIRECTION_IS_HORIZONTAL
HB_DIRECTION_IS_VALID
HB_DIRECTION_IS_VERTICAL
hb_script_from_iso15924_tag
hb_script_to_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_language_matches
hb_feature_from_string
hb_feature_to_string
hb_variation_from_string
@ -161,9 +151,17 @@ 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
@ -180,35 +178,20 @@ uint16_t
uint32_t
uint64_t
uint8_t
<SUBSECTION Private>
HB_EXTERN
HB_DEPRECATED
HB_DEPRECATED_FOR
</SECTION>
<SECTION>
<FILE>hb-features</FILE>
HB_HAS_CAIRO
HB_HAS_CORETEXT
HB_HAS_DIRECTWRITE
HB_HAS_FREETYPE
HB_HAS_GDI
HB_HAS_GLIB
HB_HAS_GOBJECT
HB_HAS_GRAPHITE
HB_HAS_ICU
HB_HAS_UNISCRIBE
</SECTION>
<SECTION>
<FILE>hb-draw</FILE>
hb_draw_funcs_t
hb_draw_funcs_create
hb_draw_funcs_get_empty
hb_draw_funcs_reference
hb_draw_funcs_destroy
hb_draw_funcs_set_user_data
hb_draw_funcs_get_user_data
hb_draw_funcs_make_immutable
hb_draw_funcs_reference
hb_draw_funcs_is_immutable
hb_draw_funcs_make_immutable
hb_draw_move_to_func_t
hb_draw_funcs_set_move_to_func
hb_draw_line_to_func_t
@ -219,79 +202,13 @@ hb_draw_cubic_to_func_t
hb_draw_funcs_set_cubic_to_func
hb_draw_close_path_func_t
hb_draw_funcs_set_close_path_func
hb_draw_state_t
HB_DRAW_STATE_DEFAULT
hb_draw_move_to
hb_draw_line_to
hb_draw_quadratic_to
hb_draw_cubic_to
hb_draw_close_path
HB_DRAW_STATE_DEFAULT
hb_draw_funcs_t
hb_draw_state_t
</SECTION>
<SECTION>
<FILE>hb-paint</FILE>
hb_paint_funcs_t
hb_paint_funcs_create
hb_paint_funcs_get_empty
hb_paint_funcs_reference
hb_paint_funcs_destroy
hb_paint_funcs_set_user_data
hb_paint_funcs_get_user_data
hb_paint_funcs_make_immutable
hb_paint_funcs_is_immutable
hb_paint_push_transform_func_t
hb_paint_funcs_set_push_transform_func
hb_paint_pop_transform_func_t
hb_paint_funcs_set_pop_transform_func
hb_paint_push_clip_glyph_func_t
hb_paint_funcs_set_push_clip_glyph_func
hb_paint_push_clip_rectangle_func_t
hb_paint_funcs_set_push_clip_rectangle_func
hb_paint_pop_clip_func_t
hb_paint_funcs_set_pop_clip_func
hb_paint_color_func_t
hb_paint_funcs_set_color_func
HB_PAINT_IMAGE_FORMAT_PNG
HB_PAINT_IMAGE_FORMAT_SVG
HB_PAINT_IMAGE_FORMAT_BGRA
hb_paint_image_func_t
hb_paint_funcs_set_image_func
hb_color_line_t
hb_color_stop_t
hb_color_line_get_color_stops_func_t
hb_color_line_get_color_stops
hb_paint_extend_t
hb_color_line_get_extend_func_t
hb_color_line_get_extend
hb_paint_linear_gradient_func_t
hb_paint_funcs_set_linear_gradient_func
hb_paint_radial_gradient_func_t
hb_paint_funcs_set_radial_gradient_func
hb_paint_sweep_gradient_func_t
hb_paint_funcs_set_sweep_gradient_func
hb_paint_composite_mode_t
hb_paint_push_group_func_t
hb_paint_funcs_set_push_group_func
hb_paint_pop_group_func_t
hb_paint_funcs_set_pop_group_func
hb_paint_custom_palette_color_func_t
hb_paint_funcs_set_custom_palette_color_func
hb_paint_push_transform
hb_paint_pop_transform
hb_paint_push_clip_glyph
hb_paint_push_clip_rectangle
hb_paint_pop_clip
hb_paint_color
hb_paint_image
hb_paint_linear_gradient
hb_paint_radial_gradient
hb_paint_sweep_gradient
hb_paint_push_group
hb_paint_pop_group
hb_paint_custom_palette_color
</SECTION>
<SECTION>
@ -338,6 +255,8 @@ hb_coretext_font_get_ct_font
<FILE>hb-directwrite</FILE>
hb_directwrite_face_create
hb_directwrite_face_get_font_face
<SUBSECTION Private>
hb_directwrite_shape_experimental_width
</SECTION>
<SECTION>
@ -346,29 +265,27 @@ hb_face_count
hb_face_t
hb_face_create
hb_face_create_for_tables
hb_face_get_empty
hb_face_reference
hb_face_destroy
hb_face_set_user_data
hb_face_get_user_data
hb_face_make_immutable
hb_face_is_immutable
hb_face_get_empty
hb_face_get_table_tags
hb_face_set_glyph_count
hb_face_get_glyph_count
hb_face_set_index
hb_face_get_index
hb_face_set_upem
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_nominal_glyph_mapping
hb_face_collect_variation_selectors
hb_face_collect_variation_unicodes
hb_face_builder_create
hb_face_builder_add_table
hb_face_builder_sort_tables
</SECTION>
<SECTION>
@ -376,126 +293,118 @@ hb_face_builder_sort_tables
hb_font_add_glyph_origin_for_direction
hb_font_create
hb_font_create_sub_font
hb_font_get_empty
hb_font_reference
hb_font_destroy
hb_font_set_user_data
hb_font_get_user_data
hb_font_make_immutable
hb_font_is_immutable
hb_font_set_face
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_shape_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_v_advance
hb_font_get_glyph_h_advance_func_t
hb_font_get_glyph_h_advances
hb_font_get_glyph_v_advances
hb_font_get_glyph_h_advances_func_t
hb_font_get_glyph_h_kerning
hb_font_get_glyph_kerning_for_direction
hb_font_get_glyph_h_kerning_func_t
hb_font_get_glyph_h_origin
hb_font_get_glyph_v_origin
hb_font_get_glyph_origin_for_direction
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_shape
hb_font_draw_glyph
hb_font_paint_glyph
hb_font_get_glyph_shape_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_variation_glyph
hb_font_set_parent
hb_font_get_nominal_glyphs_func_t
hb_font_get_parent
hb_font_set_ppem
hb_font_get_ppem
hb_font_set_ptem
hb_font_get_ptem
hb_font_set_scale
hb_font_get_scale
hb_font_get_synthetic_bold
hb_font_set_synthetic_bold
hb_font_set_synthetic_slant
hb_font_get_synthetic_slant
hb_font_set_variations
hb_font_set_variation
HB_FONT_NO_VAR_NAMED_INSTANCE
hb_font_set_var_named_instance
hb_font_get_var_named_instance
hb_font_set_var_coords_design
hb_font_get_user_data
hb_font_get_variation_glyph
hb_font_get_variation_glyph_func_t
hb_font_get_var_coords_design
hb_font_set_var_coords_normalized
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_get_serial
hb_font_changed
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_synthetic_slant
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_funcs_create
hb_font_funcs_get_empty
hb_font_funcs_reference
hb_font_funcs_destroy
hb_font_funcs_set_user_data
hb_font_funcs_get_user_data
hb_font_funcs_make_immutable
hb_font_funcs_is_immutable
hb_font_get_glyph_contour_point_func_t
hb_font_funcs_set_glyph_contour_point_func
hb_font_get_glyph_extents_func_t
hb_font_funcs_set_glyph_extents_func
hb_font_get_glyph_from_name_func_t
hb_font_funcs_set_glyph_from_name_func
hb_font_get_glyph_advance_func_t
hb_font_get_glyph_h_advance_func_t
hb_font_funcs_set_glyph_h_advance_func
hb_font_get_glyph_v_advance_func_t
hb_font_funcs_set_glyph_v_advance_func
hb_font_get_glyph_advances_func_t
hb_font_get_glyph_h_advances_func_t
hb_font_funcs_set_glyph_h_advances_func
hb_font_get_glyph_v_advances_func_t
hb_font_funcs_set_glyph_v_advances_func
hb_font_get_glyph_kerning_func_t
hb_font_get_glyph_h_kerning_func_t
hb_font_funcs_set_glyph_h_kerning_func
hb_font_get_glyph_origin_func_t
hb_font_get_glyph_h_origin_func_t
hb_font_funcs_set_glyph_h_origin_func
hb_font_get_glyph_v_origin_func_t
hb_font_funcs_set_glyph_v_origin_func
hb_font_get_glyph_name_func_t
hb_font_funcs_set_glyph_name_func
hb_font_get_glyph_shape_func_t
hb_font_funcs_set_glyph_shape_func
hb_font_draw_glyph_func_t
hb_font_funcs_set_draw_glyph_func
hb_font_paint_glyph_func_t
hb_font_funcs_set_paint_glyph_func
hb_font_get_nominal_glyph_func_t
hb_font_funcs_set_nominal_glyph_func
hb_font_get_nominal_glyphs_func_t
hb_font_funcs_set_nominal_glyphs_func
hb_font_get_variation_glyph_func_t
hb_font_funcs_set_variation_glyph_func
hb_font_funcs_t
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_funcs_set_font_h_extents_func
hb_font_get_font_v_extents_func_t
hb_font_funcs_set_font_v_extents_func
hb_font_get_h_extents
hb_font_get_v_extents
hb_font_get_extents_for_direction
hb_font_extents_t
hb_glyph_extents_t
<SUBSECTION Private>
hb_font_get_var_coords_design
hb_font_draw_glyph
</SECTION>
<SECTION>
@ -512,7 +421,6 @@ hb_ft_font_unlock_face
hb_ft_font_set_load_flags
hb_ft_font_get_load_flags
hb_ft_font_set_funcs
hb_ft_hb_font_changed
</SECTION>
<SECTION>
@ -544,33 +452,30 @@ hb_icu_script_to_script
<SECTION>
<FILE>hb-map</FILE>
hb_map_create
hb_map_allocation_successful
hb_map_copy
hb_map_clear
hb_map_get_empty
hb_map_reference
hb_map_destroy
hb_map_set_user_data
hb_map_get_user_data
hb_map_set
hb_map_get
hb_map_del
hb_map_has
hb_map_get_population
hb_map_is_empty
hb_map_is_equal
hb_map_hash
hb_map_update
hb_map_next
hb_map_keys
hb_map_values
HB_MAP_VALUE_INVALID
hb_map_allocation_successful
hb_map_clear
hb_map_copy
hb_map_create
hb_map_del
hb_map_destroy
hb_map_get
hb_map_get_empty
hb_map_get_population
hb_map_is_equal
hb_map_get_user_data
hb_map_has
hb_map_hash
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
@ -580,19 +485,16 @@ 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_paint
hb_ot_color_glyph_has_paint
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
hb_color_t
hb_ot_color_layer_t
hb_ot_color_palette_flags_t
</SECTION>
<SECTION>
@ -602,21 +504,35 @@ hb_ot_font_set_funcs
<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
hb_ot_name_id_t
hb_ot_name_id_predefined_t
hb_ot_name_entry_t
</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
@ -631,6 +547,7 @@ 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
@ -640,14 +557,12 @@ 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_get_optical_bound
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_script_select_language2
hb_ot_layout_table_find_feature_variations
hb_ot_layout_table_get_feature_tags
hb_ot_layout_table_get_script_tags
@ -655,25 +570,18 @@ 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
HB_OT_MAX_TAGS_PER_LANGUAGE
HB_OT_MAX_TAGS_PER_SCRIPT
HB_OT_TAG_DEFAULT_LANGUAGE
HB_OT_TAG_DEFAULT_SCRIPT
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_glyph_class_t
</SECTION>
<SECTION>
<FILE>hb-ot-math</FILE>
HB_OT_TAG_MATH
HB_OT_TAG_MATH_SCRIPT
hb_ot_math_constant_t
hb_ot_math_kern_t
hb_ot_math_kern_entry_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
@ -684,31 +592,23 @@ 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
HB_OT_TAG_MATH
HB_OT_TAG_MATH_SCRIPT
hb_ot_math_constant_t
hb_ot_math_kern_t
hb_ot_math_kern_entry_t
hb_ot_math_glyph_variant_t
hb_ot_math_glyph_part_flags_t
hb_ot_math_glyph_part_t
</SECTION>
<SECTION>
<FILE>hb-ot-meta</FILE>
hb_ot_meta_tag_t
hb_ot_meta_get_entry_tags
hb_ot_meta_reference_entry
hb_ot_meta_tag_t
</SECTION>
<SECTION>
<FILE>hb-ot-metrics</FILE>
hb_ot_metrics_tag_t
hb_ot_metrics_get_position
hb_ot_metrics_get_position_with_fallback
hb_ot_metrics_get_variation
hb_ot_metrics_get_x_variation
hb_ot_metrics_get_y_variation
hb_ot_metrics_tag_t
</SECTION>
<SECTION>
@ -718,7 +618,14 @@ hb_ot_shape_glyphs_closure
<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
@ -728,44 +635,31 @@ 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
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_axis_flags_t
hb_ot_var_axis_info_t
</SECTION>
<SECTION>
<FILE>hb-set</FILE>
hb_set_create
hb_set_allocation_successful
hb_set_copy
hb_set_get_empty
hb_set_reference
hb_set_destroy
hb_set_set_user_data
hb_set_get_user_data
hb_set_clear
hb_set_set
hb_set_has
HB_SET_VALUE_INVALID
hb_set_add
hb_set_add_range
hb_set_add_sorted_array
hb_set_allocation_successful
hb_set_copy
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_is_empty
hb_set_get_user_data
hb_set_has
hb_set_hash
hb_set_subtract
hb_set_intersect
hb_set_union
hb_set_symmetric_difference
hb_set_invert
hb_set_is_inverted
hb_set_is_empty
hb_set_is_equal
hb_set_is_subset
hb_set_next
@ -773,15 +667,19 @@ hb_set_next_range
hb_set_next_many
hb_set_previous
hb_set_previous_range
HB_SET_VALUE_INVALID
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_justify
hb_shape_list_shapers
</SECTION>
@ -791,50 +689,50 @@ hb_shape_plan_create
hb_shape_plan_create_cached
hb_shape_plan_create2
hb_shape_plan_create_cached2
hb_shape_plan_get_empty
hb_shape_plan_reference
hb_shape_plan_destroy
hb_shape_plan_set_user_data
hb_shape_plan_get_user_data
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_general_category
hb_unicode_combining_class
hb_unicode_mirroring
hb_unicode_script
hb_unicode_compose
hb_unicode_decompose
hb_unicode_funcs_create
hb_unicode_funcs_get_empty
hb_unicode_funcs_reference
hb_unicode_funcs_destroy
hb_unicode_funcs_set_user_data
hb_unicode_funcs_get_user_data
hb_unicode_funcs_make_immutable
hb_unicode_funcs_is_immutable
hb_unicode_funcs_get_default
hb_unicode_funcs_get_parent
hb_unicode_general_category_func_t
hb_unicode_funcs_set_general_category_func
hb_unicode_combining_class_func_t
hb_unicode_funcs_set_combining_class_func
hb_unicode_mirroring_func_t
hb_unicode_funcs_set_mirroring_func
hb_unicode_script_func_t
hb_unicode_funcs_set_script_func
hb_unicode_compose_func_t
hb_unicode_funcs_set_compose_func
hb_unicode_decompose_func_t
hb_unicode_funcs_set_decompose_func
HB_UNICODE_MAX
hb_unicode_combining_class
hb_unicode_combining_class_func_t
hb_unicode_combining_class_t
hb_unicode_general_category_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>
@ -846,13 +744,13 @@ hb_uniscribe_font_get_logfontw
<SECTION>
<FILE>hb-version</FILE>
HB_VERSION_ATLEAST
hb_version
hb_version_atleast
hb_version_string
HB_VERSION_MAJOR
HB_VERSION_MICRO
HB_VERSION_MINOR
HB_VERSION_STRING
hb_version
hb_version_atleast
hb_version_string
</SECTION>
<SECTION>
@ -863,19 +761,20 @@ hb_style_get_value
<SECTION>
<FILE>hb-subset</FILE>
hb_subset_flags_t
hb_subset_input_t
hb_subset_sets_t
hb_subset_plan_t
hb_subset_input_create_or_fail
hb_subset_input_reference
hb_subset_input_destroy
hb_subset_input_set_user_data
hb_subset_input_get_user_data
hb_subset_input_keep_everything
hb_subset_input_set_flags
hb_subset_input_get_flags
hb_subset_input_set_flags
hb_subset_input_unicode_set
hb_subset_input_glyph_set
hb_subset_input_set
hb_subset_input_pin_axis_location
hb_subset_input_pin_axis_to_default
hb_subset_or_fail
hb_subset_plan_create_or_fail
hb_subset_plan_reference
@ -886,28 +785,8 @@ hb_subset_plan_execute_or_fail
hb_subset_plan_unicode_to_old_glyph_mapping
hb_subset_plan_new_to_old_glyph_mapping
hb_subset_plan_old_to_new_glyph_mapping
hb_subset_preprocess
hb_subset_flags_t
hb_subset_input_t
hb_subset_sets_t
hb_subset_plan_t
<SUBSECTION Private>
hb_link_t
hb_object_t
hb_subset_repack_or_fail
hb_subset_input_override_name_table
</SECTION>
<SECTION>
<FILE>hb-cairo</FILE>
hb_cairo_font_face_create_for_font
hb_cairo_font_face_get_font
hb_cairo_font_face_create_for_face
hb_cairo_font_face_get_face
hb_cairo_font_init_func_t
hb_cairo_font_face_set_font_init_func
hb_cairo_scaled_font_get_font
hb_cairo_font_face_set_scale_factor
hb_cairo_font_face_get_scale_factor
hb_cairo_glyphs_from_buffer
</SECTION>

View File

@ -1,3 +1,8 @@
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()
@ -36,7 +41,6 @@ html_images = [
]
ignore_headers = [
'hb-features.h',
'hb-gobject.h',
'hb-gobject-enums.h',
'hb-gobject-enums-tmp.h',
@ -49,7 +53,7 @@ gnome.gtkdoc('harfbuzz',
meson.current_build_dir() / '..' / 'src',
],
scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED',
'--ignore-decorators=HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()',
'--ignore-decorators=HB_EXTERN|HB_DEPRECATED',
],
mkdb_args: ['--source-suffixes=h,cc',
'--xml-mode',
@ -59,6 +63,4 @@ gnome.gtkdoc('harfbuzz',
html_assets: html_images,
ignore_headers: ignore_headers,
dependencies: [libharfbuzz_dep],
install: true,
check: get_option('doc_tests'),
)
install: true)

View File

@ -23,11 +23,11 @@ Offset overflows can happen for a variety of reasons and require different strat
for more flexibility in the ordering.
* In GSUB/GPOS overflows from Lookup subtables can be resolved by changing the Lookup to an extension
lookup which uses a 32 bit offset instead of 16 bit offset.
In general there isn't a simple solution to produce an optimal topological ordering for a given graph.
Finding an ordering which doesn't overflow is a NP hard problem. Existing solutions use heuristics
which attempt a combination of the above strategies to attempt to find a non-overflowing configuration.
The harfbuzz subsetting library
[includes a repacking algorithm](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh)
which is used to resolve offset overflows that are present in the subsetted tables it produces. This
@ -47,22 +47,16 @@ There's four key pieces to the harfbuzz approach:
* [Topological sorting algorithm](https://en.wikipedia.org/wiki/Topological_sorting): an algorithm
which given a graph gives a linear sorting of the nodes such that all offsets will be positive.
* Overflow check: given a graph and a topological sorting it checks if there will be any overflows
in any of the offsets. If there are overflows it returns a list of (parent, child) tuples that
will overflow. Since the graph has information on the size of each subtable it's straightforward
to calculate the final position of each subtable and then check if any offsets to it will
overflow.
* Content Aware Preprocessing: if the overflow resolver is aware of the format of the underlying
tables (eg. GSUB, GPOS) then in some cases preprocessing can be done to increase the chance of
successfully packing the graph. For example for GSUB and GPOS we can preprocess the graph and
promote lookups to extension lookups (upgrades a 16 bit offset to 32 bits) or split large lookup
subtables into two or more pieces.
* Offset resolution strategies: given a particular occurrence of an overflow these strategies
modify the graph to attempt to resolve the overflow.
# High Level Algorithm
```
@ -70,7 +64,6 @@ def repack(graph):
graph.topological_sort()
if (graph.will_overflow())
preprocess(graph)
assign_spaces(graph)
graph.topological_sort()
@ -92,7 +85,7 @@ The harfbuzz repacker uses two different algorithms for topological sorting:
Kahn's algorithm is approximately twice as fast as the shortest distance sort so that is attempted
first (only on the first topological sort). If it fails to eliminate overflows then shortest distance
sort will be used for all subsequent topological sorting operations.
## Shortest Distance Sort
This algorithm orders the nodes based on total distance to each node. Nodes with a shorter distance
@ -120,7 +113,7 @@ operations:
* The number of incoming edges to each node is cached. This is required by the Kahn's algorithm
portion of both sorts. Where possible when the graph is modified we manually update the cached
edge counts of affected nodes.
* The distance to each node is cached. Where possible when the graph is modified we manually update
the cached distances of any affected nodes.
@ -192,37 +185,6 @@ The assign_spaces() step in the high level algorithm is responsible for identify
subgraphs and assigning unique spaces to each one. More information on the space assignment can be
found in the next section.
# Graph Preprocessing
For certain table types we can preprocess and modify the graph structure to reduce the occurences
of overflows. Currently the repacker implements preprocessing only for GPOS and GSUB tables.
## GSUB/GPOS Table Splitting
The GSUB/GPOS preprocessor scans each lookup subtable and determines if the subtable's children are
so large that no overflow resolution is possible (for example a single subtable that exceeds 65kb
cannot be pointed over). When such cases are detected table splitting is invoked:
* The subtable is first analyzed to determine the smallest number of split points that will allow
for successful offset overflow resolution.
* Then the subtable in the graph representation is modified to actually perform the split at the
previously computed split points. At a high level splits are done by inserting new subtables
which contain a subset of the data of the original subtable and then shrinking the original subtable.
Table splitting must be aware of the underlying format of each subtable type and thus needs custom
code for each subtable type. Currently subtable splitting is only supported for GPOS subtable types.
## GSUB/GPOS Extension Lookup Promotion
In GSUB/GPOS tables lookups can be regular lookups which use 16 bit offsets to the children subtables
or extension lookups which use 32 bit offsets to the children subtables. If the sub graph of all
regular lookups is too large then it can be difficult to find an overflow free configuration. This
can be remedied by promoting one or more regular lookups to extension lookups.
During preprocessing the graph is scanned to determine the size of the subgraph of regular lookups.
If the graph is found to be too big then the analysis finds a set of lookups to promote to reduce
the subgraph size. Lastly the graph is modified to convert those lookups to extension lookups.
# Offset Resolution Strategies
@ -242,13 +204,13 @@ and then assign each such subgraph to a unique non-zero space. The algorithm is
a. Pick a node `n` in set `S` then perform an undirected graph traversal and find the set `Q` of
nodes that are reachable from `n`.
b. During traversal if a node, `m`, has a edge to a node in space 0 then `m` must be duplicated
to disconnect it from space 0.
d. Remove all nodes in `Q` from `S` and assign all nodes in `Q` to `next_space`.
c. Increment `next_space` by one.
@ -264,31 +226,40 @@ of the overflowing link:
* If the overflowing offset is pointing to a subtable with more than one incoming edge: duplicate
the node so that the overflowing offset is pointing at it's own copy of that node.
* Otherwise, attempt to move the child subtable closer to it's parent. This is accomplished by
raising the priority of all children of the parent. Next time the topological sort is run the
children will be ordered closer to the parent.
# Test Cases
The harfbuzz repacker has tests defined using generic graphs: https://github.com/harfbuzz/harfbuzz/blob/main/src/test-repacker.cc
# Future Improvements
Currently for GPOS tables the repacker implementation is sufficient to handle both subsetting and the
general case of font compilation repacking. However for GSUB the repacker is only sufficient for
subsetting related overflows. To enable general case repacking of GSUB, support for splitting of
GSUB subtables will need to be added. Other table types such as COLRv1 shouldn't require table
splitting due to the wide use of 24 bit offsets throughout the table.
The above resolution strategies are not sufficient to resolve all overflows. For example consider
the case where a single subtable is 65k and the graph structure requires an offset to point over it.
Beyond subtable splitting there are a couple of "nice to have" improvements, but these are not required
to support the general case:
* Extension demotion: currently extension promotion is supported but in some cases if the non-extension
subgraph is underfilled then packed size can be reduced by demoting extension lookups back to regular
lookups.
The current harfbuzz implementation is suitable for the vast majority of subsetting related overflows.
Subsetting related overflows are typically easy to solve since all subsets are derived from a font
that was originally overflow free. A more general purpose version of the algorithm suitable for font
creation purposes will likely need some additional offset resolution strategies:
* Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
should use a heuristic (based on parent and child subtable sizes) to decide if the children's
priority should be increased or the parent's priority decreased.
* Many subtables can be split into two smaller subtables without impacting the overall functionality.
This should be done when an overflow is the result of a very large table which can't be moved
to avoid offsets pointing over it.
* Lookup subtables in GSUB/GPOS can be upgraded to extension lookups which uses a 32 bit offset.
Overflows from a Lookup subtable to it's child should be resolved by converting to an extension
lookup.
Once additional resolution strategies are added to the algorithm it's likely that we'll need to
switch to using a [backtracking algorithm](https://en.wikipedia.org/wiki/Backtracking) to explore
the various combinations of resolution strategies until a non-overflowing combination is found. This
will require the ability to restore the graph to an earlier state. It's likely that using a stack
of undoable resolution commands could be used to accomplish this.

View File

@ -1,228 +0,0 @@
# Introduction
Subset preprocessing is a mechanism which can significantly speed up font subsetting operations.
It works by prepopulating datastructures from the source font which can be used in later subsetting
operations to more quickly produce the subset. Preprocessing is useful in cases where multiple subsets
will be cut from the same source font.
# Usage
```c++
hb_face_t* preprocessed = hb_subset_preprocess (source_face);
...
hb_face_t* subset = hb_subset_or_fail (preprocessed, subset_input);
```
# Additional Details
* A subset produced from a preprocessed face should be identical to a subset produced from only the
original face. The preprocessor does not change the functionality of the subsetter, just speeds
things up.
* The preprocessing operation may take longer than the time it takes to produce a subset from the
source font. Thus the main performance gains are made when a preprocessed face is reused for
multiple subsetting operations.
* Currently the largest performance gains are seen when using a preprocessed face for CFF subsetting.
* The preprocessed face may contain references to the memory backing the source face. If this memory
is fully owned by a harfbuzz hb_blob_t* then it will automatically be kept alive for the lifetime
of the preprocessed face. However, if this memory is not fully owned by a harfbuzz hb_blob_t* then
it is necessary to ensure that the memory is kept alive for the lifetime of the preprocessed face.
# Performance Improvements
Here is the performance difference of producing a subset with a preprocessed face vs producing
a subset with the source face:
Benchmark | Delta Time (%)
----------|-----------------
BM_subset/subset_glyphs/Roboto-Regular.ttf/10_median|-56%
BM_subset/subset_glyphs/Roboto-Regular.ttf/64_median|-33%
BM_subset/subset_glyphs/Roboto-Regular.ttf/512_median|-28%
BM_subset/subset_glyphs/Roboto-Regular.ttf/1000_median|-11%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/10_median|-56%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/64_median|-33%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/512_median|-21%
BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/1000_median|-9%
BM_subset/subset_glyphs/Amiri-Regular.ttf/10_median|-67%
BM_subset/subset_glyphs/Amiri-Regular.ttf/64_median|-48%
BM_subset/subset_glyphs/Amiri-Regular.ttf/512_median|-21%
BM_subset/subset_glyphs/Amiri-Regular.ttf/4096_median|-9%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/10_median|-66%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/64_median|-50%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/512_median|-8%
BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/4096_median|-9%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/10_median|-85%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/64_median|-71%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/512_median|-3%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/1400_median|4%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-84%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-72%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|0%
BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|0%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/10_median|-30%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/64_median|-24%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/512_median|-3%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/1000_median|-3%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-30%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-3%
BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|-5%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10_median|-96%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/64_median|-90%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/512_median|-74%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/4096_median|-25%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10000_median|-23%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10_median|-95%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/64_median|-90%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/512_median|-73%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/4096_median|-24%
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10000_median|-11%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10_median|-84%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/64_median|-77%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/512_median|-70%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/4096_median|-80%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10000_median|-86%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10_median|-84%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/64_median|-78%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/512_median|-71%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86%
BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/10_median|-59%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/64_median|-55%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/512_median|-67%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/2000_median|-68%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/10_median|-60%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/64_median|-58%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/512_median|-72%
BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/2000_median|-71%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/10_median|-70%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/64_median|-64%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/300_median|-73%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/10_median|-71%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/64_median|-68%
BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/300_median|-72%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/10_median|-90%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/64_median|-82%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/512_median|-31%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/4096_median|-9%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/6000_median|-22%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/10_median|-88%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/64_median|-83%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/512_median|-31%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/4096_median|-16%
BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/6000_median|-18%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/10_median|-44%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/64_median|-18%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/512_median|-2%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/900_median|-6%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/10_median|-45%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/64_median|-17%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/512_median|-15%
BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/900_median|-3%
BM_subset/subset_codepoints/Roboto-Regular.ttf/10_median|-20%
BM_subset/subset_codepoints/Roboto-Regular.ttf/64_median|-16%
BM_subset/subset_codepoints/Roboto-Regular.ttf/512_median|-12%
BM_subset/subset_codepoints/Roboto-Regular.ttf/1000_median|-10%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/10_median|-24%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/64_median|-14%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/512_median|-15%
BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/1000_median|-9%
BM_subset/subset_codepoints/Amiri-Regular.ttf/10_median|-51%
BM_subset/subset_codepoints/Amiri-Regular.ttf/64_median|-37%
BM_subset/subset_codepoints/Amiri-Regular.ttf/512_median|-12%
BM_subset/subset_codepoints/Amiri-Regular.ttf/4096_median|-1%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/10_median|-49%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/64_median|-35%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/512_median|-6%
BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/4096_median|-1%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/10_median|-82%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/64_median|-9%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/512_median|0%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/1400_median|0%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-82%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-13%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|-3%
BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|2%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/10_median|-40%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/64_median|-26%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/512_median|-5%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/1000_median|3%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-43%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-2%
BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|2%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10_median|-83%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/64_median|-67%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/512_median|-39%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/4096_median|-20%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10000_median|-25%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10_median|-83%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/64_median|-65%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/512_median|-42%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/4096_median|-34%
BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10000_median|-21%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10_median|-69%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/64_median|-69%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/512_median|-70%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/4096_median|-84%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10000_median|-83%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10_median|-71%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/64_median|-68%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/512_median|-70%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86%
BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/10_median|-45%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/64_median|-48%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/512_median|-57%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/2000_median|-66%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/10_median|-43%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/64_median|-50%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/512_median|-63%
BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/2000_median|-72%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/10_median|-69%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/64_median|-66%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/300_median|-74%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/10_median|-70%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/64_median|-71%
BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/300_median|-75%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/10_median|-66%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/64_median|-46%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/512_median|-15%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/4096_median|-5%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/6000_median|-16%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/10_median|-66%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/64_median|-45%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/512_median|-14%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/4096_median|-11%
BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/6000_median|-27%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/10_median|-38%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/64_median|-9%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/512_median|-3%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/900_median|-16%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/10_median|-39%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/64_median|-12%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/512_median|-4%
BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/900_median|-2%
BM_subset/instance/MPLUS1-Variable.ttf/10_median|-68%
BM_subset/instance/MPLUS1-Variable.ttf/64_median|-45%
BM_subset/instance/MPLUS1-Variable.ttf/512_median|-18%
BM_subset/instance/MPLUS1-Variable.ttf/4096_median|-2%
BM_subset/instance/MPLUS1-Variable.ttf/6000_median|4%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/10_median|-69%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/64_median|-46%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/512_median|-11%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/4096_median|4%
BM_subset/instance/MPLUS1-Variable.ttf/nohinting/6000_median|-5%
BM_subset/instance/RobotoFlex-Variable.ttf/10_median|-34%
BM_subset/instance/RobotoFlex-Variable.ttf/64_median|-12%
BM_subset/instance/RobotoFlex-Variable.ttf/512_median|6%
BM_subset/instance/RobotoFlex-Variable.ttf/900_median|-6%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/10_median|-33%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/64_median|-11%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/512_median|3%
BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/900_median|0%

View File

@ -182,7 +182,8 @@
</para>
<itemizedlist>
<listitem>
<para><emphasis>Level 0</emphasis> is the default.
<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
@ -193,7 +194,7 @@
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.
point from <emphasis>different</emphasis> category.
</para>
<para>
In essence, whenever a base character is followed by a mark
@ -205,11 +206,6 @@
url="https://www.unicode.org/reports/tr29/#Regex_Definitions">Unicode
Technical Report 29</ulink>.
</para>
<para>
This cluster level is suitable for code that likes to use
HarfBuzz cluster values as an approximation of the Unicode
Grapheme Cluster Boundaries as well.
</para>
<para>
Client programs can specify level 0 behavior for a buffer by
setting its <literal>cluster_level</literal> to
@ -224,13 +220,13 @@
implement backward compatibility with the old HarfBuzz.
</para>
<para>
<emphasis>Level 1</emphasis> differs from level 0 by not merging the
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, coloring
mark glyphs differently than their base).
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
@ -246,7 +242,7 @@
</para>
<para>
This difference can be seen most clearly when HarfBuzz processes
ligature substitutions and glyph decompositions. In level 0
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.
@ -263,7 +259,7 @@
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).
0,1,2,3,4).
</para>
<para>
It is not <emphasis>required</emphasis> that the cluster values
@ -318,7 +314,7 @@
</listitem>
</itemizedlist>
</section>
<section id="a-clustering-example-for-levels-0-and-1">
<title>A clustering example for levels 0 and 1</title>
<para>

View File

@ -55,7 +55,7 @@
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 more variation-axis settings (or a
you may need to specify one or variation-axis settings (or a
named instance) in order to get the output you need.
</para>
<para>
@ -256,18 +256,6 @@
<para>
<function>hb_font_get_glyph_from_name_func_t</function>: returns
the glyph index that corresponds to a given glyph name.
</para>
</listitem>
<listitem>
<para>
<function>hb_font_draw_glyph_func_t</function>: gets the outlines
of a glyph (by calling #hb_draw_funcs_t callbacks).
</para>
</listitem>
<listitem>
<para>
<function>hb_font_paint_glyph_func_t</function>: paints a glyph
(by calling #hb_paint_funcs_t callbacks).
</para>
</listitem>
</itemizedlist>
@ -387,6 +375,20 @@
</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>
@ -453,66 +455,13 @@
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.
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>
<para>
In addition to providing the variation axes themselves, fonts may also
pre-define certain variation coordinates as named instances. HarfBuzz
makes these coordinates (and their associated names) available via
<function>hb_ot_var_named_instance_get_design_coords()</function> and
<function>hb_ot_var_named_instance_get_subfamily_name_id()</function>.
</para>
<para>
Applications should treat named instances like multiple independent,
static fonts.
</para>
</section>
<section id="glyphs-and-rendering">
<title>Glyphs and rendering</title>
<para>
The main purpose of HarfBuzz is shaping, which creates a list of positioned
glyphs as output. The remaining task for text layout is to convert this list
into rendered output. While HarfBuzz does not handle rasterization of glyphs
per se, it does have APIs that provide access to the font data that is needed
to perform this task.
</para>
<para>
Traditionally, the shapes of glyphs in scalable fonts are provided as quadratic
or cubic Beziér curves defining outlines to be filled. To obtain the outlines
for a glyph, call <function>hb_font_draw_glyph()</function> and pass a
<type>hb_draw_funcs_t</type> struct. The callbacks in that struct will be called
for each segment of the outline. Note that this API provides access to outlines
as they are defined in the font, without applying hinting to fit the curves
to the pixel grid.
</para>
<para>
Fonts may provide pre-rendered images for glyphs instead of or in addition to
outlines. This is most common for fonts that contain colored glyphs, such as
Emoji. To access these images, use <function>hb_ot_color_reference_png()</function>
or <function>hb_ot_color_reference_svg()</function>.
</para>
<para>
Another way in which fonts provide colored glyphs is via paint graphs that
combine glyph outlines with gradients and allow for transformations and
compositing. In its simplest form, this can be presented as a series of
layers that are rendered on top of each other, each with its own color.
HarfBuzz has the <function>hb_ot_color_glyph_get_layers()</function> to
access glyph data in this form.
</para>
<para>
In the general case, you have to use <function>hb_font_paint_glyph()</function>
and pass a <type>hb_paint_funcs_t</type> struct with callbacks to obtain paint
graphs for glyphs that have them. The <function>hb_font_paint_glyph()</function>
API can handle outline and image glyphs as well, so it provides a unified API for
access to glyph rendering information.
</para>
</section>
</chapter>

View File

@ -174,9 +174,7 @@
<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. These functions
make it easy for clients that use FreeType for rasterization
or font-loading, to use HarfBuzz for shaping. To use the
virtual-method structure of a font object. To use the
FreeType-integration API, include the
<filename>hb-ft.h</filename> header.
</para>
@ -310,49 +308,7 @@
it when it is unneeded.
</para>
</section>
<section id="integration-cairo">
<title>Cairo integration</title>
<para>
Cairo is a 2D graphics library that is frequently used together
with GTK and Pango. Cairo supports rendering text using FreeType, or
by using callback-based 'user fonts'.
</para>
<para>
HarfBuzz provides integration points with cairo for fonts as well as
for buffers. To use the Cairo-integration API, link against libharfbuzz-cairo,
and include the <filename>hb-cairo.h</filename> header. For easy buildsystem
integration, HarfBuzz comes with a <filename>harfbuzz-cairo.pc</filename>
pkg-config file.
</para>
<para>
To create a <type>cairo_scaled_font_t</type> font from a HarfBuzz
<type>hb_font_t</type>, you can use <function>hb_cairo_font_face_create_for_font()</function>
or <function>hb_cairo_font_face_create_for_face()</function>. The former API
applies variations and synthetic slant from the <type>hb_font_t</type> when
rendering, the latter takes them from the <type>cairo_font_options_t</type>
that were passed when creating the <type>cairo_scaled_font_t</type>.
</para>
<para>
The Cairo fonts created in this way make use of Cairo's user-font facilities.
They can be used to render on any Cairo context, and provide full support for
font rendering features, including color. One current limitation of the
implementation is that it does not support hinting for glyph outlines.
</para>
<para>
When using color fonts with this API, the color palette index is taken from
the <type>cairo_font_options_t</type> (with new enough Cairo), and the foreground
color is extracted from the source of the Cairo context.
</para>
<para>
To render the results of shaping a piece of text, use
<function>hb_cairo_glyphs_from_buffer()</function> to obtain the glyphs in
a form that can be passed to <function>cairo_show_text_glyphs()</function> or
<function>cairo_show_glyphs()</function>.
</para>
</section>
<section id="integration-uniscribe">
<title>Uniscribe integration</title>
<para>

View File

@ -237,7 +237,7 @@
<para>
The <emphasis>Indic</emphasis> shaping model handles the Indic
scripts Bengali, Devanagari, Gujarati, Gurmukhi, Kannada,
Malayalam, Oriya, Tamil, and Telugu.
Malayalam, Oriya, Tamil, Telugu, and Sinhala.
</para>
<para>
The Indic shaping model was revised significantly in

View File

@ -237,7 +237,8 @@
<listitem>
<para>
Indic (covering Devanagari, Bengali, Gujarati,
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, and Telugu)
Gurmukhi, Kannada, Malayalam, Oriya, Tamil, Telugu, and
Sinhala)
</para>
</listitem>
<listitem>

View File

@ -7,11 +7,11 @@
<shortdesc xml:lang="en">Text shaping library</shortdesc>
<homepage
rdf:resource="https://github.com/harfbuzz/harfbuzz" />
rdf:resource="http://harfbuzz.org/" />
<mailing-list
rdf:resource="https://github.com/harfbuzz/harfbuzz/discussions" />
<download-page
rdf:resource="https://github.com/harfbuzz/harfbuzz/releases" />
rdf:resource="http://lists.freedesktop.org/mailman/listinfo/harfbuzz" />
<!--download-page
rdf:resource=""/-->
<bug-database
rdf:resource="https://github.com/harfbuzz/harfbuzz/issues" />

View File

@ -1,9 +1,8 @@
project('harfbuzz', 'c', 'cpp',
meson_version: '>= 0.55.0',
version: '7.1.0',
version: '4.3.0',
default_options: [
'cpp_eh=none', # Just to support msvc, we are passing -fno-exceptions also anyway
'cpp_rtti=false', # 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
],
@ -15,25 +14,30 @@ hb_version_minor = hb_version_arr[1].to_int()
hb_version_micro = hb_version_arr[2].to_int()
# libtool versioning
hb_version_int = 60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro
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_argument_syntax() == 'msvc'
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']
# disable exception handling
add_project_arguments(['/EHs-', '/EHc-'], language: 'cpp')
endif
add_project_link_arguments(cpp.get_supported_link_arguments([
@ -79,72 +83,25 @@ check_funcs = [
m_dep = cpp.find_library('m', required: false)
if meson.version().version_compare('>=0.60.0')
# pkg-config: freetype2, cmake: Freetype
freetype_dep = dependency('freetype2', 'Freetype',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
else
# painful hack to handle multiple dependencies but also respect options
freetype_opt = get_option('freetype')
# we want to handle enabled manually after fallbacks, but also handle disabled normally
if freetype_opt.enabled()
freetype_opt = false
endif
# try pkg-config name
freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt)
# when disabled, leave it not-found
if not freetype_dep.found() and not get_option('freetype').disabled()
# Try cmake name
freetype_dep = dependency('Freetype', method: 'cmake', required: false)
# Subproject fallback, `allow_fallback: true` means the fallback will be
# tried even if the freetype option is set to `auto`.
if not freetype_dep.found()
freetype_dep = dependency('freetype2',
method: 'pkg-config',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
endif
endif
endif
# https://github.com/harfbuzz/harfbuzz/pull/2498
freetype_dep = dependency(cpp.get_argument_syntax() == 'msvc' ? 'freetype' : 'freetype2',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'])
glib_dep = dependency('glib-2.0', required: get_option('glib'))
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
graphite_dep = dependency('graphite2', required: get_option('graphite'))
if meson.version().version_compare('>=0.60.0')
# pkg-config: icu-uc, cmake: ICU but with components
icu_dep = dependency('icu-uc', 'ICU',
components: 'uc',
required: get_option('icu'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
if cpp.get_argument_syntax() == 'msvc'
icu_dep = dependency('ICU',
required: get_option('icu'),
components: 'uc',
method: 'cmake')
else
# painful hack to handle multiple dependencies but also respect options
icu_opt = get_option('icu')
# we want to handle enabled manually after fallbacks, but also handle disabled normally
if icu_opt.enabled()
icu_opt = false
endif
# try pkg-config name
icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt)
# when disabled, leave it not-found
if not icu_dep.found() and not get_option('icu').disabled()
# Try cmake name
icu_dep = dependency('ICU', method: 'cmake', components: 'uc', required: false)
# Try again with subproject fallback. `allow_fallback: true` means the
# fallback will be tried even if the icu option is set to `auto`, but
# we cannot pass this option until Meson 0.59.0, because no wrap file
# is checked into git.
if not icu_dep.found()
icu_dep = dependency('icu-uc',
method: 'pkg-config',
required: get_option('icu'))
endif
endif
icu_dep = dependency('icu-uc',
required: get_option('icu'),
method: 'pkg-config')
endif
if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
@ -161,7 +118,7 @@ if not get_option('cairo').disabled()
cairo_ft_dep = dependency('cairo-ft', required: false)
if (not cairo_dep.found() and
cpp.get_argument_syntax() == 'msvc' 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',
@ -177,8 +134,7 @@ if not get_option('cairo').disabled()
# harfbuzz support disabled, so when cairo will lookup freetype2 dependency
# it will be forced to use that one.
cairo_dep = dependency('cairo', required: get_option('cairo'))
cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled()
cairo_ft_dep = dependency('cairo-ft', required: cairo_ft_required)
cairo_ft_dep = dependency('cairo-ft', required: get_option('cairo'))
endif
endif
@ -205,19 +161,10 @@ endif
if cairo_dep.found()
conf.set('HAVE_CAIRO', 1)
check_cairo_funcs = [
['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}],
['cairo_font_options_get_custom_palette_color', {'deps': cairo_dep}],
['cairo_user_scaled_font_get_foreground_source', {'deps': cairo_dep}],
]
if cairo_dep.type_name() == 'internal'
foreach func: check_cairo_funcs
name = func[0]
conf.set('HAVE_@0@'.format(name.to_upper()), 1)
endforeach
conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1)
else
check_funcs += check_cairo_funcs
check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]]
endif
endif
@ -251,7 +198,6 @@ if freetype_dep.found()
['FT_Get_Var_Blend_Coordinates', {'deps': freetype_dep}],
['FT_Set_Var_Blend_Coordinates', {'deps': freetype_dep}],
['FT_Done_MM_Var', {'deps': freetype_dep}],
['FT_Get_Transform', {'deps': freetype_dep}],
]
if freetype_dep.type_name() == 'internal'
@ -286,12 +232,17 @@ if host_machine.system() == 'windows' and not get_option('gdi').disabled()
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
conf.set('HAVE_DIRECTWRITE', 1)
directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
if directwrite_dep.found()
conf.set('HAVE_DIRECTWRITE', 1)
endif
endif
# CoreText (macOS)
@ -373,10 +324,7 @@ foreach check : check_funcs
endforeach
subdir('src')
if not get_option('utilities').disabled()
subdir('util')
endif
subdir('util')
if not get_option('tests').disabled()
subdir('test')
@ -392,9 +340,6 @@ endif
configure_file(output: 'config.h', configuration: conf)
alias_target('lib', libharfbuzz)
alias_target('libs', libharfbuzz, libharfbuzz_subset)
build_summary = {
'Directories':
{'prefix': get_option('prefix'),
@ -409,8 +354,7 @@ build_summary = {
'ICU': conf.get('HAVE_ICU', 0) == 1,
},
'Font callbacks (the more the merrier)':
{'Builtin' : true,
'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
{'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
},
'Dependencies used for command-line utilities':
{'Cairo': conf.get('HAVE_CAIRO', 0) == 1,
@ -427,7 +371,6 @@ build_summary = {
'Other features':
{'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1,
'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1,
'Cairo integration': conf.get('HAVE_CAIRO', 0) == 1,
'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1,
'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1,
},

View File

@ -29,10 +29,6 @@ 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('doc_tests', type: 'boolean', value: false,
description: 'Run gtkdoc-check tests')
option('utilities', type: 'feature', value: 'enabled', yield: true,
description: 'Build harfbuzz utils')
option('benchmark', type: 'feature', value: 'disabled',
description: 'Enable benchmark tests')

View File

@ -17,14 +17,12 @@ exec "$(dirname "$0")"/configure \
CPP= \
LD= \
CFLAGS="-static-libgcc" \
CXXFLAGS="-O2 -static-libgcc -static-libstdc++" \
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-gdi \
--with-uniscribe \
--with-directwrite=auto \
"$@"

View File

@ -6,22 +6,14 @@ To build the benchmarks in this directory you need to set the benchmark
option while configuring the build with meson:
```
meson build -Dbenchmark=enabled --buildtype=release
```
or:
```
meson build -Dbenchmark=enabled --buildtype=debugoptimized
meson configure build -Dbenchmark=enabled --buildtype=release
```
Then build the benchmark binaries with ninja:
Then build a specific benchmark binaries with ninja:
```
ninja -Cbuild perf/benchmark-set
```
or just build the whole project:
```
ninja -Cbuild
```
Finally, to run one of the benchmarks:
@ -45,10 +37,10 @@ ninja -Cbuild
Then run the benchmark with perf:
```
perf record -g build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
perf record -g -o ~/tmp/profiles/subset.prof ./build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
```
You probably want to filter to a specific benchmark of interest and set the number of repititions high enough to get a good sampling of profile data.
Finally view the profile with:
perf report
perf report -i ~/tmp/profiles/subset.prof

View File

@ -49,8 +49,8 @@ _hb_move_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *)
static void
_hb_line_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, void *) {}
//static void
//_hb_quadratic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, void *) {}
static void
_hb_quadratic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, void *) {}
static void
_hb_cubic_to (hb_draw_funcs_t *, void *, hb_draw_state_t *, float, float, float, float, float, float, void *) {}
@ -64,7 +64,7 @@ _draw_funcs_create (void)
hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr);
hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr);
//hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr);
hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr);
return draw_funcs;
@ -163,7 +163,7 @@ static void BM_Font (benchmark::State &state,
hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
for (auto _ : state)
for (unsigned gid = 0; gid < num_glyphs; ++gid)
hb_font_draw_glyph (font, gid, draw_funcs, nullptr);
hb_font_get_glyph_shape (font, gid, draw_funcs, nullptr);
break;
hb_draw_funcs_destroy (draw_funcs);
}

View File

@ -27,18 +27,10 @@ struct test_input_t
"perf/texts/fa-thelittleprince.txt",
false},
{"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
"perf/texts/fa-words.txt",
false},
{"perf/fonts/Amiri-Regular.ttf",
"perf/texts/fa-thelittleprince.txt",
false},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
"perf/texts/hi-words.txt",
false},
{"perf/fonts/Roboto-Regular.ttf",
"perf/texts/en-thelittleprince.txt",
false},

View File

@ -2,82 +2,35 @@
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb-subset.h"
enum operation_t
{
subset_codepoints,
subset_glyphs,
instance,
subset_glyphs
};
struct axis_location_t
{
hb_tag_t axis_tag;
float axis_value;
};
static const axis_location_t
_roboto_flex_instance_opts[] =
{
{HB_TAG ('w', 'g', 'h', 't'), 600.f},
{HB_TAG ('w', 'd', 't', 'h'), 75.f},
{HB_TAG ('o', 'p', 's', 'z'), 90.f},
{HB_TAG ('G', 'R', 'A', 'D'), -100.f},
{HB_TAG ('s', 'l', 'n', 't'), -3.f},
{HB_TAG ('X', 'T', 'R', 'A'), 500.f},
{HB_TAG ('X', 'O', 'P', 'Q'), 150.f},
{HB_TAG ('Y', 'O', 'P', 'Q'), 100.f},
{HB_TAG ('Y', 'T', 'L', 'C'), 480.f},
{HB_TAG ('Y', 'T', 'U', 'C'), 600.f},
{HB_TAG ('Y', 'T', 'A', 'S'), 800.f},
{HB_TAG ('Y', 'T', 'D', 'E'), -50.f},
{HB_TAG ('Y', 'T', 'F', 'I'), 600.f},
};
static const axis_location_t
_mplus_instance_opts[] =
{
{HB_TAG ('w', 'g', 'h', 't'), 800.f},
};
template <typename Type, unsigned int n>
static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; }
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
struct test_input_t
{
const char *font_path;
unsigned max_subset_size;
const axis_location_t *instance_opts;
unsigned num_instance_opts;
} default_tests[] =
const unsigned max_subset_size;
} tests[] =
{
{SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0},
{SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0},
{SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)},
{SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)},
{SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000},
{SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000},
{SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000},
{SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000},
{SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000},
{SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000},
#if 0
{"perf/fonts/NotoSansCJKsc-VF.ttf", 100000},
#endif
};
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
void AddCodepoints(const hb_set_t* codepoints_in_font,
unsigned subset_size,
hb_subset_input_t* input)
@ -102,52 +55,24 @@ void AddGlyphs(unsigned num_glyphs_in_font,
}
}
// Preprocess face and populate the subset accelerator on it to speed up
// the subsetting operations.
static hb_face_t* preprocess_face(hb_face_t* face)
{
hb_face_t* new_face = hb_subset_preprocess(face);
hb_face_destroy(face);
return new_face;
}
/* benchmark for subsetting a font */
static void BM_subset (benchmark::State &state,
operation_t operation,
const test_input_t &test_input,
bool hinting)
const char *font_path)
{
unsigned subset_size = state.range(0);
hb_face_t *face = nullptr;
static hb_face_t *cached_face;
static const char *cached_font_path;
if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
hb_face_t *face;
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
hb_blob_t *blob = hb_blob_create_from_file_or_fail (font_path);
assert (blob);
face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
face = preprocess_face (face);
if (cached_face)
hb_face_destroy (cached_face);
cached_face = hb_face_reference (face);
cached_font_path = test_input.font_path;
}
else
face = hb_face_reference (cached_face);
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
assert (input);
if (!hinting)
hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
switch (operation)
{
case subset_codepoints:
@ -165,20 +90,6 @@ static void BM_subset (benchmark::State &state,
AddGlyphs(num_glyphs, subset_size, input);
}
break;
case instance:
{
hb_set_t* all_codepoints = hb_set_create ();
hb_face_collect_unicodes (face, all_codepoints);
AddCodepoints(all_codepoints, subset_size, input);
hb_set_destroy (all_codepoints);
for (unsigned i = 0; i < test_input.num_instance_opts; i++)
hb_subset_input_pin_axis_location (input, face,
test_input.instance_opts[i].axis_tag,
test_input.instance_opts[i].axis_value);
}
break;
}
for (auto _ : state)
@ -194,66 +105,38 @@ static void BM_subset (benchmark::State &state,
static void test_subset (operation_t op,
const char *op_name,
bool hinting,
benchmark::TimeUnit time_unit,
const test_input_t &test_input)
{
if (op == instance && test_input.instance_opts == nullptr)
return;
char name[1024] = "BM_subset/";
strcat (name, op_name);
strcat (name, "/");
const char *p = strrchr (test_input.font_path, '/');
strcat (name, p ? p + 1 : test_input.font_path);
if (!hinting)
strcat (name, "/nohinting");
strcat (name, strrchr (test_input.font_path, '/'));
benchmark::RegisterBenchmark (name, BM_subset, op, test_input, hinting)
benchmark::RegisterBenchmark (name, BM_subset, op, test_input.font_path)
->Range(10, test_input.max_subset_size)
->Unit(time_unit);
}
static void test_operation (operation_t op,
const char *op_name,
const test_input_t *tests,
unsigned num_tests,
benchmark::TimeUnit time_unit)
{
for (unsigned i = 0; i < num_tests; i++)
for (auto& test_input : tests)
{
auto& test_input = tests[i];
test_subset (op, op_name, true, time_unit, test_input);
test_subset (op, op_name, false, time_unit, test_input);
test_subset (op, op_name, time_unit, test_input);
}
}
int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
if (argc > 1)
{
num_tests = (argc - 1) / 2;
tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
for (unsigned i = 0; i < num_tests; i++)
{
tests[i].font_path = argv[1 + i * 2];
tests[i].max_subset_size = atoi (argv[2 + i * 2]);
}
}
#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit)
#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit)
TEST_OPERATION (subset_glyphs, benchmark::kMillisecond);
TEST_OPERATION (subset_codepoints, benchmark::kMillisecond);
TEST_OPERATION (instance, benchmark::kMillisecond);
#undef TEST_OPERATION
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

25
perf/run.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
CXX=clang++
FONT=fonts/NotoNastaliqUrdu-Regular.ttf
TEXT=texts/fa-monologue.txt
$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \
-lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \
-I../src $FLAGS $SOURCES \
-DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \
-DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \
-o hb-shape -g -O2 # -O3 \
#-march=native -mtune=native \
#-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \
#-Rpass-analysis=loop-vectorize -fsave-optimization-record
# -march=native: enable all vector instructions current CPU can offer
# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics
#sudo rm capture.syscap > /dev/null
#sysprof-cli -c "./a.out $@"
#sysprof capture.syscap
perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot
#perf report -g

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,250 +0,0 @@
#
# Name: Legacy Simplified Arabic encoding
#
# Format: Three tab-separated columns
# Column #1 is the PUA code (in hex as 0xXXXX)
# Column #2 is the Unicode (in hex as 0xXXXX)
# Column #3 is the Unicode name (follows a comment sign, '#')
#
# The entries are in PUA order
#
0xF100 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE
0xF100 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW
0xF100 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V
0xF100 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE
0xF100 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
0xF100 0x0653 # ARABIC MADDAH ABOVE
0xF100 0x0654 # ARABIC HAMZA ABOVE
0xF100 0x0655 # ARABIC HAMZA BELOW
0xF100 0x0656 # ARABIC SUBSCRIPT ALEF
0xF100 0x0657 # ARABIC INVERTED DAMMA
0xF100 0x0658 # ARABIC MARK NOON GHUNNA
0xF100 0x0659 # ARABIC ZWARAKAY
0xF100 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE
0xF100 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
0xF100 0x065C # ARABIC VOWEL SIGN DOT BELOW
0xF100 0x065D # ARABIC REVERSED DAMMA
0xF100 0x065E # ARABIC FATHA WITH TWO DOTS
0xF10C 0x200C # ZERO WIDTH NON-JOINER
0xF10D 0x200D # ZERO WIDTH JOINER
0xF10E 0x200E # LEFT-TO-RIGHT MARK
0xF10F 0x200F # RIGHT-TO-LEFT MARK
0xF120 0x0020 # SPACE
0xF121 0x0021 # EXCLAMATION MARK
0xF122 0x0022 # QUOTATION MARK
0xF123 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF124 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF125 0x0025 # PERCENT SIGN
0xF126 0x00D7 # MULTIPLICATION SIGN
0xF127 0x00F7 # DIVISION SIGN
0xF128 0x0028 # LEFT PARENTHESIS
0xF129 0x0029 # RIGHT PARENTHESIS
0xF12A 0x002A # ASTERISK
0xF12B 0x002B # PLUS SIGN
0xF12C 0x060C # ARABIC COMMA
0xF12D 0x002D # HYPHEN-MINUS
0xF12E 0x002E # FULL STOP
0xF12F 0x002F # SOLIDUS
0xF130 0x0660 # ARABIC-INDIC DIGIT ZERO
0xF131 0x0661 # ARABIC-INDIC DIGIT ONE
0xF132 0x0662 # ARABIC-INDIC DIGIT TWO
0xF133 0x0663 # ARABIC-INDIC DIGIT THREE
0xF134 0x0664 # ARABIC-INDIC DIGIT FOUR
0xF135 0x0665 # ARABIC-INDIC DIGIT FIVE
0xF136 0x0666 # ARABIC-INDIC DIGIT SIX
0xF137 0x0667 # ARABIC-INDIC DIGIT SEVEN
0xF138 0x0668 # ARABIC-INDIC DIGIT EIGHT
0xF139 0x0669 # ARABIC-INDIC DIGIT NINE
0xF13A 0x003A # COLON
0xF13B 0x003B # SEMICOLON
0xF13B 0x061B # ARABIC SEMICOLON
0xF13C 0x2018 # LEFT SINGLE QUOTATION MARK
0xF13D 0x003D # EQUALS SIGN
0xF13E 0x2019 # RIGHT SINGLE QUOTATION MARK
0xF13F 0x003F # QUESTION MARK
0xF13F 0x061F # ARABIC QUESTION MARK
0xF141 0x0627 # ARABIC LETTER ALEF
0xF141 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM
0xF142 0xFE8E # ARABIC LETTER ALEF FINAL FORM
0xF143 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE
0xF143 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF144 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
0xF145 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE
0xF145 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
0xF146 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
0xF147 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW
0xF147 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM
0xF148 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM
0xF149 0xFE91 # ARABIC LETTER BEH INITIAL FORM
0xF149 0xFE92 # ARABIC LETTER BEH MEDIAL FORM
0xF14A 0x0628 # ARABIC LETTER BEH
0xF14A 0xFE8F # ARABIC LETTER BEH ISOLATED FORM
0xF14A 0xFE90 # ARABIC LETTER BEH FINAL FORM
0xF14B 0xFE97 # ARABIC LETTER TEH INITIAL FORM
0xF14B 0xFE98 # ARABIC LETTER TEH MEDIAL FORM
0xF14C 0x062A # ARABIC LETTER TEH
0xF14C 0xFE95 # ARABIC LETTER TEH ISOLATED FORM
0xF14C 0xFE96 # ARABIC LETTER TEH FINAL FORM
0xF14D 0xFE9B # ARABIC LETTER THEH INITIAL FORM
0xF14D 0xFE9C # ARABIC LETTER THEH MEDIAL FORM
0xF14E 0x062B # ARABIC LETTER THEH
0xF14E 0xFE99 # ARABIC LETTER THEH ISOLATED FORM
0xF14E 0xFE9A # ARABIC LETTER THEH FINAL FORM
0xF14F 0xFE9F # ARABIC LETTER JEEM INITIAL FORM
0xF14F 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM
0xF150 0xFE9E # ARABIC LETTER JEEM FINAL FORM
0xF151 0x062C # ARABIC LETTER JEEM
0xF151 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM
0xF152 0xFEA3 # ARABIC LETTER HAH INITIAL FORM
0xF152 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM
0xF153 0xFEA2 # ARABIC LETTER HAH FINAL FORM
0xF154 0x062D # ARABIC LETTER HAH
0xF154 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM
0xF155 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM
0xF155 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM
0xF156 0xFEA6 # ARABIC LETTER KHAH FINAL FORM
0xF157 0x062E # ARABIC LETTER KHAH
0xF157 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM
0xF158 0x062F # ARABIC LETTER DAL
0xF158 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM
0xF158 0xFEAA # ARABIC LETTER DAL FINAL FORM
0xF159 0x0630 # ARABIC LETTER THAL
0xF159 0xFEAB # ARABIC LETTER THAL ISOLATED FORM
0xF159 0xFEAC # ARABIC LETTER THAL FINAL FORM
0xF15A 0x0631 # ARABIC LETTER REH
0xF15A 0xFEAD # ARABIC LETTER REH ISOLATED FORM
0xF15A 0xFEAE # ARABIC LETTER REH FINAL FORM
0xF15B 0x005B # LEFT SQUARE BRACKET
0xF15C 0x005C # REVERSE SOLIDUS
0xF15D 0x005D # RIGHT SQUARE BRACKET
0xF15E 0x002C # COMMA
0xF15E 0x066B # ARABIC DECIMAL SEPARATOR
0xF15E 0x066C # ARABIC THOUSANDS SEPARATOR
0xF15F 0x0640 # ARABIC TATWEEL
0xF160 0x0632 # ARABIC LETTER ZAIN
0xF160 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM
0xF160 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM
0xF161 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM
0xF161 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM
0xF162 0x0633 # ARABIC LETTER SEEN
0xF162 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM
0xF162 0xFEB2 # ARABIC LETTER SEEN FINAL FORM
0xF163 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM
0xF163 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM
0xF164 0x0634 # ARABIC LETTER SHEEN
0xF164 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM
0xF164 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM
0xF165 0xFEBB # ARABIC LETTER SAD INITIAL FORM
0xF165 0xFEBC # ARABIC LETTER SAD MEDIAL FORM
0xF166 0x0635 # ARABIC LETTER SAD
0xF166 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM
0xF166 0xFEBA # ARABIC LETTER SAD FINAL FORM
0xF167 0xFEBF # ARABIC LETTER DAD INITIAL FORM
0xF167 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM
0xF168 0x0636 # ARABIC LETTER DAD
0xF168 0xFEBD # ARABIC LETTER DAD ISOLATED FORM
0xF168 0xFEBE # ARABIC LETTER DAD FINAL FORM
0xF169 0x0637 # ARABIC LETTER TAH
0xF169 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM
0xF169 0xFEC2 # ARABIC LETTER TAH FINAL FORM
0xF169 0xFEC3 # ARABIC LETTER TAH INITIAL FORM
0xF169 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM
0xF16A 0x0638 # ARABIC LETTER ZAH
0xF16A 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM
0xF16A 0xFEC6 # ARABIC LETTER ZAH FINAL FORM
0xF16A 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM
0xF16A 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM
0xF16B 0xFECB # ARABIC LETTER AIN INITIAL FORM
0xF16C 0xFECC # ARABIC LETTER AIN MEDIAL FORM
0xF16D 0xFECA # ARABIC LETTER AIN FINAL FORM
0xF16E 0x0639 # ARABIC LETTER AIN
0xF16E 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM
0xF16F 0xFECF # ARABIC LETTER GHAIN INITIAL FORM
0xF170 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM
0xF171 0xFECE # ARABIC LETTER GHAIN FINAL FORM
0xF172 0x063A # ARABIC LETTER GHAIN
0xF172 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM
0xF173 0xFED3 # ARABIC LETTER FEH INITIAL FORM
0xF174 0xFED4 # ARABIC LETTER FEH MEDIAL FORM
0xF175 0x0641 # ARABIC LETTER FEH
0xF175 0xFED1 # ARABIC LETTER FEH ISOLATED FORM
0xF175 0xFED2 # ARABIC LETTER FEH FINAL FORM
0xF176 0xFED7 # ARABIC LETTER QAF INITIAL FORM
0xF177 0xFED8 # ARABIC LETTER QAF MEDIAL FORM
0xF178 0x0642 # ARABIC LETTER QAF
0xF178 0xFED5 # ARABIC LETTER QAF ISOLATED FORM
0xF178 0xFED6 # ARABIC LETTER QAF FINAL FORM
0xF179 0xFEDB # ARABIC LETTER KAF INITIAL FORM
0xF179 0xFEDC # ARABIC LETTER KAF MEDIAL FORM
0xF17A 0x0643 # ARABIC LETTER KAF
0xF17A 0xFED9 # ARABIC LETTER KAF ISOLATED FORM
0xF17A 0xFEDA # ARABIC LETTER KAF FINAL FORM
0xF17B 0xFEDF # ARABIC LETTER LAM INITIAL FORM
0xF17B 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM
0xF17C 0x0644 # ARABIC LETTER LAM
0xF17C 0xFEDD # ARABIC LETTER LAM ISOLATED FORM
0xF17C 0xFEDE # ARABIC LETTER LAM FINAL FORM
0xF17D 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM
0xF17D 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM
0xF17E 0x0645 # ARABIC LETTER MEEM
0xF17E 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM
0xF17E 0xFEE2 # ARABIC LETTER MEEM FINAL FORM
0xF17F 0xFEE7 # ARABIC LETTER NOON INITIAL FORM
0xF17F 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM
0xF1A1 0xFEEB # ARABIC LETTER HEH INITIAL FORM
0xF1A2 0xFEEC # ARABIC LETTER HEH MEDIAL FORM
0xF1A3 0xFEEA # ARABIC LETTER HEH FINAL FORM
0xF1A4 0x0647 # ARABIC LETTER HEH
0xF1A4 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM
0xF1A5 0x0648 # ARABIC LETTER WAW
0xF1A5 0xFEED # ARABIC LETTER WAW ISOLATED FORM
0xF1A5 0xFEEE # ARABIC LETTER WAW FINAL FORM
0xF1A6 0xFEF3 # ARABIC LETTER YEH INITIAL FORM
0xF1A6 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM
0xF1A7 0xFEF2 # ARABIC LETTER YEH FINAL FORM
0xF1A8 0x064A # ARABIC LETTER YEH
0xF1A8 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM
0xF1A9 0x0629 # ARABIC LETTER TEH MARBUTA
0xF1A9 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM
0xF1AA 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM
0xF1AB 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM
0xF1AC 0x0649 # ARABIC LETTER ALEF MAKSURA
0xF1AC 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
0xF1AD 0x0621 # ARABIC LETTER HAMZA
0xF1AE 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
0xF1AE 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM
0xF1AF 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
0xF1B0 0x0030 # DIGIT ZERO
0xF1B1 0x0031 # DIGIT ONE
0xF1B2 0x0032 # DIGIT TWO
0xF1B3 0x0033 # DIGIT THREE
0xF1B4 0x0034 # DIGIT FOUR
0xF1B5 0x0035 # DIGIT FIVE
0xF1B6 0x0036 # DIGIT SIX
0xF1B7 0x0037 # DIGIT SEVEN
0xF1B8 0x0038 # DIGIT EIGHT
0xF1B9 0x0039 # DIGIT NINE
0xF1BA 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE
0xF1BA 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
0xF1BB 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE
0xF1BB 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
0xF1BB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM
0xF1BC 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
0xF1BD 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
0xF1BE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF1BF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
0xF1C0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
0xF1C1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
0xF1C2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
0xF1C3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
0xF1C4 0x064E # ARABIC FATHA
0xF1C5 0x064F # ARABIC DAMMA
0xF1C6 0x0652 # ARABIC SUKUN
0xF1C7 0x064B # ARABIC FATHATAN
0xF1C8 0x064C # ARABIC DAMMATAN
0xF1C9 0x0651 # ARABIC SHADDA
0xF1CA 0x0650 # ARABIC KASRA
0xF1CB 0x064D # ARABIC KASRATAN
0xF1E1 0x0646 # ARABIC LETTER NOON
0xF1E1 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM
0xF1E1 0xFEE6 # ARABIC LETTER NOON FINAL FORM

View File

@ -1,295 +0,0 @@
#
# Name: Legacy Traditional Arabic encoding
#
# Format: Three tab-separated columns
# Column #1 is the PUA code (in hex as 0xXXXX)
# Column #2 is the Unicode (in hex as 0xXXXX)
# Column #3 is the Unicode name (follows a comment sign, '#')
#
# The entries are in PUA order
#
0xF200 0x063B # ARABIC LETTER KEHEH WITH TWO DOTS ABOVE
0xF200 0x063C # ARABIC LETTER KEHEH WITH THREE DOTS BELOW
0xF200 0x063D # ARABIC LETTER FARSI YEH WITH INVERTED V
0xF200 0x063E # ARABIC LETTER FARSI YEH WITH TWO DOTS ABOVE
0xF200 0x063F # ARABIC LETTER FARSI YEH WITH THREE DOTS ABOVE
0xF200 0x0653 # ARABIC MADDAH ABOVE
0xF200 0x0654 # ARABIC HAMZA ABOVE
0xF200 0x0655 # ARABIC HAMZA BELOW
0xF200 0x0656 # ARABIC SUBSCRIPT ALEF
0xF200 0x0657 # ARABIC INVERTED DAMMA
0xF200 0x0658 # ARABIC MARK NOON GHUNNA
0xF200 0x0659 # ARABIC ZWARAKAY
0xF200 0x065A # ARABIC VOWEL SIGN SMALL V ABOVE
0xF200 0x065B # ARABIC VOWEL SIGN INVERTED SMALL V ABOVE
0xF200 0x065C # ARABIC VOWEL SIGN DOT BELOW
0xF200 0x065D # ARABIC REVERSED DAMMA
0xF200 0x065E # ARABIC FATHA WITH TWO DOTS
0xF202 0xFC08 # ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM
0xF203 0xFC0E # ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM
0xF204 0xFC12 # ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM
0xF205 0xFC42 # ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM
0xF206 0xFC4E # ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM
0xF20C 0x200C # ZERO WIDTH NON-JOINER
0xF20D 0x200D # ZERO WIDTH JOINER
0xF20E 0x200E # LEFT-TO-RIGHT MARK
0xF20F 0x200F # RIGHT-TO-LEFT MARK
0xF210 0xFD88 # ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM
0xF212 0xFC3F # ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM
0xF213 0xFC40 # ARABIC LIGATURE LAM WITH HAH ISOLATED FORM
0xF214 0xFC41 # ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM
0xF215 0xFC6A # ARABIC LIGATURE BEH WITH REH FINAL FORM
0xF216 0xFC70 # ARABIC LIGATURE TEH WITH REH FINAL FORM
0xF217 0xFC91 # ARABIC LIGATURE YEH WITH REH FINAL FORM
0xF218 0xFCB0 # ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM
0xF219 0xFD30 # ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM
0xF21A 0xFCCD # ARABIC LIGATURE LAM WITH HEH INITIAL FORM
0xF21C 0xFC44 # ARABIC LIGATURE LAM WITH YEH ISOLATED FORM
0xF21D 0xFC0A # ARABIC LIGATURE BEH WITH YEH ISOLATED FORM
0xF21E 0xFC10 # ARABIC LIGATURE TEH WITH YEH ISOLATED FORM
0xF21F 0xFC50 # ARABIC LIGATURE NOON WITH YEH ISOLATED FORM
0xF220 0x0020 # SPACE
0xF221 0x0021 # EXCLAMATION MARK
0xF222 0x0022 # QUOTATION MARK
0xF223 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF224 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
0xF225 0x0025 # PERCENT SIGN
0xF226 0x00D7 # MULTIPLICATION SIGN
0xF227 0x00F7 # DIVISION SIGN
0xF228 0x0028 # LEFT PARENTHESIS
0xF229 0x0029 # RIGHT PARENTHESIS
0xF22A 0x002A # ASTERISK
0xF22B 0x002B # PLUS SIGN
0xF22C 0x060C # ARABIC COMMA
0xF22D 0x002D # HYPHEN-MINUS
0xF22E 0x002E # FULL STOP
0xF22F 0x002F # SOLIDUS
0xF230 0x0660 # ARABIC-INDIC DIGIT ZERO
0xF231 0x0661 # ARABIC-INDIC DIGIT ONE
0xF232 0x0662 # ARABIC-INDIC DIGIT TWO
0xF233 0x0663 # ARABIC-INDIC DIGIT THREE
0xF234 0x0664 # ARABIC-INDIC DIGIT FOUR
0xF235 0x0665 # ARABIC-INDIC DIGIT FIVE
0xF236 0x0666 # ARABIC-INDIC DIGIT SIX
0xF237 0x0667 # ARABIC-INDIC DIGIT SEVEN
0xF238 0x0668 # ARABIC-INDIC DIGIT EIGHT
0xF239 0x0669 # ARABIC-INDIC DIGIT NINE
0xF23A 0x003A # COLON
0xF23B 0x003B # SEMICOLON
0xF23B 0x061B # ARABIC SEMICOLON
0xF23C 0x201C # LEFT DOUBLE QUOTATION MARK
0xF23D 0x003D # EQUALS SIGN
0xF23E 0x201D # RIGHT DOUBLE QUOTATION MARK
0xF23F 0x003F # QUESTION MARK
0xF23F 0x061F # ARABIC QUESTION MARK
0xF241 0x0627 # ARABIC LETTER ALEF
0xF241 0xFE8D # ARABIC LETTER ALEF ISOLATED FORM
0xF242 0xFE8E # ARABIC LETTER ALEF FINAL FORM
0xF243 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE
0xF243 0xFE83 # ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF244 0xFE84 # ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM
0xF245 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE
0xF245 0xFE81 # ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM
0xF246 0xFE82 # ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM
0xF247 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW
0xF247 0xFE87 # ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM
0xF248 0xFE88 # ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM
0xF249 0xFE91 # ARABIC LETTER BEH INITIAL FORM
0xF24A 0xFE92 # ARABIC LETTER BEH MEDIAL FORM
0xF24B 0xFE90 # ARABIC LETTER BEH FINAL FORM
0xF24C 0x0628 # ARABIC LETTER BEH
0xF24C 0xFE8F # ARABIC LETTER BEH ISOLATED FORM
0xF24D 0xFE97 # ARABIC LETTER TEH INITIAL FORM
0xF24E 0xFE98 # ARABIC LETTER TEH MEDIAL FORM
0xF24F 0xFE96 # ARABIC LETTER TEH FINAL FORM
0xF250 0x062A # ARABIC LETTER TEH
0xF250 0xFE95 # ARABIC LETTER TEH ISOLATED FORM
0xF251 0xFE9B # ARABIC LETTER THEH INITIAL FORM
0xF252 0xFE9C # ARABIC LETTER THEH MEDIAL FORM
0xF253 0xFE9A # ARABIC LETTER THEH FINAL FORM
0xF254 0x062B # ARABIC LETTER THEH
0xF254 0xFE99 # ARABIC LETTER THEH ISOLATED FORM
0xF255 0xFE9F # ARABIC LETTER JEEM INITIAL FORM
0xF256 0xFEA0 # ARABIC LETTER JEEM MEDIAL FORM
0xF257 0xFE9E # ARABIC LETTER JEEM FINAL FORM
0xF258 0x062C # ARABIC LETTER JEEM
0xF258 0xFE9D # ARABIC LETTER JEEM ISOLATED FORM
0xF259 0xFEA3 # ARABIC LETTER HAH INITIAL FORM
0xF25A 0xFEA4 # ARABIC LETTER HAH MEDIAL FORM
0xF25B 0x005B # LEFT SQUARE BRACKET
0xF25C 0xFEA2 # ARABIC LETTER HAH FINAL FORM
0xF25D 0x005D # RIGHT SQUARE BRACKET
0xF25E 0x002C # COMMA
0xF25E 0x066B # ARABIC DECIMAL SEPARATOR
0xF25E 0x066C # ARABIC THOUSANDS SEPARATOR
0xF25F 0x0640 # ARABIC TATWEEL
0xF260 0x062D # ARABIC LETTER HAH
0xF260 0xFEA1 # ARABIC LETTER HAH ISOLATED FORM
0xF261 0xFEA7 # ARABIC LETTER KHAH INITIAL FORM
0xF262 0xFEA8 # ARABIC LETTER KHAH MEDIAL FORM
0xF263 0xFEA6 # ARABIC LETTER KHAH FINAL FORM
0xF264 0x062E # ARABIC LETTER KHAH
0xF264 0xFEA5 # ARABIC LETTER KHAH ISOLATED FORM
0xF265 0x062F # ARABIC LETTER DAL
0xF265 0xFEA9 # ARABIC LETTER DAL ISOLATED FORM
0xF266 0xFEAA # ARABIC LETTER DAL FINAL FORM
0xF267 0x0630 # ARABIC LETTER THAL
0xF267 0xFEAB # ARABIC LETTER THAL ISOLATED FORM
0xF268 0xFEAC # ARABIC LETTER THAL FINAL FORM
0xF269 0x0631 # ARABIC LETTER REH
0xF269 0xFEAD # ARABIC LETTER REH ISOLATED FORM
0xF26A 0xFEAE # ARABIC LETTER REH FINAL FORM
0xF26B 0x0632 # ARABIC LETTER ZAIN
0xF26B 0xFEAF # ARABIC LETTER ZAIN ISOLATED FORM
0xF26C 0xFEB0 # ARABIC LETTER ZAIN FINAL FORM
0xF26D 0xFEB3 # ARABIC LETTER SEEN INITIAL FORM
0xF26E 0xFEB4 # ARABIC LETTER SEEN MEDIAL FORM
0xF26F 0xFEB2 # ARABIC LETTER SEEN FINAL FORM
0xF270 0x0633 # ARABIC LETTER SEEN
0xF270 0xFEB1 # ARABIC LETTER SEEN ISOLATED FORM
0xF271 0xFEB7 # ARABIC LETTER SHEEN INITIAL FORM
0xF272 0xFEB8 # ARABIC LETTER SHEEN MEDIAL FORM
0xF273 0xFEB6 # ARABIC LETTER SHEEN FINAL FORM
0xF274 0x0634 # ARABIC LETTER SHEEN
0xF274 0xFEB5 # ARABIC LETTER SHEEN ISOLATED FORM
0xF275 0xFEBB # ARABIC LETTER SAD INITIAL FORM
0xF276 0xFEBC # ARABIC LETTER SAD MEDIAL FORM
0xF277 0xFEBA # ARABIC LETTER SAD FINAL FORM
0xF278 0x0635 # ARABIC LETTER SAD
0xF278 0xFEB9 # ARABIC LETTER SAD ISOLATED FORM
0xF279 0xFEBF # ARABIC LETTER DAD INITIAL FORM
0xF27A 0xFEC0 # ARABIC LETTER DAD MEDIAL FORM
0xF27B 0xFD3E # ORNATE LEFT PARENTHESIS
0xF27C 0xFEBE # ARABIC LETTER DAD FINAL FORM
0xF27D 0xFD3F # ORNATE RIGHT PARENTHESIS
0xF27E 0x0636 # ARABIC LETTER DAD
0xF27E 0xFEBD # ARABIC LETTER DAD ISOLATED FORM
0xF27F 0xFEC3 # ARABIC LETTER TAH INITIAL FORM
0xF280 0xFC9C # ARABIC LIGATURE BEH WITH JEEM INITIAL FORM
0xF281 0xFC9D # ARABIC LIGATURE BEH WITH HAH INITIAL FORM
0xF282 0xFC9E # ARABIC LIGATURE BEH WITH KHAH INITIAL FORM
0xF283 0xFCA1 # ARABIC LIGATURE TEH WITH JEEM INITIAL FORM
0xF284 0xFCA2 # ARABIC LIGATURE TEH WITH HAH INITIAL FORM
0xF285 0xFCA3 # ARABIC LIGATURE TEH WITH KHAH INITIAL FORM
0xF286 0xFCC9 # ARABIC LIGATURE LAM WITH JEEM INITIAL FORM
0xF287 0xFCCA # ARABIC LIGATURE LAM WITH HAH INITIAL FORM
0xF288 0xFCCB # ARABIC LIGATURE LAM WITH KHAH INITIAL FORM
0xF289 0xFCCE # ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM
0xF28A 0xFCCF # ARABIC LIGATURE MEEM WITH HAH INITIAL FORM
0xF28B 0xFCD0 # ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM
0xF28D 0xFCD2 # ARABIC LIGATURE NOON WITH JEEM INITIAL FORM
0xF28E 0xFCD3 # ARABIC LIGATURE NOON WITH HAH INITIAL FORM
0xF28F 0xFCDA # ARABIC LIGATURE YEH WITH JEEM INITIAL FORM
0xF290 0xFCDB # ARABIC LIGATURE YEH WITH HAH INITIAL FORM
0xF291 0xFCDC # ARABIC LIGATURE YEH WITH KHAH INITIAL FORM
0xF292 0xFC6D # ARABIC LIGATURE BEH WITH NOON FINAL FORM
0xF293 0xFC73 # ARABIC LIGATURE TEH WITH NOON FINAL FORM
0xF294 0xFC94 # ARABIC LIGATURE YEH WITH NOON FINAL FORM
0xF295 0xFC86 # ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM
0xF296 0xFC9F # ARABIC LIGATURE BEH WITH MEEM INITIAL FORM
0xF297 0xFCA4 # ARABIC LIGATURE TEH WITH MEEM INITIAL FORM
0xF298 0xFCD5 # ARABIC LIGATURE NOON WITH MEEM INITIAL FORM
0xF299 0xFCDD # ARABIC LIGATURE YEH WITH MEEM INITIAL FORM
0xF29A 0xFCA8 # ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM
0xF29B 0xFCAA # ARABIC LIGATURE HAH WITH MEEM INITIAL FORM
0xF29C 0xFCAC # ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM
0xF29D 0xFCCC # ARABIC LIGATURE LAM WITH MEEM INITIAL FORM
0xF29E 0xFCD1 # ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM
0xF29F 0xFC32 # ARABIC LIGATURE FEH WITH YEH ISOLATED FORM
0xF2A1 0xFEC2 # ARABIC LETTER TAH FINAL FORM
0xF2A2 0x0637 # ARABIC LETTER TAH
0xF2A2 0xFEC1 # ARABIC LETTER TAH ISOLATED FORM
0xF2A3 0x0638 # ARABIC LETTER ZAH
0xF2A3 0xFEC7 # ARABIC LETTER ZAH INITIAL FORM
0xF2A4 0xFEC8 # ARABIC LETTER ZAH MEDIAL FORM
0xF2A5 0xFEC6 # ARABIC LETTER ZAH FINAL FORM
0xF2A6 0xFEC5 # ARABIC LETTER ZAH ISOLATED FORM
0xF2A7 0xFECB # ARABIC LETTER AIN INITIAL FORM
0xF2A8 0xFECC # ARABIC LETTER AIN MEDIAL FORM
0xF2A9 0xFECA # ARABIC LETTER AIN FINAL FORM
0xF2AA 0x0639 # ARABIC LETTER AIN
0xF2AA 0xFEC9 # ARABIC LETTER AIN ISOLATED FORM
0xF2AB 0xFECF # ARABIC LETTER GHAIN INITIAL FORM
0xF2AC 0xFED0 # ARABIC LETTER GHAIN MEDIAL FORM
0xF2AD 0xFECE # ARABIC LETTER GHAIN FINAL FORM
0xF2AE 0x063A # ARABIC LETTER GHAIN
0xF2AE 0xFECD # ARABIC LETTER GHAIN ISOLATED FORM
0xF2AF 0xFED3 # ARABIC LETTER FEH INITIAL FORM
0xF2B0 0xFED4 # ARABIC LETTER FEH MEDIAL FORM
0xF2B1 0xFED2 # ARABIC LETTER FEH FINAL FORM
0xF2B2 0x0641 # ARABIC LETTER FEH
0xF2B2 0xFED1 # ARABIC LETTER FEH ISOLATED FORM
0xF2B3 0xFED7 # ARABIC LETTER QAF INITIAL FORM
0xF2B4 0xFED8 # ARABIC LETTER QAF MEDIAL FORM
0xF2B5 0xFED6 # ARABIC LETTER QAF FINAL FORM
0xF2B6 0x0642 # ARABIC LETTER QAF
0xF2B6 0xFED5 # ARABIC LETTER QAF ISOLATED FORM
0xF2B7 0xFEDB # ARABIC LETTER KAF INITIAL FORM
0xF2B8 0xFEDC # ARABIC LETTER KAF MEDIAL FORM
0xF2B9 0xFEDA # ARABIC LETTER KAF FINAL FORM
0xF2BA 0x0643 # ARABIC LETTER KAF
0xF2BA 0xFED9 # ARABIC LETTER KAF ISOLATED FORM
0xF2BB 0xFEDF # ARABIC LETTER LAM INITIAL FORM
0xF2BC 0xFEE0 # ARABIC LETTER LAM MEDIAL FORM
0xF2BD 0xFEDE # ARABIC LETTER LAM FINAL FORM
0xF2BE 0x0644 # ARABIC LETTER LAM
0xF2BE 0xFEDD # ARABIC LETTER LAM ISOLATED FORM
0xF2BF 0xFEE3 # ARABIC LETTER MEEM INITIAL FORM
0xF2C0 0xFEE4 # ARABIC LETTER MEEM MEDIAL FORM
0xF2C1 0xFEE2 # ARABIC LETTER MEEM FINAL FORM
0xF2C2 0x0645 # ARABIC LETTER MEEM
0xF2C2 0xFEE1 # ARABIC LETTER MEEM ISOLATED FORM
0xF2C3 0xFEE7 # ARABIC LETTER NOON INITIAL FORM
0xF2C4 0xFEE8 # ARABIC LETTER NOON MEDIAL FORM
0xF2C5 0xFEE6 # ARABIC LETTER NOON FINAL FORM
0xF2C6 0x0646 # ARABIC LETTER NOON
0xF2C6 0xFEE5 # ARABIC LETTER NOON ISOLATED FORM
0xF2C7 0xFEEB # ARABIC LETTER HEH INITIAL FORM
0xF2C8 0xFEEC # ARABIC LETTER HEH MEDIAL FORM
0xF2C9 0xFEEA # ARABIC LETTER HEH FINAL FORM
0xF2CA 0x0647 # ARABIC LETTER HEH
0xF2CA 0xFEE9 # ARABIC LETTER HEH ISOLATED FORM
0xF2CB 0x0648 # ARABIC LETTER WAW
0xF2CB 0xFEED # ARABIC LETTER WAW ISOLATED FORM
0xF2CC 0xFEEE # ARABIC LETTER WAW FINAL FORM
0xF2CD 0xFEF3 # ARABIC LETTER YEH INITIAL FORM
0xF2CE 0xFEF4 # ARABIC LETTER YEH MEDIAL FORM
0xF2CF 0xFEF2 # ARABIC LETTER YEH FINAL FORM
0xF2D0 0x064A # ARABIC LETTER YEH
0xF2D0 0xFEF1 # ARABIC LETTER YEH ISOLATED FORM
0xF2D1 0x0629 # ARABIC LETTER TEH MARBUTA
0xF2D1 0xFE93 # ARABIC LETTER TEH MARBUTA ISOLATED FORM
0xF2D2 0xFE94 # ARABIC LETTER TEH MARBUTA FINAL FORM
0xF2D3 0xFEF0 # ARABIC LETTER ALEF MAKSURA FINAL FORM
0xF2D4 0x0649 # ARABIC LETTER ALEF MAKSURA
0xF2D4 0xFEEF # ARABIC LETTER ALEF MAKSURA ISOLATED FORM
0xF2D5 0x0621 # ARABIC LETTER HAMZA
0xF2D6 0xFE8B # ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM
0xF2D7 0xFE8C # ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM
0xF2D8 0xFE8A # ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM
0xF2D9 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE
0xF2D9 0xFE89 # ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM
0xF2DA 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE
0xF2DA 0xFE85 # ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM
0xF2DB 0xFE86 # ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM
0xF2DC 0xFEFB # ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
0xF2DD 0xFEFC # ARABIC LIGATURE LAM WITH ALEF FINAL FORM
0xF2DE 0xFEF7 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
0xF2DF 0xFEF8 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM
0xF2E0 0xFEF5 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
0xF2E1 0xFEF6 # ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM
0xF2E2 0xFEF9 # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
0xF2E3 0xFEFA # ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM
0xF2E4 0x064E # ARABIC FATHA
0xF2E5 0x064F # ARABIC DAMMA
0xF2E6 0x0652 # ARABIC SUKUN
0xF2E7 0x064B # ARABIC FATHATAN
0xF2E8 0x064C # ARABIC DAMMATAN
0xF2E9 0x0651 # ARABIC SHADDA
0xF2EA 0x0650 # ARABIC KASRA
0xF2EB 0x064D # ARABIC KASRATAN
0xF2EC 0xFC60 # ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM
0xF2ED 0xFC61 # ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM
0xF2EF 0xFC5E # ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM
0xF2F0 0xFC62 # ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM
0xF2F1 0xFEC4 # ARABIC LETTER TAH MEDIAL FORM

View File

@ -12,7 +12,7 @@ DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
TESTS =
check_PROGRAMS =
EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
EXTRA_DIST += harfbuzz.cc
EXTRA_DIST += meson.build
EXTRA_DIST += fix_get_types.py
@ -47,9 +47,6 @@ HBLIBS += $(GLIB_LIBS)
HBDEPS += $(GLIB_DEPS)
HBSOURCES += $(HB_GLIB_sources)
HBHEADERS += $(HB_GLIB_headers)
HB_HAS_GLIB_DEF = define HB_HAS_GLIB 1
else
HB_HAS_GLIB_DEF = undef HB_HAS_GLIB
endif
if HAVE_FREETYPE
@ -58,9 +55,6 @@ HBLIBS += $(FREETYPE_LIBS)
HBDEPS += $(FREETYPE_DEPS)
HBSOURCES += $(HB_FT_sources)
HBHEADERS += $(HB_FT_headers)
HB_HAS_FREETYPE_DEF = define HB_HAS_FREETYPE 1
else
HB_HAS_FREETYPE_DEF = undef HB_HAS_FREETYPE
endif
if HAVE_GRAPHITE2
@ -69,9 +63,6 @@ HBLIBS += $(GRAPHITE2_LIBS)
HBDEPS += $(GRAPHITE2_DEPS)
HBSOURCES += $(HB_GRAPHITE2_sources)
HBHEADERS += $(HB_GRAPHITE2_headers)
HB_HAS_GRAPHITE_DEF = define HB_HAS_GRAPHITE 1
else
HB_HAS_GRAPHITE_DEF = undef HB_HAS_GRAPHITE
endif
if HAVE_UNISCRIBE
@ -79,9 +70,6 @@ HBCFLAGS += $(UNISCRIBE_CFLAGS)
HBNONPCLIBS += $(UNISCRIBE_LIBS)
HBSOURCES += $(HB_UNISCRIBE_sources)
HBHEADERS += $(HB_UNISCRIBE_headers)
HB_HAS_UNISCRIBE_DEF = define HB_HAS_UNISCRIBE 1
else
HB_HAS_UNISCRIBE_DEF = undef HB_HAS_UNISCRIBE
endif
if HAVE_DIRECTWRITE
@ -89,9 +77,6 @@ HBCFLAGS += $(DIRECTWRITE_CXXFLAGS)
HBNONPCLIBS += $(DIRECTWRITE_LIBS)
HBSOURCES += $(HB_DIRECTWRITE_sources)
HBHEADERS += $(HB_DIRECTWRITE_headers)
HB_HAS_DIRECTWRITE_DEF = define HB_HAS_DIRECTWRITE 1
else
HB_HAS_DIRECTWRITE_DEF = undef HB_HAS_DIRECTWRITE
endif
if HAVE_GDI
@ -99,9 +84,6 @@ HBCFLAGS += $(GDI_CXXFLAGS)
HBNONPCLIBS += $(GDI_LIBS)
HBSOURCES += $(HB_GDI_sources)
HBHEADERS += $(HB_GDI_headers)
HB_HAS_GDI_DEF = define HB_HAS_GDI 1
else
HB_HAS_GDI_DEF = undef HB_HAS_GDI
endif
if HAVE_CORETEXT
@ -109,9 +91,6 @@ HBCFLAGS += $(CORETEXT_CFLAGS)
HBNONPCLIBS += $(CORETEXT_LIBS)
HBSOURCES += $(HB_CORETEXT_sources)
HBHEADERS += $(HB_CORETEXT_headers)
HB_HAS_CORETEXT_DEF = define HB_HAS_CORETEXT 1
else
HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT
endif
@ -135,8 +114,6 @@ 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_cairo = -export-symbols harfbuzz-cairo.def
harfbuzz_cairo_def_dependency = harfbuzz-cairo.def
export_symbols_icu = -export-symbols harfbuzz-icu.def
harfbuzz_icu_def_dependency = harfbuzz-icu.def
export_symbols_gobject = -export-symbols harfbuzz-gobject.def
@ -170,7 +147,7 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = harfbuzz.pc
cmakedir = $(libdir)/cmake/harfbuzz
cmake_DATA = harfbuzz-config.cmake
EXTRA_DIST += hb-version.h.in hb-features.h.in harfbuzz.pc.in harfbuzz-config.cmake.in
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)
@ -183,36 +160,12 @@ pkginclude_HEADERS += $(HB_SUBSET_headers)
pkgconfig_DATA += harfbuzz-subset.pc
EXTRA_DIST += harfbuzz-subset.pc.in
harfbuzz-subset.cc: Makefile.sources
$(AM_V_GEN) \
LANG=C; \
for f in \
$(HB_BASE_sources) \
$(HB_SUBSET_sources) \
; do echo '#include "'$$f'"'; done | \
sort -u | \
grep '[.]cc"' > $(srcdir)/harfbuzz-subset.cc \
|| ($(RM) $(srcdir)/harfbuzz-subset.cc; false)
BUILT_SOURCES += harfbuzz-subset.cc
lib_LTLIBRARIES += libharfbuzz-cairo.la
libharfbuzz_cairo_la_LINK = $(chosen_linker) $(libharfbuzz_cairo_la_LDFLAGS)
libharfbuzz_cairo_la_SOURCES = $(HB_CAIRO_sources)
libharfbuzz_cairo_la_CPPFLAGS = $(HBCFLAGS) $(CAIRO_CFLAGS) $(CODE_COVERAGE_CFLAGS)
libharfbuzz_cairo_la_LDFLAGS = $(base_link_flags) $(export_symbols_cairo) $(CODE_COVERAGE_LDFLAGS)
libharfbuzz_cairo_la_LIBADD = $(CAIRO_LIBS) libharfbuzz.la
EXTRA_libharfbuzz_cairo_la_DEPENDENCIES = $(harfbuzz_cairo_def_dependency)
pkginclude_HEADERS += $(HB_CAIRO_headers)
pkgconfig_DATA += harfbuzz-cairo.pc
EXTRA_DIST += harfbuzz-cairo.pc.in
if HAVE_ICU
if HAVE_ICU_BUILTIN
HBCFLAGS += $(ICU_CFLAGS)
HBLIBS += $(ICU_LIBS)
HBSOURCES += $(HB_ICU_sources)
HBHEADERS += $(HB_ICU_headers)
HB_HAS_ICU_DEF = define HB_HAS_ICU 1
else
lib_LTLIBRARIES += libharfbuzz-icu.la
libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources)
@ -222,7 +175,6 @@ 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
HB_HAS_ICU_DEF = undef HB_HAS_ICU
endif
endif
EXTRA_DIST += harfbuzz-icu.pc.in
@ -254,9 +206,6 @@ hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS)
--template $^ | \
sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \
|| ($(RM) "$@"; false)
HB_HAS_GOBJECT_DEF = define HB_HAS_GOBJECT 1
else
HB_HAS_GOBJECT_DEF = undef HB_HAS_GOBJECT
endif
EXTRA_DIST += \
harfbuzz-gobject.pc.in \
@ -265,27 +214,6 @@ EXTRA_DIST += \
$(NULL)
BUILT_SOURCES += \
hb-features.h
DISTCLEANFILES += \
hb-features.h
hb-features.h: hb-features.h.in $(top_builddir)/config.status
$(AM_V_GEN) $(SED) \
-e 's/mesondefine HB_HAS_CAIRO/$(HB_HAS_CAIRO_DEF)/' \
-e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \
-e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
-e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \
-e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \
-e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \
-e 's/mesondefine HB_HAS_GOBJECT/$(HB_HAS_GOBJECT_DEF)/' \
-e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \
-e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \
-e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \
-e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \
"$<" > "$@" || ($(RM) "$@"; false)
%.pc: %.pc.in $(top_builddir)/config.status
$(AM_V_GEN) \
$(SED) -e 's@%prefix%@$(prefix)@g' \
@ -312,8 +240,6 @@ harfbuzz.def: $(HBHEADERS)
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-subset.def: $(HB_SUBSET_headers)
$(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^
harfbuzz-cairo.def: $(HB_CAIRO_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)
@ -358,7 +284,6 @@ $(srcdir)/%.hh: $(srcdir)/%.rl
harfbuzz.cc: Makefile.sources
$(AM_V_GEN) \
LANG=C; \
for f in \
$(HB_BASE_sources) \
$(HB_GLIB_sources) \
@ -369,7 +294,6 @@ harfbuzz.cc: Makefile.sources
$(HB_DIRECTWRITE_sources) \
$(HB_CORETEXT_sources) \
; do echo '#include "'$$f'"'; done | \
sort -u | \
grep '[.]cc"' > $(srcdir)/harfbuzz.cc \
|| ($(RM) $(srcdir)/harfbuzz.cc; false)
BUILT_SOURCES += harfbuzz.cc
@ -382,9 +306,7 @@ noinst_PROGRAMS = \
test-ot-name \
test-ot-glyphname \
test-gpos-size-params \
test-gsub-get-alternates \
test-gsub-would-substitute \
test-use-table \
$(NULL)
bin_PROGRAMS =
@ -412,18 +334,10 @@ test_ot_glyphname_SOURCES = test-ot-glyphname.cc
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
test_use_table_SOURCES = test-use-table.cc
test_use_table_CPPFLAGS = $(HBCFLAGS)
test_use_table_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_get_alternates_SOURCES = test-gsub-get-alternates.cc
test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS)
test_gsub_get_alternates_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)
@ -435,7 +349,6 @@ COMPILED_TESTS = \
test-iter \
test-machinery \
test-map \
test-multimap \
test-number \
test-ot-tag \
test-priority-queue \
@ -444,7 +357,6 @@ COMPILED_TESTS = \
test-unicode-ranges \
test-vector \
test-repacker \
test-classdef-graph \
$(NULL)
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
@ -475,10 +387,6 @@ test_map_SOURCES = test-map.cc hb-static.cc
test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_map_LDADD = $(COMPILED_TESTS_LDADD)
test_multimap_SOURCES = test-multimap.cc hb-static.cc
test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_multimap_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)
@ -491,14 +399,10 @@ 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 graph/gsubgpos-context.cc
test_repacker_SOURCES = test-repacker.cc hb-static.cc
test_repacker_CPPFLAGS = $(HBCFLAGS)
test_repacker_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
test_classdef_graph_SOURCES = graph/test-classdef-graph.cc hb-static.cc graph/gsubgpos-context.cc
test_classdef_graph_CPPFLAGS = $(HBCFLAGS)
test_classdef_graph_LDADD = libharfbuzz.la libharfbuzz-subset.la $(HBLIBS)
test_set_SOURCES = test-set.cc hb-static.cc
test_set_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
test_set_LDADD = $(COMPILED_TESTS_LDADD)

View File

@ -42,19 +42,16 @@ HB_BASE_sources = \
hb-draw.hh \
hb-face.cc \
hb-face.hh \
hb-face-builder.cc \
hb-fallback-shape.cc \
hb-font.cc \
hb-font.hh \
hb-iter.hh \
hb-kern.hh \
hb-limits.hh \
hb-machinery.hh \
hb-map.cc \
hb-map.hh \
hb-meta.hh \
hb-ms-feature-ranges.hh \
hb-multimap.hh \
hb-mutex.hh \
hb-null.hh \
hb-number.cc \
@ -69,6 +66,11 @@ HB_BASE_sources = \
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 \
@ -85,91 +87,29 @@ HB_BASE_sources = \
hb-ot-layout-common.hh \
hb-ot-layout-gdef-table.hh \
hb-ot-layout-gpos-table.hh \
hb-outline.hh \
hb-outline.cc \
hb-paint.cc \
hb-paint.hh \
hb-paint-extents.cc \
hb-paint-extents.hh \
hb-ot-layout-gsub-table.hh \
OT/Color/CBDT/CBDT.hh \
OT/Color/COLR/COLR.hh \
OT/Color/CPAL/CPAL.hh \
OT/Color/sbix/sbix.hh \
OT/Color/svg/svg.hh \
OT/glyf/glyf.hh \
OT/glyf/glyf-helpers.hh \
OT/glyf/loca.hh \
OT/glyf/path-builder.hh \
OT/glyf/Glyph.hh \
OT/glyf/GlyphHeader.hh \
OT/glyf/SimpleGlyph.hh \
OT/glyf/coord-setter.hh \
OT/glyf/composite-iter.hh \
OT/glyf/CompositeGlyph.hh \
OT/glyf/VarCompositeGlyph.hh \
OT/glyf/SubsetGlyph.hh \
OT/Layout/types.hh \
OT/Layout/Common/Coverage.hh \
OT/Layout/Common/CoverageFormat1.hh \
OT/Layout/Common/CoverageFormat2.hh \
OT/Layout/Common/RangeRecord.hh \
OT/Layout/GDEF/GDEF.hh \
OT/Layout/GPOS/AnchorFormat1.hh \
OT/Layout/GPOS/AnchorFormat2.hh \
OT/Layout/GPOS/AnchorFormat3.hh \
OT/Layout/GPOS/Anchor.hh \
OT/Layout/GPOS/AnchorMatrix.hh \
OT/Layout/GPOS/ChainContextPos.hh \
OT/Layout/GPOS/Common.hh \
OT/Layout/GPOS/ContextPos.hh \
OT/Layout/GPOS/CursivePosFormat1.hh \
OT/Layout/GPOS/CursivePos.hh \
OT/Layout/GPOS/ExtensionPos.hh \
OT/Layout/GPOS/GPOS.hh \
OT/Layout/GPOS/LigatureArray.hh \
OT/Layout/GPOS/MarkArray.hh \
OT/Layout/GPOS/MarkBasePosFormat1.hh \
OT/Layout/GPOS/MarkBasePos.hh \
OT/Layout/GPOS/MarkLigPosFormat1.hh \
OT/Layout/GPOS/MarkLigPos.hh \
OT/Layout/GPOS/MarkMarkPosFormat1.hh \
OT/Layout/GPOS/MarkMarkPos.hh \
OT/Layout/GPOS/MarkRecord.hh \
OT/Layout/GPOS/PairPosFormat1.hh \
OT/Layout/GPOS/PairPosFormat2.hh \
OT/Layout/GPOS/PairPos.hh \
OT/Layout/GPOS/PairSet.hh \
OT/Layout/GPOS/PairValueRecord.hh \
OT/Layout/GPOS/PosLookup.hh \
OT/Layout/GPOS/PosLookupSubTable.hh \
OT/Layout/GPOS/SinglePosFormat1.hh \
OT/Layout/GPOS/SinglePosFormat2.hh \
OT/Layout/GPOS/SinglePos.hh \
OT/Layout/GPOS/ValueFormat.hh \
OT/Layout/GSUB/AlternateSet.hh \
OT/Layout/GSUB/AlternateSubstFormat1.hh \
OT/Layout/GSUB/AlternateSubst.hh \
OT/Layout/GSUB/ChainContextSubst.hh \
OT/Layout/GSUB/Common.hh \
OT/Layout/GSUB/ContextSubst.hh \
OT/Layout/GSUB/ExtensionSubst.hh \
OT/Layout/GSUB/GSUB.hh \
OT/Layout/GSUB/Ligature.hh \
OT/Layout/GSUB/LigatureSet.hh \
OT/Layout/GSUB/LigatureSubstFormat1.hh \
OT/Layout/GSUB/LigatureSubst.hh \
OT/Layout/GSUB/MultipleSubstFormat1.hh \
OT/Layout/GSUB/MultipleSubst.hh \
OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
OT/Layout/GSUB/ReverseChainSingleSubst.hh \
OT/Layout/GSUB/Sequence.hh \
OT/Layout/GSUB/SingleSubstFormat1.hh \
OT/Layout/GSUB/SingleSubstFormat2.hh \
OT/Layout/GSUB/SingleSubst.hh \
OT/Layout/GSUB/SubstLookup.hh \
OT/Layout/GSUB/MultipleSubstFormat1.hh \
OT/Layout/GSUB/MultipleSubst.hh \
OT/Layout/GSUB/AlternateSubstFormat1.hh \
OT/Layout/GSUB/AlternateSubst.hh \
OT/Layout/GSUB/AlternateSet.hh \
OT/Layout/GSUB/LigatureSubstFormat1.hh \
OT/Layout/GSUB/LigatureSubst.hh \
OT/Layout/GSUB/LigatureSet.hh \
OT/Layout/GSUB/Ligature.hh \
OT/Layout/GSUB/ReverseChainSingleSubst.hh \
OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh \
OT/Layout/GSUB/ContextSubst.hh \
OT/Layout/GSUB/ChainContextSubst.hh \
OT/Layout/GSUB/ExtensionSubst.hh \
OT/Layout/GSUB/SubstLookupSubTable.hh \
OT/name/name.hh \
OT/Layout/GSUB/SubstLookup.hh \
OT/Layout/GSUB/GSUB.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout.cc \
@ -193,7 +133,6 @@ HB_BASE_sources = \
hb-ot-post-table.hh \
hb-ot-shaper-arabic-fallback.hh \
hb-ot-shaper-arabic-joining-list.hh \
hb-ot-shaper-arabic-pua.hh \
hb-ot-shaper-arabic-table.hh \
hb-ot-shaper-arabic-win1256.hh \
hb-ot-shaper-arabic.cc \
@ -205,7 +144,9 @@ HB_BASE_sources = \
hb-ot-shaper-indic.cc \
hb-ot-shaper-indic.hh \
hb-ot-shaper-khmer.cc \
hb-ot-shaper-khmer.hh \
hb-ot-shaper-myanmar.cc \
hb-ot-shaper-myanmar.hh \
hb-ot-shaper-syllabic.cc \
hb-ot-shaper-syllabic.hh \
hb-ot-shaper-thai.cc \
@ -225,7 +166,6 @@ HB_BASE_sources = \
hb-ot-tag.cc \
hb-ot-var-avar-table.hh \
hb-ot-var-common.hh \
hb-ot-var-cvar-table.hh \
hb-ot-var-fvar-table.hh \
hb-ot-var-gvar-table.hh \
hb-ot-var-hvar-table.hh \
@ -261,8 +201,7 @@ HB_BASE_sources = \
HB_BASE_RAGEL_GENERATED_sources = \
hb-buffer-deserialize-json.hh \
hb-buffer-deserialize-text-glyphs.hh \
hb-buffer-deserialize-text-unicode.hh \
hb-buffer-deserialize-text.hh \
hb-number-parser.hh \
hb-ot-shaper-indic-machine.hh \
hb-ot-shaper-khmer-machine.hh \
@ -271,8 +210,7 @@ HB_BASE_RAGEL_GENERATED_sources = \
$(NULL)
HB_BASE_RAGEL_sources = \
hb-buffer-deserialize-json.rl \
hb-buffer-deserialize-text-glyphs.rl \
hb-buffer-deserialize-text-unicode.rl \
hb-buffer-deserialize-text.rl \
hb-number-parser.rl \
hb-ot-shaper-indic-machine.rl \
hb-ot-shaper-khmer-machine.rl \
@ -303,7 +241,6 @@ HB_BASE_headers = \
hb-ot-shape.h \
hb-ot-var.h \
hb-ot.h \
hb-paint.h \
hb-set.h \
hb-shape-plan.h \
hb-shape.h \
@ -315,7 +252,7 @@ HB_BASE_headers = \
# Optional Sources and Headers with external deps
HB_FT_sources = hb-ft.cc hb-ft-colr.hh
HB_FT_sources = hb-ft.cc
HB_FT_headers = hb-ft.h
HB_GLIB_sources = hb-glib.cc
@ -348,6 +285,7 @@ HB_SUBSET_sources = \
hb-number.hh \
hb-ot-cff1-table.cc \
hb-ot-cff2-table.cc \
hb-ot-color-colrv1-closure.hh \
hb-ot-post-table-v2subset.hh \
hb-static.cc \
hb-subset-cff-common.cc \
@ -358,25 +296,12 @@ HB_SUBSET_sources = \
hb-subset-cff2.hh \
hb-subset-input.cc \
hb-subset-input.hh \
hb-subset-instancer-solver.cc \
hb-subset-accelerator.hh \
hb-subset-plan.cc \
hb-subset-plan.hh \
hb-subset-repacker.cc \
hb-subset.cc \
hb-subset.hh \
hb-repacker.hh \
graph/graph.hh \
graph/gsubgpos-graph.hh \
graph/gsubgpos-context.hh \
graph/gsubgpos-context.cc \
graph/coverage-graph.hh \
graph/classdef-graph.hh \
graph/pairpos-graph.hh \
graph/markbasepos-graph.hh \
graph/split-helpers.hh \
graph/serialize.hh \
OT/Color/COLR/colrv1-closure.hh \
$(NULL)
HB_SUBSET_headers = \
@ -384,16 +309,6 @@ HB_SUBSET_headers = \
hb-subset-repacker.h \
$(NULL)
HB_CAIRO_sources = \
hb-cairo.cc \
hb-cairo-utils.cc \
hb-cairo-utils.hh \
hb-static.cc \
$(NULL)
HB_CAIRO_headers = \
hb-cairo.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

View File

@ -1,337 +0,0 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_COVERAGE_HH
#define OT_LAYOUT_COMMON_COVERAGE_HH
#include "../types.hh"
#include "CoverageFormat1.hh"
#include "CoverageFormat2.hh"
namespace OT {
namespace Layout {
namespace Common {
template<typename Iterator>
static inline void Coverage_serialize (hb_serialize_context_t *c,
Iterator it);
struct Coverage
{
protected:
union {
HBUINT16 format; /* Format identifier */
CoverageFormat1_3<SmallTypes> format1;
CoverageFormat2_4<SmallTypes> format2;
#ifndef HB_NO_BEYOND_64K
CoverageFormat1_3<MediumTypes>format3;
CoverageFormat2_4<MediumTypes>format4;
#endif
} u;
public:
DEFINE_SIZE_UNION (2, format);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format)
{
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
#endif
default:return_trace (true);
}
}
/* Has interface. */
unsigned operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
unsigned int get (hb_codepoint_t k) const { return get_coverage (k); }
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1: return u.format1.get_coverage (glyph_id);
case 2: return u.format2.get_coverage (glyph_id);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_coverage (glyph_id);
case 4: return u.format4.get_coverage (glyph_id);
#endif
default:return NOT_COVERED;
}
}
unsigned get_population () const
{
switch (u.format) {
case 1: return u.format1.get_population ();
case 2: return u.format2.get_population ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_population ();
case 4: return u.format4.get_population ();
#endif
default:return NOT_COVERED;
}
}
template <typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned count = 0;
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
for (auto g: glyphs)
{
if (last + 1 != g)
num_ranges++;
last = g;
count++;
}
u.format = count <= num_ranges * 3 ? 1 : 2;
#ifndef HB_NO_BEYOND_64K
if (count && last > 0xFFFFu)
u.format += 2;
#endif
switch (u.format)
{
case 1: return_trace (u.format1.serialize (c, glyphs));
case 2: return_trace (u.format2.serialize (c, glyphs));
#ifndef HB_NO_BEYOND_64K
case 3: return_trace (u.format3.serialize (c, glyphs));
case 4: return_trace (u.format4.serialize (c, glyphs));
#endif
default:return_trace (false);
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto it =
+ iter ()
| hb_take (c->plan->source->get_num_glyphs ())
| hb_filter (c->plan->glyph_map_gsub)
| hb_map_retains_sorting (c->plan->glyph_map_gsub)
;
// Cache the iterator result as it will be iterated multiple times
// by the serialize code below.
hb_sorted_vector_t<hb_codepoint_t> glyphs (it);
Coverage_serialize (c->serializer, glyphs.iter ());
return_trace (bool (glyphs));
}
bool intersects (const hb_set_t *glyphs) const
{
switch (u.format)
{
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersects (glyphs);
case 4: return u.format4.intersects (glyphs);
#endif
default:return false;
}
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
switch (u.format)
{
case 1: return u.format1.intersects_coverage (glyphs, index);
case 2: return u.format2.intersects_coverage (glyphs, index);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersects_coverage (glyphs, index);
case 4: return u.format4.intersects_coverage (glyphs, index);
#endif
default:return false;
}
}
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
switch (u.format)
{
case 1: return u.format1.collect_coverage (glyphs);
case 2: return u.format2.collect_coverage (glyphs);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.collect_coverage (glyphs);
case 4: return u.format4.collect_coverage (glyphs);
#endif
default:return false;
}
}
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
switch (u.format)
{
case 1: return u.format1.intersect_set (glyphs, intersect_glyphs);
case 2: return u.format2.intersect_set (glyphs, intersect_glyphs);
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.intersect_set (glyphs, intersect_glyphs);
case 4: return u.format4.intersect_set (glyphs, intersect_glyphs);
#endif
default:return ;
}
}
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
iter_t (const Coverage &c_ = Null (Coverage))
{
hb_memset (this, 0, sizeof (*this));
format = c_.u.format;
switch (format)
{
case 1: u.format1.init (c_.u.format1); return;
case 2: u.format2.init (c_.u.format2); return;
#ifndef HB_NO_BEYOND_64K
case 3: u.format3.init (c_.u.format3); return;
case 4: u.format4.init (c_.u.format4); return;
#endif
default: return;
}
}
bool __more__ () const
{
switch (format)
{
case 1: return u.format1.__more__ ();
case 2: return u.format2.__more__ ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.__more__ ();
case 4: return u.format4.__more__ ();
#endif
default:return false;
}
}
void __next__ ()
{
switch (format)
{
case 1: u.format1.__next__ (); break;
case 2: u.format2.__next__ (); break;
#ifndef HB_NO_BEYOND_64K
case 3: u.format3.__next__ (); break;
case 4: u.format4.__next__ (); break;
#endif
default: break;
}
}
typedef hb_codepoint_t __item_t__;
__item_t__ __item__ () const { return get_glyph (); }
hb_codepoint_t get_glyph () const
{
switch (format)
{
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3.get_glyph ();
case 4: return u.format4.get_glyph ();
#endif
default:return 0;
}
}
bool operator != (const iter_t& o) const
{
if (unlikely (format != o.format)) return true;
switch (format)
{
case 1: return u.format1 != o.u.format1;
case 2: return u.format2 != o.u.format2;
#ifndef HB_NO_BEYOND_64K
case 3: return u.format3 != o.u.format3;
case 4: return u.format4 != o.u.format4;
#endif
default:return false;
}
}
iter_t __end__ () const
{
iter_t it = {};
it.format = format;
switch (format)
{
case 1: it.u.format1 = u.format1.__end__ (); break;
case 2: it.u.format2 = u.format2.__end__ (); break;
#ifndef HB_NO_BEYOND_64K
case 3: it.u.format3 = u.format3.__end__ (); break;
case 4: it.u.format4 = u.format4.__end__ (); break;
#endif
default: break;
}
return it;
}
private:
unsigned int format;
union {
#ifndef HB_NO_BEYOND_64K
CoverageFormat2_4<MediumTypes>::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */
CoverageFormat1_3<MediumTypes>::iter_t format3;
#endif
CoverageFormat2_4<SmallTypes>::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */
CoverageFormat1_3<SmallTypes>::iter_t format1;
} u;
};
iter_t iter () const { return iter_t (*this); }
};
template<typename Iterator>
static inline void
Coverage_serialize (hb_serialize_context_t *c,
Iterator it)
{ c->start_embed<Coverage> ()->serialize (c, it); }
}
}
}
#endif // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH

View File

@ -1,133 +0,0 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
#define OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH
namespace OT {
namespace Layout {
namespace Common {
#define NOT_COVERED ((unsigned int) -1)
template <typename Types>
struct CoverageFormat1_3
{
friend struct Coverage;
protected:
HBUINT16 coverageFormat; /* Format identifier--format = 1 */
SortedArray16Of<typename Types::HBGlyphID>
glyphArray; /* Array of GlyphIDs--in numerical order */
public:
DEFINE_SIZE_ARRAY (4, glyphArray);
private:
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (glyphArray.sanitize (c));
}
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
unsigned int i;
glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED);
return i;
}
unsigned get_population () const
{
return glyphArray.len;
}
template <typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
return_trace (glyphArray.serialize (c, glyphs));
}
bool intersects (const hb_set_t *glyphs) const
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
{
for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
}
for (const auto& g : glyphArray.as_array ())
if (glyphs->has (g))
return true;
return false;
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{ return glyphs->has (glyphArray[index]); }
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
unsigned count = glyphArray.len;
for (unsigned i = 0; i < count; i++)
if (glyphs.has (glyphArray[i]))
intersect_glyphs << glyphArray[i];
}
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{ return glyphs->add_sorted_array (glyphArray.as_array ()); }
public:
/* Older compilers need this to be public. */
struct iter_t
{
void init (const struct CoverageFormat1_3 &c_) { c = &c_; i = 0; }
bool __more__ () const { return i < c->glyphArray.len; }
void __next__ () { i++; }
hb_codepoint_t get_glyph () const { return c->glyphArray[i]; }
bool operator != (const iter_t& o) const
{ return i != o.i; }
iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; }
private:
const struct CoverageFormat1_3 *c;
unsigned int i;
};
private:
};
}
}
}
#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH

View File

@ -1,232 +0,0 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
#define OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH
#include "RangeRecord.hh"
namespace OT {
namespace Layout {
namespace Common {
template <typename Types>
struct CoverageFormat2_4
{
friend struct Coverage;
protected:
HBUINT16 coverageFormat; /* Format identifier--format = 2 */
SortedArray16Of<RangeRecord<Types>>
rangeRecord; /* Array of glyph ranges--ordered by
* Start GlyphID. rangeCount entries
* long */
public:
DEFINE_SIZE_ARRAY (4, rangeRecord);
private:
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (rangeRecord.sanitize (c));
}
unsigned int get_coverage (hb_codepoint_t glyph_id) const
{
const RangeRecord<Types> &range = rangeRecord.bsearch (glyph_id);
return likely (range.first <= range.last)
? (unsigned int) range.value + (glyph_id - range.first)
: NOT_COVERED;
}
unsigned get_population () const
{
typename Types::large_int ret = 0;
for (const auto &r : rangeRecord)
ret += r.get_population ();
return ret > UINT_MAX ? UINT_MAX : (unsigned) ret;
}
template <typename Iterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
bool serialize (hb_serialize_context_t *c, Iterator glyphs)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
for (auto g: glyphs)
{
if (last + 1 != g)
num_ranges++;
last = g;
}
if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false);
if (!num_ranges) return_trace (true);
unsigned count = 0;
unsigned range = (unsigned) -1;
last = (hb_codepoint_t) -2;
for (auto g: glyphs)
{
if (last + 1 != g)
{
range++;
rangeRecord[range].first = g;
rangeRecord[range].value = count;
}
rangeRecord[range].last = g;
last = g;
count++;
}
return_trace (true);
}
bool intersects (const hb_set_t *glyphs) const
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
}
return hb_any (+ hb_iter (rangeRecord)
| hb_map ([glyphs] (const RangeRecord<Types> &range) { return range.intersects (*glyphs); }));
}
bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
{
auto *range = rangeRecord.as_array ().bsearch (index);
if (range)
return range->intersects (*glyphs);
return false;
}
template <typename IterableOut,
hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))>
void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const
{
/* Break out of loop for overlapping, broken, tables,
* to avoid fuzzer timouts. */
hb_codepoint_t last = 0;
for (const auto& range : rangeRecord)
{
if (unlikely (range.first < last))
break;
last = range.last;
for (hb_codepoint_t g = range.first - 1;
glyphs.next (&g) && g <= last;)
intersect_glyphs << g;
}
}
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
for (const auto& range: rangeRecord)
if (unlikely (!range.collect_coverage (glyphs)))
return false;
return true;
}
public:
/* Older compilers need this to be public. */
struct iter_t
{
void init (const CoverageFormat2_4 &c_)
{
c = &c_;
coverage = 0;
i = 0;
j = c->rangeRecord.len ? c->rangeRecord[0].first : 0;
if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last))
{
/* Broken table. Skip. */
i = c->rangeRecord.len;
j = 0;
}
}
bool __more__ () const { return i < c->rangeRecord.len; }
void __next__ ()
{
if (j >= c->rangeRecord[i].last)
{
i++;
if (__more__ ())
{
unsigned int old = coverage;
j = c->rangeRecord[i].first;
coverage = c->rangeRecord[i].value;
if (unlikely (coverage != old + 1))
{
/* Broken table. Skip. Important to avoid DoS.
* Also, our callers depend on coverage being
* consecutive and monotonically increasing,
* ie. iota(). */
i = c->rangeRecord.len;
j = 0;
return;
}
}
else
j = 0;
return;
}
coverage++;
j++;
}
hb_codepoint_t get_glyph () const { return j; }
bool operator != (const iter_t& o) const
{ return i != o.i || j != o.j; }
iter_t __end__ () const
{
iter_t it;
it.init (*c);
it.i = c->rangeRecord.len;
it.j = 0;
return it;
}
private:
const struct CoverageFormat2_4 *c;
unsigned int i, coverage;
hb_codepoint_t j;
};
private:
};
}
}
}
#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH

View File

@ -1,85 +0,0 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod, Garret Rieger
*/
#ifndef OT_LAYOUT_COMMON_RANGERECORD_HH
#define OT_LAYOUT_COMMON_RANGERECORD_HH
namespace OT {
namespace Layout {
namespace Common {
template <typename Types>
struct RangeRecord
{
typename Types::HBGlyphID first; /* First GlyphID in the range */
typename Types::HBGlyphID last; /* Last GlyphID in the range */
HBUINT16 value; /* Value */
DEFINE_SIZE_STATIC (2 + 2 * Types::size);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
unsigned get_population () const
{
if (unlikely (last < first)) return 0;
return (last - first + 1);
}
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); }
};
}
}
}
// TODO(garretrieger): This was previously implemented using
// DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (OT, RangeRecord, 9);
// but that only works when there is only a single namespace level.
// The macro should probably be fixed so it can work in this situation.
extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9];
template <typename Spec>
struct Null<OT::Layout::Common::RangeRecord<Spec>> {
static OT::Layout::Common::RangeRecord<Spec> const & get_null () {
return *reinterpret_cast<const OT::Layout::Common::RangeRecord<Spec> *> (_hb_Null_OT_RangeRecord);
}
};
#endif // #ifndef OT_LAYOUT_COMMON_RANGERECORD_HH

View File

@ -1,918 +0,0 @@
/*
* Copyright © 2007,2008,2009 Red Hat, Inc.
* Copyright © 2010,2011,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
#ifndef OT_LAYOUT_GDEF_GDEF_HH
#define OT_LAYOUT_GDEF_GDEF_HH
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-font.hh"
namespace OT {
/*
* Attachment List Table
*/
/* Array of contour point indices--in increasing numerical order */
struct AttachPoint : Array16Of<HBUINT16>
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (out->serialize (c->serializer, + iter ()));
}
};
struct AttachList
{
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (point_count)
*point_count = 0;
return 0;
}
const AttachPoint &points = this+attachPoint[index];
if (point_count)
{
+ points.as_array ().sub_array (start_offset, point_count)
| hb_sink (hb_array (point_array, *point_count))
;
}
return points.len;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, attachPoint)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
}
protected:
Offset16To<Coverage>
coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
Array16OfOffset16To<AttachPoint>
attachPoint; /* Array of AttachPoint tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, attachPoint);
};
/*
* Ligature Caret Table
*/
struct CaretValueFormat1
{
friend struct CaretValue;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (true);
}
private:
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 1 */
FWORD coordinate; /* X or Y value, in design units */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat2
{
friend struct CaretValue;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (true);
}
private:
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
{
hb_position_t x, y;
font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 2 */
HBUINT16 caretValuePoint; /* Contour point index on glyph */
public:
DEFINE_SIZE_STATIC (4);
};
struct CaretValueFormat3
{
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
const VariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
if (!c->serializer->embed (caretValueFormat)) return_trace (false);
if (!c->serializer->embed (coordinate)) return_trace (false);
unsigned varidx = (this+deviceTable).get_variation_index ();
if (c->plan->layout_variation_idx_delta_map.has (varidx))
{
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
}
if (c->plan->all_axes_pinned)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
return_trace (false);
return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ (this+deviceTable).collect_variation_indices (c); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
}
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */
Offset16To<Device>
deviceTable; /* Offset to Device table for X or Y
* value--from beginning of CaretValue
* table */
public:
DEFINE_SIZE_STATIC (6);
};
struct CaretValue
{
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
case 2: return u.format2.get_caret_value (font, direction, glyph_id);
case 3: return u.format3.get_caret_value (font, direction, var_store);
default:return 0;
}
}
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.format) {
case 1:
case 2:
return;
case 3:
u.format3.collect_variation_indices (c);
return;
default: return;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
CaretValueFormat1 format1;
CaretValueFormat2 format2;
CaretValueFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
struct LigGlyph
{
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
if (caret_count)
{
+ carets.as_array ().sub_array (start_offset, caret_count)
| hb_map (hb_add (this))
| hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
| hb_sink (hb_array (caret_array, *caret_count))
;
}
return carets.len;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_iter (carets)
| hb_apply (subset_offset_array (c, out->carets, this))
;
return_trace (bool (out->carets));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (const Offset16To<CaretValue>& offset : carets.iter ())
(this+offset).collect_variation_indices (c);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (carets.sanitize (c, this));
}
protected:
Array16OfOffset16To<CaretValue>
carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
* --in increasing coordinate order */
public:
DEFINE_SIZE_ARRAY (2, carets);
};
struct LigCaretList
{
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
const VariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED)
{
if (caret_count)
*caret_count = 0;
return 0;
}
const LigGlyph &lig_glyph = this+ligGlyph[index];
return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, ligGlyph)
| hb_filter (glyphset, hb_first)
| hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+coverage, ligGlyph)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
}
protected:
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
Array16OfOffset16To<LigGlyph>
ligGlyph; /* Array of LigGlyph tables
* in Coverage Index order */
public:
DEFINE_SIZE_ARRAY (4, ligGlyph);
};
struct MarkGlyphSetsFormat1
{
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
bool ret = true;
for (const Offset32To<Coverage>& offset : coverage.iter ())
{
auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o))
{
ret = false;
break;
}
//not using o->serialize_subset (c, offset, this, out) here because
//OTS doesn't allow null offset.
//See issue: https://github.com/khaledhosny/ots/issues/172
c->serializer->push ();
c->dispatch (this+offset);
c->serializer->add_link (*o, c->serializer->pop_pack ());
}
return_trace (ret && out->coverage.len);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Array16Of<Offset32To<Coverage>>
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
DEFINE_SIZE_ARRAY (4, coverage);
};
struct MarkGlyphSets
{
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{
switch (u.format) {
case 1: return u.format1.covers (set_index, glyph_id);
default:return false;
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
switch (u.format) {
case 1: return_trace (u.format1.subset (c));
default:return_trace (false);
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
protected:
union {
HBUINT16 format; /* Format identifier */
MarkGlyphSetsFormat1 format1;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
/*
* GDEF -- Glyph Definition
* https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
*/
template <typename Types>
struct GDEFVersion1_2
{
friend struct GDEF;
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
* 0x00010003u */
typename Types::template OffsetTo<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
* GDEF header (may be Null) */
typename Types::template OffsetTo<AttachList>
attachList; /* Offset to list of glyphs with
* attachment points--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<LigCaretList>
ligCaretList; /* Offset to list of positioning points
* for ligature carets--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<ClassDef>
markAttachClassDef; /* Offset to class definition table for
* mark attachment type--from beginning
* of GDEF header (may be Null) */
typename Types::template OffsetTo<MarkGlyphSets>
markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
Offset32To<VariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010003. */
public:
DEFINE_SIZE_MIN (4 + 4 * Types::size);
unsigned int get_size () const
{
return min_size +
(version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
(version.to_int () >= 0x00010003u ? varStore.static_size : 0);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
glyphClassDef.sanitize (c, this) &&
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_markglyphsetsdef = false;
if (version.to_int () >= 0x00010002u)
{
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
}
bool subset_varstore = false;
if (version.to_int () >= 0x00010003u)
{
if (c->plan->all_axes_pinned)
out->varStore = 0;
else
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
}
if (subset_varstore)
{
out->version.minor = 3;
} else if (subset_markglyphsetsdef) {
out->version.minor = 2;
} else {
out->version.minor = 0;
}
return_trace (subset_glyphclassdef || subset_attachlist ||
subset_ligcaretlist || subset_markattachclassdef ||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
(out->version.to_int () >= 0x00010003u && subset_varstore));
}
};
struct GDEF
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
enum GlyphClasses {
UnclassifiedGlyph = 0,
BaseGlyph = 1,
LigatureGlyph = 2,
MarkGlyph = 3,
ComponentGlyph = 4
};
unsigned int get_size () const
{
switch (u.version.major) {
case 1: return u.version1.get_size ();
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.get_size ();
#endif
default: return u.version.static_size;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false);
switch (u.version.major) {
case 1: return_trace (u.version1.sanitize (c));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (u.version2.sanitize (c));
#endif
default: return_trace (true);
}
}
bool subset (hb_subset_context_t *c) const
{
switch (u.version.major) {
case 1: return u.version1.subset (c);
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.subset (c);
#endif
default: return false;
}
}
bool has_glyph_classes () const
{
switch (u.version.major) {
case 1: return u.version1.glyphClassDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.glyphClassDef != 0;
#endif
default: return false;
}
}
const ClassDef &get_glyph_class_def () const
{
switch (u.version.major) {
case 1: return this+u.version1.glyphClassDef;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.glyphClassDef;
#endif
default: return Null(ClassDef);
}
}
bool has_attach_list () const
{
switch (u.version.major) {
case 1: return u.version1.attachList != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.attachList != 0;
#endif
default: return false;
}
}
const AttachList &get_attach_list () const
{
switch (u.version.major) {
case 1: return this+u.version1.attachList;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.attachList;
#endif
default: return Null(AttachList);
}
}
bool has_lig_carets () const
{
switch (u.version.major) {
case 1: return u.version1.ligCaretList != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.ligCaretList != 0;
#endif
default: return false;
}
}
const LigCaretList &get_lig_caret_list () const
{
switch (u.version.major) {
case 1: return this+u.version1.ligCaretList;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.ligCaretList;
#endif
default: return Null(LigCaretList);
}
}
bool has_mark_attachment_types () const
{
switch (u.version.major) {
case 1: return u.version1.markAttachClassDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.markAttachClassDef != 0;
#endif
default: return false;
}
}
const ClassDef &get_mark_attach_class_def () const
{
switch (u.version.major) {
case 1: return this+u.version1.markAttachClassDef;
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.markAttachClassDef;
#endif
default: return Null(ClassDef);
}
}
bool has_mark_glyph_sets () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.markGlyphSetsDef != 0;
#endif
default: return false;
}
}
const MarkGlyphSets &get_mark_glyph_sets () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.markGlyphSetsDef;
#endif
default: return Null(MarkGlyphSets);
}
}
bool has_var_store () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
#ifndef HB_NO_BEYOND_64K
case 2: return u.version2.varStore != 0;
#endif
default: return false;
}
}
const VariationStore &get_var_store () const
{
switch (u.version.major) {
case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
default: return Null(VariationStore);
}
}
bool has_data () const { return u.version.to_int (); }
unsigned int get_glyph_class (hb_codepoint_t glyph) const
{ return get_glyph_class_def ().get_class (glyph); }
void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
{ get_glyph_class_def ().collect_class (glyphs, klass); }
unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
{ return get_mark_attach_class_def ().get_class (glyph); }
unsigned int get_attach_points (hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *point_count /* IN/OUT */,
unsigned int *point_array /* OUT */) const
{ return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
{ return get_lig_caret_list ().get_lig_carets (font,
direction, glyph_id, get_var_store(),
start_offset, caret_count, caret_array); }
bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return get_mark_glyph_sets ().covers (set_index, glyph_id); }
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
* glyph class and other bits, and high 8-bit the mark attachment type (if any).
* Not to be confused with lookup_props which is very similar. */
unsigned int get_glyph_props (hb_codepoint_t glyph) const
{
unsigned int klass = get_glyph_class (glyph);
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
switch (klass) {
default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
case MarkGlyph:
klass = get_mark_attachment_type (glyph);
return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
}
}
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<GDEF> (face);
if (unlikely (table->is_blocklisted (table.get_blob (), face)))
{
hb_blob_destroy (table.get_blob ());
table = hb_blob_get_empty ();
}
}
~accelerator_t () { table.destroy (); }
hb_blob_ptr_t<GDEF> table;
};
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
if (layout_variation_indices->is_empty ()) return;
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ())
{
uint16_t major = idx >> 16;
if (major >= get_var_store ().get_sub_table_count ()) break;
if (major != last_major)
{
new_minor = 0;
++new_major;
}
unsigned new_idx = (new_major << 16) + new_minor;
if (!layout_variation_idx_delta_map->has (idx))
continue;
int delta = hb_second (layout_variation_idx_delta_map->get (idx));
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
}
protected:
union {
FixedVersion<> version; /* Version identifier */
GDEFVersion1_2<SmallTypes> version1;
#ifndef HB_NO_BEYOND_64K
GDEFVersion1_2<MediumTypes> version2;
#endif
} u;
public:
DEFINE_SIZE_MIN (4);
};
struct GDEF_accelerator_t : GDEF::accelerator_t {
GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_LAYOUT_GDEF_GDEF_HH */

View File

@ -1,83 +0,0 @@
#ifndef OT_LAYOUT_GPOS_ANCHOR_HH
#define OT_LAYOUT_GPOS_ANCHOR_HH
#include "AnchorFormat1.hh"
#include "AnchorFormat2.hh"
#include "AnchorFormat3.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct Anchor
{
protected:
union {
HBUINT16 format; /* Format identifier */
AnchorFormat1 format1;
AnchorFormat2 format2;
AnchorFormat3 format3;
} u;
public:
DEFINE_SIZE_UNION (2, format);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
default:return_trace (true);
}
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
float *x, float *y) const
{
*x = *y = 0;
switch (u.format) {
case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
default: return;
}
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
switch (u.format) {
case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
case 2:
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
// AnchorFormat 2 just containins extra hinting information, so
// if hints are being dropped convert to format 1.
return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
}
return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
case 3: return_trace (u.format3.subset (c));
default:return_trace (false);
}
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
switch (u.format) {
case 1: case 2:
return;
case 3:
u.format3.collect_variation_indices (c);
return;
default: return;
}
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_ANCHOR_HH

View File

@ -1,46 +0,0 @@
#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
#define OT_LAYOUT_GPOS_ANCHORFORMAT1_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct AnchorFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
FWORD xCoordinate; /* Horizontal value--in design units */
FWORD yCoordinate; /* Vertical value--in design units */
public:
DEFINE_SIZE_STATIC (6);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
float *x, float *y) const
{
hb_font_t *font = c->font;
*x = font->em_fscale_x (xCoordinate);
*y = font->em_fscale_y (yCoordinate);
}
AnchorFormat1* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
AnchorFormat1* out = c->embed<AnchorFormat1> (this);
if (!out) return_trace (out);
out->format = 1;
return_trace (out);
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_ANCHORFORMAT1_HH

View File

@ -1,58 +0,0 @@
#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
#define OT_LAYOUT_GPOS_ANCHORFORMAT2_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct AnchorFormat2
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
FWORD xCoordinate; /* Horizontal value--in design units */
FWORD yCoordinate; /* Vertical value--in design units */
HBUINT16 anchorPoint; /* Index to glyph contour point */
public:
DEFINE_SIZE_STATIC (8);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
float *x, float *y) const
{
hb_font_t *font = c->font;
#ifdef HB_NO_HINTING
*x = font->em_fscale_x (xCoordinate);
*y = font->em_fscale_y (yCoordinate);
return;
#endif
unsigned int x_ppem = font->x_ppem;
unsigned int y_ppem = font->y_ppem;
hb_position_t cx = 0, cy = 0;
bool ret;
ret = (x_ppem || y_ppem) &&
font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
*x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
*y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
}
AnchorFormat2* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
return_trace (c->embed<AnchorFormat2> (this));
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_ANCHORFORMAT2_HH

View File

@ -1,100 +0,0 @@
#ifndef OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
#define OT_LAYOUT_GPOS_ANCHORFORMAT3_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct AnchorFormat3
{
protected:
HBUINT16 format; /* Format identifier--format = 3 */
FWORD xCoordinate; /* Horizontal value--in design units */
FWORD yCoordinate; /* Vertical value--in design units */
Offset16To<Device>
xDeviceTable; /* Offset to Device table for X
* coordinate-- from beginning of
* Anchor table (may be NULL) */
Offset16To<Device>
yDeviceTable; /* Offset to Device table for Y
* coordinate-- from beginning of
* Anchor table (may be NULL) */
public:
DEFINE_SIZE_STATIC (10);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
float *x, float *y) const
{
hb_font_t *font = c->font;
*x = font->em_fscale_x (xCoordinate);
*y = font->em_fscale_y (yCoordinate);
if (font->x_ppem || font->num_coords)
*x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
if (font->y_ppem || font->num_coords)
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (format))) return_trace (false);
if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
{
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
if (delta != 0)
{
if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
}
unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
{
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
if (delta != 0)
{
if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
}
if (c->plan->all_axes_pinned)
return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (xDeviceTable)) return_trace (false);
if (!c->serializer->embed (yDeviceTable)) return_trace (false);
out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
return_trace (out);
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
(this+xDeviceTable).collect_variation_indices (c);
(this+yDeviceTable).collect_variation_indices (c);
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_ANCHORFORMAT3_HH

View File

@ -1,77 +0,0 @@
#ifndef OT_LAYOUT_GPOS_ANCHORMATRIX_HH
#define OT_LAYOUT_GPOS_ANCHORMATRIX_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct AnchorMatrix
{
HBUINT16 rows; /* Number of rows */
UnsizedArrayOf<Offset16To<Anchor>>
matrixZ; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
DEFINE_SIZE_ARRAY (2, matrixZ);
bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
for (unsigned int i = 0; i < count; i++)
if (!matrixZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
const Anchor& get_anchor (unsigned int row, unsigned int col,
unsigned int cols, bool *found) const
{
*found = false;
if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
*found = !matrixZ[row * cols + col].is_null ();
return this+matrixZ[row * cols + col];
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
Iterator index_iter) const
{
for (unsigned i : index_iter)
(this+matrixZ[i]).collect_variation_indices (c);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool subset (hb_subset_context_t *c,
unsigned num_rows,
Iterator index_iter) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (!index_iter) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->rows = num_rows;
for (const unsigned i : index_iter)
{
auto *offset = c->serializer->embed (matrixZ[i]);
if (!offset) return_trace (false);
offset->serialize_subset (c, matrixZ[i], this);
}
return_trace (true);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_ANCHORMATRIX_HH */

View File

@ -1,14 +0,0 @@
#ifndef OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
#define OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct ChainContextPos : ChainContext {};
}
}
}
#endif /* OT_LAYOUT_GPOS_CHAINCONTEXTPOS_HH */

View File

@ -1,33 +0,0 @@
#ifndef OT_LAYOUT_GPOS_COMMON_HH
#define OT_LAYOUT_GPOS_COMMON_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
enum attach_type_t {
ATTACH_TYPE_NONE = 0X00,
/* Each attachment should be either a mark or a cursive; can't be both. */
ATTACH_TYPE_MARK = 0X01,
ATTACH_TYPE_CURSIVE = 0X02,
};
/* buffer **position** var allocations */
#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
#define attach_type() var.u8[2] /* attachment type */
/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
template<typename Iterator, typename SrcLookup>
static void SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
bool all_axes_pinned);
}
}
}
#endif // OT_LAYOUT_GPOS_COMMON_HH

View File

@ -1,14 +0,0 @@
#ifndef OT_LAYOUT_GPOS_CONTEXTPOS_HH
#define OT_LAYOUT_GPOS_CONTEXTPOS_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct ContextPos : Context {};
}
}
}
#endif /* OT_LAYOUT_GPOS_CONTEXTPOS_HH */

View File

@ -1,35 +0,0 @@
#ifndef OT_LAYOUT_GPOS_CURSIVEPOS_HH
#define OT_LAYOUT_GPOS_CURSIVEPOS_HH
#include "CursivePosFormat1.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct CursivePos
{
protected:
union {
HBUINT16 format; /* Format identifier */
CursivePosFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_CURSIVEPOS_HH */

View File

@ -1,301 +0,0 @@
#ifndef OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
#define OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH
#include "Anchor.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct EntryExitRecord
{
friend struct CursivePosFormat1;
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const void *src_base) const
{
(src_base+entryAnchor).collect_variation_indices (c);
(src_base+exitAnchor).collect_variation_indices (c);
}
EntryExitRecord* subset (hb_subset_context_t *c,
const void *src_base) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (nullptr);
out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
return_trace (out);
}
protected:
Offset16To<Anchor>
entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
Offset16To<Anchor>
exitAnchor; /* Offset to ExitAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
public:
DEFINE_SIZE_STATIC (4);
};
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent) {
int chain = pos[i].attach_chain(), type = pos[i].attach_type();
if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
return;
pos[i].attach_chain() = 0;
unsigned int j = (int) i + chain;
/* Stop if we see new parent in the chain. */
if (j == new_parent)
return;
reverse_cursive_minor_offset (pos, j, direction, new_parent);
if (HB_DIRECTION_IS_HORIZONTAL (direction))
pos[j].y_offset = -pos[i].y_offset;
else
pos[j].x_offset = -pos[i].x_offset;
pos[j].attach_chain() = -chain;
pos[j].attach_type() = type;
}
struct CursivePosFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
Array16Of<EntryExitRecord>
entryExitRecord; /* Array of EntryExit records--in
* Coverage Index order */
public:
DEFINE_SIZE_ARRAY (6, entryExitRecord);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+coverage, entryExitRecord)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
const Coverage &get_coverage () const { return this+coverage; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.entryAnchor) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
if (!prev_record.exitAnchor)
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
unsigned int i = skippy_iter.idx;
unsigned int j = buffer->idx;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"cursive attaching glyph at %u to glyph at %u",
i, j);
}
buffer->unsafe_to_break (i, j + 1);
float entry_x, entry_y, exit_x, exit_y;
(this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
(this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
hb_glyph_position_t *pos = buffer->pos;
hb_position_t d;
/* Main-direction adjustment */
switch (c->direction) {
case HB_DIRECTION_LTR:
pos[i].x_advance = roundf (exit_x) + pos[i].x_offset;
d = roundf (entry_x) + pos[j].x_offset;
pos[j].x_advance -= d;
pos[j].x_offset -= d;
break;
case HB_DIRECTION_RTL:
d = roundf (exit_x) + pos[i].x_offset;
pos[i].x_advance -= d;
pos[i].x_offset -= d;
pos[j].x_advance = roundf (entry_x) + pos[j].x_offset;
break;
case HB_DIRECTION_TTB:
pos[i].y_advance = roundf (exit_y) + pos[i].y_offset;
d = roundf (entry_y) + pos[j].y_offset;
pos[j].y_advance -= d;
pos[j].y_offset -= d;
break;
case HB_DIRECTION_BTT:
d = roundf (exit_y) + pos[i].y_offset;
pos[i].y_advance -= d;
pos[i].y_offset -= d;
pos[j].y_advance = roundf (entry_y);
break;
case HB_DIRECTION_INVALID:
default:
break;
}
/* Cross-direction adjustment */
/* We attach child to parent (think graph theory and rooted trees whereas
* the root stays on baseline and each node aligns itself against its
* parent.
*
* Optimize things for the case of RightToLeft, as that's most common in
* Arabic. */
unsigned int child = i;
unsigned int parent = j;
hb_position_t x_offset = entry_x - exit_x;
hb_position_t y_offset = entry_y - exit_y;
if (!(c->lookup_props & LookupFlag::RightToLeft))
{
unsigned int k = child;
child = parent;
parent = k;
x_offset = -x_offset;
y_offset = -y_offset;
}
/* If child was already connected to someone else, walk through its old
* chain and reverse the link direction, such that the whole tree of its
* previous connection now attaches to new parent. Watch out for case
* where new parent is on the path from old chain...
*/
reverse_cursive_minor_offset (pos, child, c->direction, parent);
pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
pos[child].attach_chain() = (int) parent - (int) child;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
pos[child].y_offset = y_offset;
else
pos[child].x_offset = x_offset;
/* If parent was attached to child, separate them.
* https://github.com/harfbuzz/harfbuzz/issues/2469
*/
if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
{
pos[parent].attach_chain() = 0;
if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
pos[parent].y_offset = 0;
else
pos[parent].x_offset = 0;
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"cursive attached glyph at %u to glyph at %u",
i, j);
}
buffer->idx++;
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_subset_context_t *c,
Iterator it,
const void *src_base)
{
if (unlikely (!c->serializer->extend_min ((*this)))) return;
this->format = 1;
this->entryExitRecord.len = it.len ();
for (const EntryExitRecord& entry_record : + it
| hb_map (hb_second))
entry_record.subset (c, src_base);
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
coverage.serialize_serialize (c->serializer, glyphs);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!out)) return_trace (false);
auto it =
+ hb_zip (this+coverage, entryExitRecord)
| hb_filter (glyphset, hb_first)
| hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
{ return hb_pair (glyph_map[p.first], p.second);})
;
bool ret = bool (it);
out->serialize (c, it, this);
return_trace (ret);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_CURSIVEPOSFORMAT1_HH */

View File

@ -1,17 +0,0 @@
#ifndef OT_LAYOUT_GPOS_EXTENSIONPOS_HH
#define OT_LAYOUT_GPOS_EXTENSIONPOS_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct ExtensionPos : Extension<ExtensionPos>
{
typedef struct PosLookupSubTable SubTable;
};
}
}
}
#endif /* OT_LAYOUT_GPOS_EXTENSIONPOS_HH */

View File

@ -1,171 +0,0 @@
#ifndef OT_LAYOUT_GPOS_GPOS_HH
#define OT_LAYOUT_GPOS_GPOS_HH
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-layout-gsubgpos.hh"
#include "Common.hh"
#include "PosLookup.hh"
namespace OT {
using Layout::GPOS_impl::PosLookup;
namespace Layout {
static void
propagate_attachment_offsets (hb_glyph_position_t *pos,
unsigned int len,
unsigned int i,
hb_direction_t direction,
unsigned nesting_level = HB_MAX_NESTING_LEVEL);
/*
* GPOS -- Glyph Positioning
* https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
*/
struct GPOS : GSUBGPOS
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
using Lookup = PosLookup;
const PosLookup& get_lookup (unsigned int i) const
{ return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
bool subset (hb_subset_context_t *c) const
{
hb_subset_layout_context_t l (c, tableTag);
return GSUBGPOS::subset<PosLookup> (&l);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (GSUBGPOS::sanitize<PosLookup> (c));
}
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
{
if (!c->gpos_lookups->has (i)) continue;
const PosLookup &l = get_lookup (i);
l.dispatch (c);
}
}
void closure_lookups (hb_face_t *face,
const hb_set_t *glyphs,
hb_set_t *lookup_indexes /* IN/OUT */) const
{ GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }
typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
};
static void
propagate_attachment_offsets (hb_glyph_position_t *pos,
unsigned int len,
unsigned int i,
hb_direction_t direction,
unsigned nesting_level)
{
/* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
* offset of glyph they are attached to. */
int chain = pos[i].attach_chain(), type = pos[i].attach_type();
if (likely (!chain))
return;
pos[i].attach_chain() = 0;
unsigned int j = (int) i + chain;
if (unlikely (j >= len))
return;
if (unlikely (!nesting_level))
return;
propagate_attachment_offsets (pos, len, j, direction, nesting_level - 1);
assert (!!(type & GPOS_impl::ATTACH_TYPE_MARK) ^ !!(type & GPOS_impl::ATTACH_TYPE_CURSIVE));
if (type & GPOS_impl::ATTACH_TYPE_CURSIVE)
{
if (HB_DIRECTION_IS_HORIZONTAL (direction))
pos[i].y_offset += pos[j].y_offset;
else
pos[i].x_offset += pos[j].x_offset;
}
else /*if (type & GPOS_impl::ATTACH_TYPE_MARK)*/
{
pos[i].x_offset += pos[j].x_offset;
pos[i].y_offset += pos[j].y_offset;
assert (j < i);
if (HB_DIRECTION_IS_FORWARD (direction))
for (unsigned int k = j; k < i; k++) {
pos[i].x_offset -= pos[k].x_advance;
pos[i].y_offset -= pos[k].y_advance;
}
else
for (unsigned int k = j + 1; k < i + 1; k++) {
pos[i].x_offset += pos[k].x_advance;
pos[i].y_offset += pos[k].y_advance;
}
}
}
void
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
for (unsigned int i = 0; i < count; i++)
buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
}
void
GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
{
//_hb_buffer_assert_gsubgpos_vars (buffer);
}
void
GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
_hb_buffer_assert_gsubgpos_vars (buffer);
unsigned int len;
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
hb_direction_t direction = buffer->props.direction;
/* Handle attachments */
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
for (unsigned i = 0; i < len; i++)
propagate_attachment_offsets (pos, len, i, direction);
if (unlikely (font->slant))
{
for (unsigned i = 0; i < len; i++)
if (unlikely (pos[i].y_offset))
pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
}
}
}
struct GPOS_accelerator_t : Layout::GPOS::accelerator_t {
GPOS_accelerator_t (hb_face_t *face) : Layout::GPOS::accelerator_t (face) {}
};
}
#endif /* OT_LAYOUT_GPOS_GPOS_HH */

View File

@ -1,56 +0,0 @@
#ifndef OT_LAYOUT_GPOS_LIGATUREARRAY_HH
#define OT_LAYOUT_GPOS_LIGATUREARRAY_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
typedef AnchorMatrix LigatureAttach; /* component-major--
* in order of writing direction--,
* mark-minor--
* ordered by class--zero-based. */
/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
struct LigatureArray : List16OfOffset16To<LigatureAttach>
{
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool subset (hb_subset_context_t *c,
Iterator coverage,
unsigned class_count,
const hb_map_t *klass_mapping) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
for (const auto _ : + hb_zip (coverage, *this)
| hb_filter (glyphset, hb_first))
{
auto *matrix = out->serialize_append (c->serializer);
if (unlikely (!matrix)) return_trace (false);
const LigatureAttach& src = (this + _.second);
auto indexes =
+ hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
;
matrix->serialize_subset (c,
_.second,
this,
src.rows,
indexes);
}
return_trace (this->len);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_LIGATUREARRAY_HH */

View File

@ -1,128 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKARRAY_HH
#define OT_LAYOUT_GPOS_MARKARRAY_HH
#include "AnchorMatrix.hh"
#include "MarkRecord.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage order */
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (Array16Of<MarkRecord>::sanitize (c, this));
}
bool apply (hb_ot_apply_context_t *c,
unsigned int mark_index, unsigned int glyph_index,
const AnchorMatrix &anchors, unsigned int class_count,
unsigned int glyph_pos) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
unsigned int mark_class = record.klass;
const Anchor& mark_anchor = this + record.markAnchor;
bool found;
const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
/* If this subtable doesn't have an anchor for this base and this class,
* return false such that the subsequent subtables have a chance at it. */
if (unlikely (!found)) return_trace (false);
float mark_x, mark_y, base_x, base_y;
buffer->unsafe_to_break (glyph_pos, buffer->idx + 1);
mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"attaching mark glyph at %u to glyph at %u",
c->buffer->idx, glyph_pos);
}
hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = roundf (base_x - mark_x);
o.y_offset = roundf (base_y - mark_y);
o.attach_type() = ATTACH_TYPE_MARK;
o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"attached mark glyph at %u to glyph at %u",
c->buffer->idx, glyph_pos);
}
buffer->idx++;
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool subset (hb_subset_context_t *c,
Iterator coverage,
const hb_map_t *klass_mapping) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
auto* out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
auto mark_iter =
+ hb_zip (coverage, this->iter ())
| hb_filter (glyphset, hb_first)
| hb_map (hb_second)
;
unsigned new_length = 0;
for (const auto& mark_record : mark_iter) {
if (unlikely (!mark_record.subset (c, this, klass_mapping)))
return_trace (false);
new_length++;
}
if (unlikely (!c->serializer->check_assign (out->len, new_length,
HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
return_trace (false);
return_trace (true);
}
};
HB_INTERNAL inline
void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
const MarkArray &mark_array,
const hb_set_t &glyphset,
hb_map_t* klass_mapping /* INOUT */)
{
hb_set_t orig_classes;
+ hb_zip (mark_coverage, mark_array)
| hb_filter (glyphset, hb_first)
| hb_map (hb_second)
| hb_map (&MarkRecord::get_class)
| hb_sink (orig_classes)
;
unsigned idx = 0;
for (auto klass : orig_classes.iter ())
{
if (klass_mapping->has (klass)) continue;
klass_mapping->set (klass, idx);
idx++;
}
}
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKARRAY_HH */

View File

@ -1,41 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKBASEPOS_HH
#define OT_LAYOUT_GPOS_MARKBASEPOS_HH
#include "MarkBasePosFormat1.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct MarkBasePos
{
protected:
union {
HBUINT16 format; /* Format identifier */
MarkBasePosFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
MarkBasePosFormat1_2<MediumTypes> format2;
#endif
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKBASEPOS_HH */

View File

@ -1,244 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
#define OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH
#include "MarkArray.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
typedef AnchorMatrix BaseArray; /* base-major--
* in order of BaseCoverage Index--,
* mark-minor--
* ordered by class--zero-based. */
template <typename Types>
struct MarkBasePosFormat1_2
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
typename Types::template OffsetTo<Coverage>
markCoverage; /* Offset to MarkCoverage table--from
* beginning of MarkBasePos subtable */
typename Types::template OffsetTo<Coverage>
baseCoverage; /* Offset to BaseCoverage table--from
* beginning of MarkBasePos subtable */
HBUINT16 classCount; /* Number of classes defined for marks */
typename Types::template OffsetTo<MarkArray>
markArray; /* Offset to MarkArray table--from
* beginning of MarkBasePos subtable */
typename Types::template OffsetTo<BaseArray>
baseArray; /* Offset to BaseArray table--from
* beginning of MarkBasePos subtable */
public:
DEFINE_SIZE_STATIC (4 + 4 * Types::size);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
markCoverage.sanitize (c, this) &&
baseCoverage.sanitize (c, this) &&
markArray.sanitize (c, this) &&
baseArray.sanitize (c, this, (unsigned int) classCount));
}
bool intersects (const hb_set_t *glyphs) const
{
return (this+markCoverage).intersects (glyphs) &&
(this+baseCoverage).intersects (glyphs);
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+markCoverage, this+markArray)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
;
hb_map_t klass_mapping;
Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
unsigned basecount = (this+baseArray).rows;
auto base_iter =
+ hb_zip (this+baseCoverage, hb_range (basecount))
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
;
hb_sorted_vector_t<unsigned> base_indexes;
for (const unsigned row : base_iter)
{
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
| hb_sink (base_indexes)
;
}
(this+baseArray).collect_variation_indices (c, base_indexes.iter ());
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
}
const Coverage &get_coverage () const { return this+markCoverage; }
static inline bool accept (hb_buffer_t *buffer, unsigned idx)
{
/* We only want to attach to the first of a MultipleSubst sequence.
* https://github.com/harfbuzz/harfbuzz/issues/740
* Reject others...
* ...but stop if we find a mark in the MultipleSubst sequence:
* https://github.com/harfbuzz/harfbuzz/issues/1020 */
return !_hb_glyph_info_multiplied (&buffer->info[idx]) ||
0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) ||
(idx == 0 ||
_hb_glyph_info_is_mark (&buffer->info[idx - 1]) ||
!_hb_glyph_info_multiplied (&buffer->info[idx - 1]) ||
_hb_glyph_info_get_lig_id (&buffer->info[idx]) !=
_hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) ||
_hb_glyph_info_get_lig_comp (&buffer->info[idx]) !=
_hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1
);
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false);
/* Now we search backwards for a non-mark glyph.
* We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (c->last_base_until > buffer->idx)
{
c->last_base_until = 0;
c->last_base = -1;
}
unsigned j;
for (j = buffer->idx; j > c->last_base_until; j--)
{
auto match = skippy_iter.match (buffer->info[j - 1]);
if (match == skippy_iter.MATCH)
{
// https://github.com/harfbuzz/harfbuzz/issues/4124
if (!accept (buffer, j - 1) &&
NOT_COVERED == (this+baseCoverage).get_coverage (buffer->info[j - 1].codepoint))
match = skippy_iter.SKIP;
}
if (match == skippy_iter.MATCH)
{
c->last_base = (signed) j - 1;
break;
}
}
c->last_base_until = buffer->idx;
if (c->last_base == -1)
{
buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
return_trace (false);
}
unsigned idx = (unsigned) c->last_base;
/* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint);
if (base_index == NOT_COVERED)
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
hb_map_t klass_mapping;
Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
if (!klass_mapping.get_population ()) return_trace (false);
out->classCount = klass_mapping.get_population ();
auto mark_iter =
+ hb_zip (this+markCoverage, this+markArray)
| hb_filter (glyphset, hb_first)
;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ mark_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
out->markArray.serialize_subset (c, markArray, this,
(this+markCoverage).iter (),
&klass_mapping);
unsigned basecount = (this+baseArray).rows;
auto base_iter =
+ hb_zip (this+baseCoverage, hb_range (basecount))
| hb_filter (glyphset, hb_first)
;
new_coverage.reset ();
+ base_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->baseCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> base_indexes;
for (const unsigned row : + base_iter
| hb_map (hb_second))
{
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
| hb_sink (base_indexes)
;
}
out->baseArray.serialize_subset (c, baseArray, this,
base_iter.len (),
base_indexes.iter ());
return_trace (true);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKBASEPOSFORMAT1_HH */

View File

@ -1,41 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKLIGPOS_HH
#define OT_LAYOUT_GPOS_MARKLIGPOS_HH
#include "MarkLigPosFormat1.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct MarkLigPos
{
protected:
union {
HBUINT16 format; /* Format identifier */
MarkLigPosFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
MarkLigPosFormat1_2<MediumTypes> format2;
#endif
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKLIGPOS_HH */

View File

@ -1,223 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
#define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH
#include "LigatureArray.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
template <typename Types>
struct MarkLigPosFormat1_2
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
typename Types::template OffsetTo<Coverage>
markCoverage; /* Offset to Mark Coverage table--from
* beginning of MarkLigPos subtable */
typename Types::template OffsetTo<Coverage>
ligatureCoverage; /* Offset to Ligature Coverage
* table--from beginning of MarkLigPos
* subtable */
HBUINT16 classCount; /* Number of defined mark classes */
typename Types::template OffsetTo<MarkArray>
markArray; /* Offset to MarkArray table--from
* beginning of MarkLigPos subtable */
typename Types::template OffsetTo<LigatureArray>
ligatureArray; /* Offset to LigatureArray table--from
* beginning of MarkLigPos subtable */
public:
DEFINE_SIZE_STATIC (4 + 4 * Types::size);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
markCoverage.sanitize (c, this) &&
ligatureCoverage.sanitize (c, this) &&
markArray.sanitize (c, this) &&
ligatureArray.sanitize (c, this, (unsigned int) classCount));
}
bool intersects (const hb_set_t *glyphs) const
{
return (this+markCoverage).intersects (glyphs) &&
(this+ligatureCoverage).intersects (glyphs);
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+markCoverage, this+markArray)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
;
hb_map_t klass_mapping;
Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);
unsigned ligcount = (this+ligatureArray).len;
auto lig_iter =
+ hb_zip (this+ligatureCoverage, hb_range (ligcount))
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
;
const LigatureArray& lig_array = this+ligatureArray;
for (const unsigned i : lig_iter)
{
hb_sorted_vector_t<unsigned> lig_indexes;
unsigned row_count = lig_array[i].rows;
for (unsigned row : + hb_range (row_count))
{
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
| hb_sink (lig_indexes)
;
}
lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
}
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
}
const Coverage &get_coverage () const { return this+markCoverage; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
if (likely (mark_index == NOT_COVERED)) return_trace (false);
/* Now we search backwards for a non-mark glyph */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (c->last_base_until > buffer->idx)
{
c->last_base_until = 0;
c->last_base = -1;
}
unsigned j;
for (j = buffer->idx; j > c->last_base_until; j--)
{
auto match = skippy_iter.match (buffer->info[j - 1]);
if (match == skippy_iter.MATCH)
{
c->last_base = (signed) j - 1;
break;
}
}
c->last_base_until = buffer->idx;
if (c->last_base == -1)
{
buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
return_trace (false);
}
unsigned idx = (unsigned) c->last_base;
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
//if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint);
if (lig_index == NOT_COVERED)
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
const LigatureArray& lig_array = this+ligatureArray;
const LigatureAttach& lig_attach = lig_array[lig_index];
/* Find component to attach to */
unsigned int comp_count = lig_attach.rows;
if (unlikely (!comp_count))
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
/* We must now check whether the ligature ID of the current mark glyph
* is identical to the ligature ID of the found ligature. If yes, we
* can directly use the component index. If not, we attach the mark
* glyph to the last component of the ligature. */
unsigned int comp_index;
unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (lig_id && lig_id == mark_id && mark_comp > 0)
comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
else
comp_index = comp_count - 1;
return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
hb_map_t klass_mapping;
Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);
if (!klass_mapping.get_population ()) return_trace (false);
out->classCount = klass_mapping.get_population ();
auto mark_iter =
+ hb_zip (this+markCoverage, this+markArray)
| hb_filter (glyphset, hb_first)
;
auto new_mark_coverage =
+ mark_iter
| hb_map_retains_sorting (hb_first)
| hb_map_retains_sorting (glyph_map)
;
if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
return_trace (false);
out->markArray.serialize_subset (c, markArray, this,
(this+markCoverage).iter (),
&klass_mapping);
auto new_ligature_coverage =
+ hb_iter (this + ligatureCoverage)
| hb_filter (glyphset)
| hb_map_retains_sorting (glyph_map)
;
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
return_trace (false);
out->ligatureArray.serialize_subset (c, ligatureArray, this,
hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
return_trace (true);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH */

View File

@ -1,42 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKMARKPOS_HH
#define OT_LAYOUT_GPOS_MARKMARKPOS_HH
#include "MarkMarkPosFormat1.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct MarkMarkPos
{
protected:
union {
HBUINT16 format; /* Format identifier */
MarkMarkPosFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
MarkMarkPosFormat1_2<MediumTypes> format2;
#endif
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKMARKPOS_HH */

View File

@ -1,228 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
#define OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH
#include "MarkMarkPosFormat1.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
typedef AnchorMatrix Mark2Array; /* mark2-major--
* in order of Mark2Coverage Index--,
* mark1-minor--
* ordered by class--zero-based. */
template <typename Types>
struct MarkMarkPosFormat1_2
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
typename Types::template OffsetTo<Coverage>
mark1Coverage; /* Offset to Combining Mark1 Coverage
* table--from beginning of MarkMarkPos
* subtable */
typename Types::template OffsetTo<Coverage>
mark2Coverage; /* Offset to Combining Mark2 Coverage
* table--from beginning of MarkMarkPos
* subtable */
HBUINT16 classCount; /* Number of defined mark classes */
typename Types::template OffsetTo<MarkArray>
mark1Array; /* Offset to Mark1Array table--from
* beginning of MarkMarkPos subtable */
typename Types::template OffsetTo<Mark2Array>
mark2Array; /* Offset to Mark2Array table--from
* beginning of MarkMarkPos subtable */
public:
DEFINE_SIZE_STATIC (4 + 4 * Types::size);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
mark1Coverage.sanitize (c, this) &&
mark2Coverage.sanitize (c, this) &&
mark1Array.sanitize (c, this) &&
mark2Array.sanitize (c, this, (unsigned int) classCount));
}
bool intersects (const hb_set_t *glyphs) const
{
return (this+mark1Coverage).intersects (glyphs) &&
(this+mark2Coverage).intersects (glyphs);
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
+ hb_zip (this+mark1Coverage, this+mark1Array)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
| hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
;
hb_map_t klass_mapping;
Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);
unsigned mark2_count = (this+mark2Array).rows;
auto mark2_iter =
+ hb_zip (this+mark2Coverage, hb_range (mark2_count))
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
;
hb_sorted_vector_t<unsigned> mark2_indexes;
for (const unsigned row : mark2_iter)
{
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
| hb_sink (mark2_indexes)
;
}
(this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
}
const Coverage &get_coverage () const { return this+mark1Coverage; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
if (likely (mark1_index == NOT_COVERED)) return_trace (false);
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
unsigned int j = skippy_iter.idx;
unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
if (likely (id1 == id2))
{
if (id1 == 0) /* Marks belonging to the same base. */
goto good;
else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
goto good;
}
else
{
/* If ligature ids don't match, it may be the case that one of the marks
* itself is a ligature. In which case match. */
if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
goto good;
}
/* Didn't match. */
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
good:
unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
if (mark2_index == NOT_COVERED)
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
hb_map_t klass_mapping;
Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);
if (!klass_mapping.get_population ()) return_trace (false);
out->classCount = klass_mapping.get_population ();
auto mark1_iter =
+ hb_zip (this+mark1Coverage, this+mark1Array)
| hb_filter (glyphset, hb_first)
;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ mark1_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
out->mark1Array.serialize_subset (c, mark1Array, this,
(this+mark1Coverage).iter (),
&klass_mapping);
unsigned mark2count = (this+mark2Array).rows;
auto mark2_iter =
+ hb_zip (this+mark2Coverage, hb_range (mark2count))
| hb_filter (glyphset, hb_first)
;
new_coverage.reset ();
+ mark2_iter
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
if (!out->mark2Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
hb_sorted_vector_t<unsigned> mark2_indexes;
for (const unsigned row : + mark2_iter
| hb_map (hb_second))
{
+ hb_range ((unsigned) classCount)
| hb_filter (klass_mapping)
| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
| hb_sink (mark2_indexes)
;
}
out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
return_trace (true);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKMARKPOSFORMAT1_HH */

View File

@ -1,52 +0,0 @@
#ifndef OT_LAYOUT_GPOS_MARKRECORD_HH
#define OT_LAYOUT_GPOS_MARKRECORD_HH
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct MarkRecord
{
friend struct MarkArray;
public:
HBUINT16 klass; /* Class defined for this mark */
Offset16To<Anchor>
markAnchor; /* Offset to Anchor table--from
* beginning of MarkArray table */
public:
DEFINE_SIZE_STATIC (4);
unsigned get_class () const { return (unsigned) klass; }
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
}
MarkRecord *subset (hb_subset_context_t *c,
const void *src_base,
const hb_map_t *klass_mapping) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (nullptr);
out->klass = klass_mapping->get (klass);
out->markAnchor.serialize_subset (c, markAnchor, src_base);
return_trace (out);
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const void *src_base) const
{
(src_base+markAnchor).collect_variation_indices (c);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_MARKRECORD_HH */

View File

@ -1,46 +0,0 @@
#ifndef OT_LAYOUT_GPOS_PAIRPOS_HH
#define OT_LAYOUT_GPOS_PAIRPOS_HH
#include "PairPosFormat1.hh"
#include "PairPosFormat2.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct PairPos
{
protected:
union {
HBUINT16 format; /* Format identifier */
PairPosFormat1_3<SmallTypes> format1;
PairPosFormat2_4<SmallTypes> format2;
#ifndef HB_NO_BEYOND_64K
PairPosFormat1_3<MediumTypes> format3;
PairPosFormat2_4<MediumTypes> format4;
#endif
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_PAIRPOS_HH

View File

@ -1,217 +0,0 @@
#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
#define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH
#include "PairSet.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
template <typename Types>
struct PairPosFormat1_3
{
using PairSet = GPOS_impl::PairSet<Types>;
using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
protected:
HBUINT16 format; /* Format identifier--format = 1 */
typename Types::template OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat[2]; /* [0] Defines the types of data in
* ValueRecord1--for the first glyph
* in the pair--may be zero (0) */
/* [1] Defines the types of data in
* ValueRecord2--for the second glyph
* in the pair--may be zero (0) */
Array16Of<typename Types::template OffsetTo<PairSet>>
pairSet; /* Array of PairSet tables
* ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (8 + Types::size, pairSet);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
unsigned int len1 = valueFormat[0].get_len ();
unsigned int len2 = valueFormat[1].get_len ();
typename PairSet::sanitize_closure_t closure =
{
valueFormat,
len1,
PairSet::get_size (len1, len2)
};
return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
}
bool intersects (const hb_set_t *glyphs) const
{
auto &cov = this+coverage;
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
{
for (hb_codepoint_t g : glyphs->iter())
{
unsigned i = cov.get_coverage (g);
if ((this+pairSet[i]).intersects (glyphs, valueFormat))
return true;
}
return false;
}
return
+ hb_zip (cov, pairSet)
| hb_filter (*glyphs, hb_first)
| hb_map (hb_second)
| hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
{ return (this+_).intersects (glyphs, valueFormat); })
| hb_any
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;
auto it =
+ hb_zip (this+coverage, pairSet)
| hb_filter (c->glyph_set, hb_first)
| hb_map (hb_second)
;
if (!it) return;
+ it
| hb_map (hb_add (this))
| hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
;
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
unsigned int count = pairSet.len;
for (unsigned int i = 0; i < count; i++)
(this+pairSet[i]).collect_glyphs (c, valueFormat);
}
const Coverage &get_coverage () const { return this+coverage; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
unsigned unsafe_to;
if (!skippy_iter.next (&unsafe_to))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
}
return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
out->valueFormat[0] = valueFormat[0];
out->valueFormat[1] = valueFormat[1];
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
out->valueFormat[0] = newFormats.first;
out->valueFormat[1] = newFormats.second;
}
if (c->plan->all_axes_pinned)
{
out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
}
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+ hb_zip (this+coverage, pairSet)
| hb_filter (glyphset, hb_first)
| hb_filter ([this, c, out] (const typename Types::template OffsetTo<PairSet>& _)
{
auto snap = c->serializer->snapshot ();
auto *o = out->pairSet.serialize_append (c->serializer);
if (unlikely (!o)) return false;
bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
if (!ret)
{
out->pairSet.pop ();
c->serializer->revert (snap);
}
return ret;
},
hb_second)
| hb_map (hb_first)
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
{
unsigned record_size = PairSet::get_size (valueFormat);
unsigned format1 = 0;
unsigned format2 = 0;
for (const auto & _ :
+ hb_zip (this+coverage, pairSet)
| hb_filter (glyphset, hb_first)
| hb_map (hb_second)
)
{
const PairSet& set = (this + _);
const PairValueRecord *record = &set.firstPairValueRecord;
unsigned count = set.len;
for (unsigned i = 0; i < count; i++)
{
if (record->intersects (glyphset))
{
format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
}
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
if (format1 == valueFormat[0] && format2 == valueFormat[1])
break;
}
return hb_pair (format1, format2);
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH

View File

@ -1,351 +0,0 @@
#ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
#define OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH
#include "ValueFormat.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
template <typename Types>
struct PairPosFormat2_4
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
typename Types::template OffsetTo<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat1; /* ValueRecord definition--for the
* first glyph of the pair--may be zero
* (0) */
ValueFormat valueFormat2; /* ValueRecord definition--for the
* second glyph of the pair--may be
* zero (0) */
typename Types::template OffsetTo<ClassDef>
classDef1; /* Offset to ClassDef table--from
* beginning of PairPos subtable--for
* the first glyph of the pair */
typename Types::template OffsetTo<ClassDef>
classDef2; /* Offset to ClassDef table--from
* beginning of PairPos subtable--for
* the second glyph of the pair */
HBUINT16 class1Count; /* Number of classes in ClassDef1
* table--includes Class0 */
HBUINT16 class2Count; /* Number of classes in ClassDef2
* table--includes Class0 */
ValueRecord values; /* Matrix of value pairs:
* class1-major, class2-minor,
* Each entry has value1 and value2 */
public:
DEFINE_SIZE_ARRAY (10 + 3 * Types::size, values);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!(c->check_struct (this)
&& coverage.sanitize (c, this)
&& classDef1.sanitize (c, this)
&& classDef2.sanitize (c, this))) return_trace (false);
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int stride = HBUINT16::static_size * (len1 + len2);
unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_range ((const void *) values,
count,
record_size) &&
valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
}
bool intersects (const hb_set_t *glyphs) const
{
return (this+coverage).intersects (glyphs) &&
(this+classDef2).intersects (glyphs);
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
if (!intersects (c->glyph_set)) return;
if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;
hb_set_t klass1_glyphs, klass2_glyphs;
if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;
hb_set_t class1_set, class2_set;
for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
{
if (!klass1_glyphs.has (cp)) class1_set.add (0);
else
{
unsigned klass1 = (this+classDef1).get (cp);
class1_set.add (klass1);
}
}
class2_set.add (0);
for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
{
unsigned klass2 = (this+classDef2).get (cp);
class2_set.add (klass2);
}
if (class1_set.is_empty ()
|| class2_set.is_empty ()
|| (class2_set.get_population() == 1 && class2_set.has(0)))
return;
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
for (const unsigned class1_idx : class1_set.iter ())
{
for (const unsigned class2_idx : class2_set.iter ())
{
unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
if (valueFormat1.has_device ())
valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));
if (valueFormat2.has_device ())
valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
}
}
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
}
const Coverage &get_coverage () const { return this+coverage; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset (buffer->idx, 1);
unsigned unsafe_to;
if (!skippy_iter.next (&unsafe_to))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
}
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int record_len = len1 + len2;
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
return_trace (false);
}
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
bool applied_first = false, applied_second = false;
/* Isolate simple kerning and apply it half to each side.
* Results in better cursor positinoing / underline drawing.
*
* Disabled, because causes issues... :-(
* https://github.com/harfbuzz/harfbuzz/issues/3408
* https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
*/
#ifndef HB_SPLIT_KERN
if (0)
#endif
{
if (!len2)
{
const hb_direction_t dir = buffer->props.direction;
const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir);
const bool backward = HB_DIRECTION_IS_BACKWARD (dir);
unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance;
if (backward)
mask |= mask >> 2; /* Add eg. xPlacement in RTL. */
/* Add Devices. */
mask |= mask << 4;
if (valueFormat1 & ~mask)
goto bail;
/* Is simple kern. Apply value on an empty position slot,
* then split it between sides. */
hb_glyph_position_t pos{};
if (valueFormat1.apply_value (c, this, v, pos))
{
hb_position_t *src = &pos.x_advance;
hb_position_t *dst1 = &buffer->cur_pos().x_advance;
hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance;
unsigned i = horizontal ? 0 : 1;
hb_position_t kern = src[i];
hb_position_t kern1 = kern >> 1;
hb_position_t kern2 = kern - kern1;
if (!backward)
{
dst1[i] += kern1;
dst2[i] += kern2;
dst2[i + 2] += kern2;
}
else
{
dst1[i] += kern1;
dst1[i + 2] += src[i + 2] - kern2;
dst2[i] += kern2;
}
applied_first = applied_second = kern != 0;
goto success;
}
goto boring;
}
}
bail:
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"try kerning glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx);
}
applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerned glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx);
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"tried kerning glyphs at %u,%u",
c->buffer->idx, skippy_iter.idx);
}
success:
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
else
boring:
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
if (len2)
{
skippy_iter.idx++;
// https://github.com/harfbuzz/harfbuzz/issues/3824
// https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
}
buffer->idx = skippy_iter.idx;
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
hb_map_t klass1_map;
out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
out->class1Count = klass1_map.get_population ();
hb_map_t klass2_map;
out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
out->class2Count = klass2_map.get_population ();
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
newFormats = compute_effective_value_formats (klass1_map, klass2_map);
out->valueFormat1 = newFormats.first;
out->valueFormat2 = newFormats.second;
if (c->plan->all_axes_pinned)
{
out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
}
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
{
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
}
}
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto it =
+ hb_iter (this+coverage)
| hb_filter (glyphset)
| hb_map_retains_sorting (glyph_map)
;
out->coverage.serialize_serialize (c->serializer, it);
return_trace (out->class1Count && out->class2Count && bool (it));
}
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
const hb_map_t& klass2_map) const
{
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
unsigned record_size = len1 + len2;
unsigned format1 = 0;
unsigned format2 = 0;
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
{
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
}
if (format1 == valueFormat1 && format2 == valueFormat2)
break;
}
return hb_pair (format1, format2);
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_PAIRPOSFORMAT2_HH

View File

@ -1,207 +0,0 @@
#ifndef OT_LAYOUT_GPOS_PAIRSET_HH
#define OT_LAYOUT_GPOS_PAIRSET_HH
#include "PairValueRecord.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
template <typename Types>
struct PairSet
{
template <typename Types2>
friend struct PairPosFormat1_3;
using PairValueRecord = GPOS_impl::PairValueRecord<Types>;
protected:
HBUINT16 len; /* Number of PairValueRecords */
PairValueRecord firstPairValueRecord;
/* Array of PairValueRecords--ordered
* by GlyphID of the second glyph */
public:
DEFINE_SIZE_MIN (2);
static unsigned get_size (unsigned len1, unsigned len2)
{
return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
}
static unsigned get_size (const ValueFormat valueFormats[2])
{
unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len ();
return get_size (len1, len2);
}
struct sanitize_closure_t
{
const ValueFormat *valueFormats;
unsigned int len1; /* valueFormats[0].get_len() */
unsigned int stride; /* bytes */
};
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
{
TRACE_SANITIZE (this);
if (!(c->check_struct (this)
&& c->check_range (&firstPairValueRecord,
len,
closure->stride))) return_trace (false);
unsigned int count = len;
const PairValueRecord *record = &firstPairValueRecord;
return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
}
bool intersects (const hb_set_t *glyphs,
const ValueFormat *valueFormats) const
{
unsigned record_size = get_size (valueFormats);
const PairValueRecord *record = &firstPairValueRecord;
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
{
if (glyphs->has (record->secondGlyph))
return true;
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
return false;
}
void collect_glyphs (hb_collect_glyphs_context_t *c,
const ValueFormat *valueFormats) const
{
unsigned record_size = get_size (valueFormats);
const PairValueRecord *record = &firstPairValueRecord;
c->input->add_array (&record->secondGlyph, len, record_size);
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats) const
{
unsigned record_size = get_size (valueFormats);
const PairValueRecord *record = &firstPairValueRecord;
unsigned count = len;
for (unsigned i = 0; i < count; i++)
{
if (c->glyph_set->has (record->secondGlyph))
{ record->collect_variation_indices (c, valueFormats, this); }
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
}
bool apply (hb_ot_apply_context_t *c,
const ValueFormat *valueFormats,
unsigned int pos) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len ();
unsigned record_size = get_size (len1, len2);
const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
&firstPairValueRecord,
len,
record_size);
if (record)
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"try kerning glyphs at %u,%u",
c->buffer->idx, pos);
}
bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"kerned glyphs at %u,%u",
c->buffer->idx, pos);
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"tried kerning glyphs at %u,%u",
c->buffer->idx, pos);
}
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, pos + 1);
if (len2)
{
pos++;
// https://github.com/harfbuzz/harfbuzz/issues/3824
// https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116
buffer->unsafe_to_break (buffer->idx, pos + 1);
}
buffer->idx = pos;
return_trace (true);
}
buffer->unsafe_to_concat (buffer->idx, pos + 1);
return_trace (false);
}
bool subset (hb_subset_context_t *c,
const ValueFormat valueFormats[2],
const ValueFormat newFormats[2]) const
{
TRACE_SUBSET (this);
auto snap = c->serializer->snapshot ();
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->len = 0;
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = get_size (len1, len2);
typename PairValueRecord::context_t context =
{
this,
valueFormats,
newFormats,
len1,
&glyph_map,
&c->plan->layout_variation_idx_delta_map
};
const PairValueRecord *record = &firstPairValueRecord;
unsigned count = len, num = 0;
for (unsigned i = 0; i < count; i++)
{
if (glyphset.has (record->secondGlyph)
&& record->subset (c, &context)) num++;
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
out->len = num;
if (!num) c->serializer->revert (snap);
return_trace (num);
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_PAIRSET_HH

View File

@ -1,99 +0,0 @@
#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#include "ValueFormat.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
template <typename Types>
struct PairValueRecord
{
template <typename Types2>
friend struct PairSet;
protected:
typename Types::HBGlyphID
secondGlyph; /* GlyphID of second glyph in the
* pair--first glyph is listed in the
* Coverage table */
ValueRecord values; /* Positioning data for the first glyph
* followed by for second glyph */
public:
DEFINE_SIZE_ARRAY (Types::size, values);
int cmp (hb_codepoint_t k) const
{ return secondGlyph.cmp (k); }
struct context_t
{
const void *base;
const ValueFormat *valueFormats;
const ValueFormat *newFormats;
unsigned len1; /* valueFormats[0].get_len() */
const hb_map_t *glyph_map;
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map;
};
bool subset (hb_subset_context_t *c,
context_t *closure) const
{
TRACE_SERIALIZE (this);
auto *s = c->serializer;
auto *out = s->start_embed (*this);
if (unlikely (!s->extend_min (out))) return_trace (false);
out->secondGlyph = (*closure->glyph_map)[secondGlyph];
closure->valueFormats[0].copy_values (s,
closure->newFormats[0],
closure->base, &values[0],
closure->layout_variation_idx_delta_map);
closure->valueFormats[1].copy_values (s,
closure->newFormats[1],
closure->base,
&values[closure->len1],
closure->layout_variation_idx_delta_map);
return_trace (true);
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats,
const void *base) const
{
unsigned record1_len = valueFormats[0].get_len ();
unsigned record2_len = valueFormats[1].get_len ();
const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);
if (valueFormats[0].has_device ())
valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));
if (valueFormats[1].has_device ())
valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
}
bool intersects (const hb_set_t& glyphset) const
{
return glyphset.has(secondGlyph);
}
const Value* get_values_1 () const
{
return &values[0];
}
const Value* get_values_2 (ValueFormat format1) const
{
return &values[format1.get_len ()];
}
};
}
}
}
#endif // OT_LAYOUT_GPOS_PAIRVALUERECORD_HH

View File

@ -1,79 +0,0 @@
#ifndef OT_LAYOUT_GPOS_POSLOOKUP_HH
#define OT_LAYOUT_GPOS_POSLOOKUP_HH
#include "PosLookupSubTable.hh"
#include "../../../hb-ot-layout-common.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct PosLookup : Lookup
{
using SubTable = PosLookupSubTable;
const SubTable& get_subtable (unsigned int i) const
{ return Lookup::get_subtable<SubTable> (i); }
bool is_reverse () const
{
return false;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
return_trace (dispatch (c));
}
bool intersects (const hb_set_t *glyphs) const
{
hb_intersects_context_t c (glyphs);
return dispatch (&c);
}
hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{ return dispatch (c); }
hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
{
if (c->is_lookup_visited (this_index))
return hb_closure_lookups_context_t::default_return_value ();
c->set_lookup_visited (this_index);
if (!intersects (c->glyphs))
{
c->set_lookup_inactive (this_index);
return hb_closure_lookups_context_t::default_return_value ();
}
hb_closure_lookups_context_t::return_t ret = dispatch (c);
return ret;
}
template <typename set_t>
void collect_coverage (set_t *glyphs) const
{
hb_collect_coverage_context_t<set_t> c (glyphs);
dispatch (&c);
}
template <typename context_t>
static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{ return Lookup::dispatch<SubTable> (c, std::forward<Ts> (ds)...); }
bool subset (hb_subset_context_t *c) const
{ return Lookup::subset<SubTable> (c); }
bool sanitize (hb_sanitize_context_t *c) const
{ return Lookup::sanitize<SubTable> (c); }
};
}
}
}
#endif /* OT_LAYOUT_GPOS_POSLOOKUP_HH */

View File

@ -1,79 +0,0 @@
#ifndef OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
#define OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH
#include "SinglePos.hh"
#include "PairPos.hh"
#include "CursivePos.hh"
#include "MarkBasePos.hh"
#include "MarkLigPos.hh"
#include "MarkMarkPos.hh"
#include "ContextPos.hh"
#include "ChainContextPos.hh"
#include "ExtensionPos.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct PosLookupSubTable
{
friend struct ::OT::Lookup;
friend struct PosLookup;
enum Type {
Single = 1,
Pair = 2,
Cursive = 3,
MarkBase = 4,
MarkLig = 5,
MarkMark = 6,
Context = 7,
ChainContext = 8,
Extension = 9
};
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
{
TRACE_DISPATCH (this, lookup_type);
switch (lookup_type) {
case Single: return_trace (u.single.dispatch (c, std::forward<Ts> (ds)...));
case Pair: return_trace (u.pair.dispatch (c, std::forward<Ts> (ds)...));
case Cursive: return_trace (u.cursive.dispatch (c, std::forward<Ts> (ds)...));
case MarkBase: return_trace (u.markBase.dispatch (c, std::forward<Ts> (ds)...));
case MarkLig: return_trace (u.markLig.dispatch (c, std::forward<Ts> (ds)...));
case MarkMark: return_trace (u.markMark.dispatch (c, std::forward<Ts> (ds)...));
case Context: return_trace (u.context.dispatch (c, std::forward<Ts> (ds)...));
case ChainContext: return_trace (u.chainContext.dispatch (c, std::forward<Ts> (ds)...));
case Extension: return_trace (u.extension.dispatch (c, std::forward<Ts> (ds)...));
default: return_trace (c->default_return_value ());
}
}
bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
{
hb_intersects_context_t c (glyphs);
return dispatch (&c, lookup_type);
}
protected:
union {
SinglePos single;
PairPos pair;
CursivePos cursive;
MarkBasePos markBase;
MarkLigPos markLig;
MarkMarkPos markMark;
ContextPos context;
ChainContextPos chainContext;
ExtensionPos extension;
} u;
public:
DEFINE_SIZE_MIN (0);
};
}
}
}
#endif /* HB_OT_LAYOUT_GPOS_POSLOOKUPSUBTABLE_HH */

View File

@ -1,100 +0,0 @@
#ifndef OT_LAYOUT_GPOS_SINGLEPOS_HH
#define OT_LAYOUT_GPOS_SINGLEPOS_HH
#include "SinglePosFormat1.hh"
#include "SinglePosFormat2.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct SinglePos
{
protected:
union {
HBUINT16 format; /* Format identifier */
SinglePosFormat1 format1;
SinglePosFormat2 format2;
} u;
public:
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
unsigned get_format (Iterator glyph_val_iter_pairs)
{
hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);
for (const auto iter : glyph_val_iter_pairs)
for (const auto _ : hb_zip (iter.second, first_val_iter))
if (_.first != _.second)
return 2;
return 1;
}
template<typename Iterator,
typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
const SrcLookup* src,
Iterator glyph_val_iter_pairs,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
bool all_axes_pinned)
{
if (unlikely (!c->extend_min (u.format))) return;
unsigned format = 2;
ValueFormat new_format = src->get_value_format ();
if (all_axes_pinned)
new_format = new_format.drop_device_table_flags ();
if (glyph_val_iter_pairs)
format = get_format (glyph_val_iter_pairs);
u.format = format;
switch (u.format) {
case 1: u.format1.serialize (c,
src,
glyph_val_iter_pairs,
new_format,
layout_variation_idx_delta_map);
return;
case 2: u.format2.serialize (c,
src,
glyph_val_iter_pairs,
new_format,
layout_variation_idx_delta_map);
return;
default:return;
}
}
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
};
template<typename Iterator, typename SrcLookup>
static void
SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
bool all_axes_pinned)
{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
}
}
}
#endif /* OT_LAYOUT_GPOS_SINGLEPOS_HH */

View File

@ -1,164 +0,0 @@
#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH
#include "Common.hh"
#include "ValueFormat.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct SinglePosFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat; /* Defines the types of data in the
* ValueRecord */
ValueRecord values; /* Defines positioning
* value(s)--applied to all glyphs in
* the Coverage table */
public:
DEFINE_SIZE_ARRAY (6, values);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
/* The coverage table may use a range to represent a set
* of glyphs, which means a small number of bytes can
* generate a large glyph set. Manually modify the
* sanitizer max ops to take this into account.
*
* Note: This check *must* be right after coverage sanitize. */
c->check_ops ((this + coverage).get_population () >> 1) &&
valueFormat.sanitize_value (c, this, values));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
if (!valueFormat.has_device ()) return;
hb_set_t intersection;
(this+coverage).intersect_set (*c->glyph_set, intersection);
if (!intersection) return;
valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
const Coverage &get_coverage () const { return this+coverage; }
ValueFormat get_value_format () const { return valueFormat; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioning glyph at %u",
c->buffer->idx);
}
valueFormat.apply_value (c, this, values, buffer->cur_pos());
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioned glyph at %u",
c->buffer->idx);
}
buffer->idx++;
return_trace (true);
}
bool
position_single (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
{
unsigned int index = (this+coverage).get_coverage (gid);
if (likely (index == NOT_COVERED)) return false;
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
OT::hb_ot_apply_context_t c (1, font, &buffer);
valueFormat.apply_value (&c, this, values, pos);
return true;
}
template<typename Iterator,
typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
ValueFormat newFormat,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
{
if (unlikely (!c->extend_min (this))) return;
if (unlikely (!c->check_assign (valueFormat,
newFormat,
HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
{
src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map);
// Only serialize the first entry in the iterator, the rest are assumed to
// be the same.
break;
}
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
coverage.serialize_serialize (c, glyphs);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_set_t intersection;
(this+coverage).intersect_set (glyphset, intersection);
auto it =
+ hb_iter (intersection)
| hb_map_retains_sorting (glyph_map)
| hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
;
bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
return_trace (ret);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT1_HH */

View File

@ -1,176 +0,0 @@
#ifndef OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
#define OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH
#include "Common.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
struct SinglePosFormat2
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of subtable */
ValueFormat valueFormat; /* Defines the types of data in the
* ValueRecord */
HBUINT16 valueCount; /* Number of ValueRecords */
ValueRecord values; /* Array of ValueRecords--positioning
* values applied to glyphs */
public:
DEFINE_SIZE_ARRAY (8, values);
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
valueFormat.sanitize_values (c, this, values, valueCount));
}
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
void closure_lookups (hb_closure_lookups_context_t *c) const {}
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
if (!valueFormat.has_device ()) return;
auto it =
+ hb_zip (this+coverage, hb_range ((unsigned) valueCount))
| hb_filter (c->glyph_set, hb_first)
;
if (!it) return;
unsigned sub_length = valueFormat.get_len ();
const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);
for (unsigned i : + it
| hb_map (hb_second))
valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));
}
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{ if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
const Coverage &get_coverage () const { return this+coverage; }
ValueFormat get_value_format () const { return valueFormat; }
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= valueCount)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioning glyph at %u",
c->buffer->idx);
}
valueFormat.apply_value (c, this,
&values[index * valueFormat.get_len ()],
buffer->cur_pos());
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"positioned glyph at %u",
c->buffer->idx);
}
buffer->idx++;
return_trace (true);
}
bool
position_single (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
{
unsigned int index = (this+coverage).get_coverage (gid);
if (likely (index == NOT_COVERED)) return false;
if (unlikely (index >= valueCount)) return false;
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
OT::hb_ot_apply_context_t c (1, font, &buffer);
valueFormat.apply_value (&c, this,
&values[index * valueFormat.get_len ()],
pos);
return true;
}
template<typename Iterator,
typename SrcLookup,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
ValueFormat newFormat,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
{
auto out = c->extend_min (this);
if (unlikely (!out)) return;
if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
+ it
| hb_map (hb_second)
| hb_apply ([&] (hb_array_t<const Value> _)
{ src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); })
;
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
coverage.serialize_serialize (c, glyphs);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
unsigned sub_length = valueFormat.get_len ();
auto values_array = values.as_array (valueCount * sub_length);
auto it =
+ hb_zip (this+coverage, hb_range ((unsigned) valueCount))
| hb_filter (glyphset, hb_first)
| hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
{
return hb_pair (glyph_map[_.first],
values_array.sub_array (_.second * sub_length,
sub_length));
})
;
bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
return_trace (ret);
}
};
}
}
}
#endif /* OT_LAYOUT_GPOS_SINGLEPOSFORMAT2_HH */

View File

@ -1,394 +0,0 @@
#ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH
#define OT_LAYOUT_GPOS_VALUEFORMAT_HH
#include "../../../hb-ot-layout-gsubgpos.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
typedef HBUINT16 Value;
typedef UnsizedArrayOf<Value> ValueRecord;
struct ValueFormat : HBUINT16
{
enum Flags {
xPlacement = 0x0001u, /* Includes horizontal adjustment for placement */
yPlacement = 0x0002u, /* Includes vertical adjustment for placement */
xAdvance = 0x0004u, /* Includes horizontal adjustment for advance */
yAdvance = 0x0008u, /* Includes vertical adjustment for advance */
xPlaDevice = 0x0010u, /* Includes horizontal Device table for placement */
yPlaDevice = 0x0020u, /* Includes vertical Device table for placement */
xAdvDevice = 0x0040u, /* Includes horizontal Device table for advance */
yAdvDevice = 0x0080u, /* Includes vertical Device table for advance */
ignored = 0x0F00u, /* Was used in TrueType Open for MM fonts */
reserved = 0xF000u, /* For future use */
devices = 0x00F0u /* Mask for having any Device table */
};
/* All fields are options. Only those available advance the value pointer. */
#if 0
HBINT16 xPlacement; /* Horizontal adjustment for
* placement--in design units */
HBINT16 yPlacement; /* Vertical adjustment for
* placement--in design units */
HBINT16 xAdvance; /* Horizontal adjustment for
* advance--in design units (only used
* for horizontal writing) */
HBINT16 yAdvance; /* Vertical adjustment for advance--in
* design units (only used for vertical
* writing) */
Offset16To<Device> xPlaDevice; /* Offset to Device table for
* horizontal placement--measured from
* beginning of PosTable (may be NULL) */
Offset16To<Device> yPlaDevice; /* Offset to Device table for vertical
* placement--measured from beginning
* of PosTable (may be NULL) */
Offset16To<Device> xAdvDevice; /* Offset to Device table for
* horizontal advance--measured from
* beginning of PosTable (may be NULL) */
Offset16To<Device> yAdvDevice; /* Offset to Device table for vertical
* advance--measured from beginning of
* PosTable (may be NULL) */
#endif
IntType& operator = (uint16_t i) { v = i; return *this; }
unsigned int get_len () const { return hb_popcount ((unsigned int) *this); }
unsigned int get_size () const { return get_len () * Value::static_size; }
hb_vector_t<unsigned> get_device_table_indices () const {
unsigned i = 0;
hb_vector_t<unsigned> result;
unsigned format = *this;
if (format & xPlacement) i++;
if (format & yPlacement) i++;
if (format & xAdvance) i++;
if (format & yAdvance) i++;
if (format & xPlaDevice) result.push (i++);
if (format & yPlaDevice) result.push (i++);
if (format & xAdvDevice) result.push (i++);
if (format & yAdvDevice) result.push (i++);
return result;
}
bool apply_value (hb_ot_apply_context_t *c,
const void *base,
const Value *values,
hb_glyph_position_t &glyph_pos) const
{
bool ret = false;
unsigned int format = *this;
if (!format) return ret;
hb_font_t *font = c->font;
bool horizontal =
#ifndef HB_NO_VERTICAL
HB_DIRECTION_IS_HORIZONTAL (c->direction)
#else
true
#endif
;
if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret));
if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret));
if (format & xAdvance) {
if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
values++;
}
/* y_advance values grow downward but font-space grows upward, hence negation */
if (format & yAdvance) {
if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
values++;
}
if (!has_device ()) return ret;
bool use_x_device = font->x_ppem || font->num_coords;
bool use_y_device = font->y_ppem || font->num_coords;
if (!use_x_device && !use_y_device) return ret;
const VariationStore &store = c->var_store;
auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
values++;
}
if (format & yPlaDevice) {
if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
values++;
}
if (format & xAdvDevice) {
if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
values++;
}
if (format & yAdvDevice) {
/* y_advance values grow downward but font-space grows upward, hence negation */
if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
values++;
}
return ret;
}
unsigned int get_effective_format (const Value *values) const
{
unsigned int format = *this;
for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
if (format & flag) should_drop (*values++, (Flags) flag, &format);
}
return format;
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
unsigned int get_effective_format (Iterator it) const {
unsigned int new_format = 0;
for (const hb_array_t<const Value>& values : it)
new_format = new_format | get_effective_format (&values);
return new_format;
}
void copy_values (hb_serialize_context_t *c,
unsigned int new_format,
const void *base,
const Value *values,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
unsigned int format = *this;
if (!format) return;
HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr;
if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++);
if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++);
if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++);
if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++);
if (format & xPlaDevice)
{
add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice);
}
if (format & yPlaDevice)
{
add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map);
copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice);
}
if (format & xAdvDevice)
{
add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map);
copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice);
}
if (format & yAdvDevice)
{
add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map);
copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice);
}
}
HBINT16* copy_value (hb_serialize_context_t *c,
unsigned int new_format,
Flags flag,
Value value) const
{
// Filter by new format.
if (!(new_format & flag)) return nullptr;
return reinterpret_cast<HBINT16 *> (c->copy (value));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const void *base,
const hb_array_t<const Value>& values) const
{
unsigned format = *this;
unsigned i = 0;
if (format & xPlacement) i++;
if (format & yPlacement) i++;
if (format & xAdvance) i++;
if (format & yAdvance) i++;
if (format & xPlaDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yPlaDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::xAdvDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yAdvDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
}
unsigned drop_device_table_flags () const
{
unsigned format = *this;
for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
format = format & ~flag;
return format;
}
private:
bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
{
unsigned int format = *this;
if (format & xPlacement) values++;
if (format & yPlacement) values++;
if (format & xAdvance) values++;
if (format & yAdvance) values++;
if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
return true;
}
static inline Offset16To<Device>& get_device (Value* value)
{
return *static_cast<Offset16To<Device> *> (value);
}
static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
{
if (worked) *worked |= bool (*value);
return *static_cast<const Offset16To<Device> *> (value);
}
void add_delta_to_value (HBINT16 *value,
const void *base,
const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
if (!value) return;
unsigned varidx = (base + get_device (src_value)).get_variation_index ();
hb_pair_t<unsigned, int> *varidx_delta;
if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return;
*value += hb_second (*varidx_delta);
}
bool copy_device (hb_serialize_context_t *c, const void *base,
const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
unsigned int new_format, Flags flag) const
{
// Filter by new format.
if (!(new_format & flag)) return true;
Value *dst_value = c->copy (*src_value);
if (!dst_value) return false;
if (*dst_value == 0) return true;
*dst_value = 0;
c->push ();
if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
{
c->add_link (*dst_value, c->pop_pack ());
return true;
}
else
{
c->pop_discard ();
return false;
}
}
static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
{
if (worked) *worked |= bool (*value);
return *reinterpret_cast<const HBINT16 *> (value);
}
public:
bool has_device () const
{
unsigned int format = *this;
return (format & devices) != 0;
}
bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
{
TRACE_SANITIZE (this);
return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
}
bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
{
TRACE_SANITIZE (this);
unsigned int len = get_len ();
if (!c->check_range (values, count, get_size ())) return_trace (false);
if (!has_device ()) return_trace (true);
for (unsigned int i = 0; i < count; i++) {
if (!sanitize_value_devices (c, base, values))
return_trace (false);
values += len;
}
return_trace (true);
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
{
TRACE_SANITIZE (this);
if (!has_device ()) return_trace (true);
for (unsigned int i = 0; i < count; i++) {
if (!sanitize_value_devices (c, base, values))
return_trace (false);
values = &StructAtOffset<const Value> (values, stride);
}
return_trace (true);
}
private:
void should_drop (Value value, Flags flag, unsigned int* format) const
{
if (value) return;
*format = *format & ~flag;
}
};
}
}
}
#endif // #ifndef OT_LAYOUT_GPOS_VALUEFORMAT_HH

View File

@ -5,13 +5,12 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
template <typename Types>
struct AlternateSet
{
protected:
Array16Of<typename Types::HBGlyphID>
Array16Of<HBGlyphID16>
alternates; /* Array of alternate GlyphIDs--in
* arbitrary order */
public:
@ -57,23 +56,8 @@ struct AlternateSet
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %u (alternate substitution)",
c->buffer->idx);
}
c->replace_glyph (alternates[alt_index - 1]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %u (alternate substitution)",
c->buffer->idx - 1u);
}
return_trace (true);
}
@ -84,7 +68,7 @@ struct AlternateSet
{
if (alternates.len && alternate_count)
{
+ alternates.as_array ().sub_array (start_offset, alternate_count)
+ alternates.sub_array (start_offset, alternate_count)
| hb_sink (hb_array (alternate_glyphs, *alternate_count))
;
}

View File

@ -6,36 +6,28 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
struct AlternateSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
AlternateSubstFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
AlternateSubstFormat1_2<MediumTypes> format2;
#endif
HBUINT16 format; /* Format identifier */
AlternateSubstFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
/* TODO This function is unused and not updated to 24bit GIDs. Should be done by using
* iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> alternate_len_list,
@ -50,9 +42,6 @@ struct AlternateSubst
default:return_trace (false);
}
}
/* TODO subset() should choose format. */
};
}

View File

@ -6,21 +6,20 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
template <typename Types>
struct AlternateSubstFormat1_2
struct AlternateSubstFormat1
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
typename Types::template OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
Array16Of<typename Types::template OffsetTo<AlternateSet<Types>>>
Array16OfOffset16To<AlternateSet>
alternateSet; /* Array of AlternateSet tables
* ordered by Coverage Index */
public:
DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet);
DEFINE_SIZE_ARRAY (6, alternateSet);
bool sanitize (hb_sanitize_context_t *c) const
{
@ -28,6 +27,8 @@ struct AlternateSubstFormat1_2
return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
}
inline bool is_inplace () const { return true; }
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
@ -40,8 +41,9 @@ struct AlternateSubstFormat1_2
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet<Types> &_) { _.closure (c); })
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -52,7 +54,7 @@ struct AlternateSubstFormat1_2
+ hb_zip (this+coverage, alternateSet)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet<Types> &_) { _.collect_glyphs (c); })
| hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
;
}

View File

@ -7,7 +7,7 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
struct ChainContextSubst : ChainContext {};

View File

@ -6,7 +6,7 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;

View File

@ -7,7 +7,7 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
struct ContextSubst : Context {};

View File

@ -7,7 +7,7 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
struct ExtensionSubst : Extension<ExtensionSubst>
{

View File

@ -1,15 +1,16 @@
#ifndef OT_LAYOUT_GSUB_GSUB_HH
#define OT_LAYOUT_GSUB_GSUB_HH
// TODO(garretrieger): move to new layout.
#include "../../../hb-ot-layout-gsubgpos.hh"
#include "Common.hh"
#include "SubstLookup.hh"
using OT::Layout::GSUB::SubstLookup;
namespace OT {
using Layout::GSUB_impl::SubstLookup;
namespace Layout {
namespace GSUB {
/*
* GSUB -- Glyph Substitution
@ -18,8 +19,6 @@ namespace Layout {
struct GSUB : GSUBGPOS
{
using Lookup = SubstLookup;
static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
const SubstLookup& get_lookup (unsigned int i) const
@ -27,15 +26,12 @@ struct GSUB : GSUBGPOS
bool subset (hb_subset_context_t *c) const
{
hb_subset_layout_context_t l (c, tableTag);
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
return GSUBGPOS::subset<SubstLookup> (&l);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (GSUBGPOS::sanitize<SubstLookup> (c));
}
{ return GSUBGPOS::sanitize<SubstLookup> (c); }
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
@ -49,10 +45,11 @@ struct GSUB : GSUBGPOS
};
}
}
struct GSUB_accelerator_t : Layout::GSUB::accelerator_t {
GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {}
struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t {
GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {}
};

View File

@ -5,20 +5,18 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
template <typename Types>
struct Ligature
{
protected:
typename Types::HBGlyphID
ligGlyph; /* GlyphID of ligature to substitute */
HeadlessArrayOf<typename Types::HBGlyphID>
component; /* Array of component GlyphIDs--start
HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */
HeadlessArrayOf<HBGlyphID16>
component; /* Array of component GlyphIDs--start
* with the second component--ordered
* in writing direction */
public:
DEFINE_SIZE_ARRAY (Types::size + 2, component);
DEFINE_SIZE_ARRAY (4, component);
bool sanitize (hb_sanitize_context_t *c) const
{
@ -29,9 +27,6 @@ struct Ligature
bool intersects (const hb_set_t *glyphs) const
{ return hb_all (component, glyphs); }
bool intersects_lig_glyph (const hb_set_t *glyphs) const
{ return glyphs->has(ligGlyph); }
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;
@ -67,24 +62,7 @@ struct Ligature
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %u (ligature substitution)",
c->buffer->idx);
}
c->replace_glyph (ligGlyph);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %u (ligature substitution)",
c->buffer->idx - 1u);
}
return_trace (true);
}
@ -105,31 +83,6 @@ struct Ligature
return_trace (false);
}
unsigned pos = 0;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
unsigned delta = c->buffer->sync_so_far ();
pos = c->buffer->idx;
char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
char *p = buf;
match_end += delta;
for (unsigned i = 0; i < count; i++)
{
match_positions[i] += delta;
if (i)
*p++ = ',';
snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]);
p += strlen(p);
}
c->buffer->message (c->font,
"ligating glyphs at %s",
buf);
}
ligate_input (c,
count,
match_positions,
@ -137,14 +90,6 @@ struct Ligature
ligGlyph,
total_component_count);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"ligated glyph at %u",
pos);
}
return_trace (true);
}

View File

@ -6,13 +6,12 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
template <typename Types>
struct LigatureSet
{
protected:
Array16OfOffset16To<Ligature<Types>>
Array16OfOffset16To<Ligature>
ligature; /* Array LigatureSet tables
* ordered by preference */
public:
@ -29,19 +28,7 @@ struct LigatureSet
return
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_map ([glyphs] (const Ligature<Types> &_) { return _.intersects (glyphs); })
| hb_any
;
}
bool intersects_lig_glyph (const hb_set_t *glyphs) const
{
return
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_map ([glyphs] (const Ligature<Types> &_) {
return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
})
| hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
| hb_any
;
}
@ -50,7 +37,7 @@ struct LigatureSet
{
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_apply ([c] (const Ligature<Types> &_) { _.closure (c); })
| hb_apply ([c] (const Ligature &_) { _.closure (c); })
;
}
@ -58,7 +45,7 @@ struct LigatureSet
{
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_apply ([c] (const Ligature<Types> &_) { _.collect_glyphs (c); })
| hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
;
}
@ -67,7 +54,7 @@ struct LigatureSet
return
+ hb_iter (ligature)
| hb_map (hb_add (this))
| hb_map ([c] (const Ligature<Types> &_) { return _.would_apply (c); })
| hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
| hb_any
;
}
@ -78,7 +65,7 @@ struct LigatureSet
unsigned int num_ligs = ligature.len;
for (unsigned int i = 0; i < num_ligs; i++)
{
const auto &lig = this+ligature[i];
const Ligature &lig = this+ligature[i];
if (lig.apply (c)) return_trace (true);
}

View File

@ -6,37 +6,28 @@
namespace OT {
namespace Layout {
namespace GSUB_impl {
namespace GSUB {
struct LigatureSubst
{
protected:
union {
HBUINT16 format; /* Format identifier */
LigatureSubstFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
LigatureSubstFormat1_2<MediumTypes> format2;
#endif
HBUINT16 format; /* Format identifier */
LigatureSubstFormat1 format1;
} u;
public:
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
/* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should
* be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t
* instead. */
bool serialize (hb_serialize_context_t *c,
hb_sorted_array_t<const HBGlyphID16> first_glyphs,
hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
@ -58,9 +49,6 @@ struct LigatureSubst
default:return_trace (false);
}
}
/* TODO subset() should choose format. */
};

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