Compare commits

..

19 Commits

Author SHA1 Message Date
Garret Rieger f2b9065246 [repacker] for ext promotion choose lookups from highest subtables per byte to lowest.
Attempts to roughly maximize the number of subtables that are non-ext.
2022-07-25 21:55:03 +00:00
Garret Rieger e4fd5ff727 [repacker] count subtable size in each group of consecutive layers for extension promotion decisions.
Enforce that the following groups are all <64k in size:
- LookupList + Lookups
- Lookups + SubTables
- SubTables + Descendants
2022-07-25 21:31:17 +00:00
Garret Rieger 0a5b69b255 [repacker] when calculating 16bit space size also consider ext lookup subtables. 2022-07-25 20:11:24 +00:00
Garret Rieger fa177b7f33 [repacker] include LookupList size when calculating size of 16bit space for ext promotion decisions. 2022-07-25 19:42:58 +00:00
Garret Rieger 156105b0f0 [repacker] Use extension promotion when repacking invoked via hb-subset-repacker (eg. from fonttools). 2022-07-25 19:16:03 +00:00
Garret Rieger e6dda54c88 [repacker] remove temporary visibility overrides in gsubgpos. 2022-07-22 22:49:40 +00:00
Garret Rieger ffb0f7936f [repacker] add ext promotion test. 2022-07-22 22:36:04 +00:00
Garret Rieger 7ebc92f2e0 [repacker] todo. 2022-07-21 23:12:15 +00:00
Garret Rieger 8c6afa69d5 [repacker] Add basic version of the extension promotion selection algorithm. 2022-07-21 22:50:14 +00:00
Garret Rieger 514fcea0aa [repacker] fix GSTAR sanitize. 2022-07-21 21:57:17 +00:00
Garret Rieger 2f63f0c861 [repacker] support extension promotion in 24bit GSUB/GPOS. 2022-07-21 21:54:42 +00:00
Garret Rieger a8887b2740 [repacker] save buffer reference (not copy). 2022-07-21 21:50:23 +00:00
Garret Rieger ede7b74584 [repacker] add sanitization for GSUB/LookupList/Lookup during extension promotion. 2022-07-21 21:45:04 +00:00
Garret Rieger c61c05e431 [repacker] add make_extension_context_t. 2022-07-21 19:07:55 +00:00
Garret Rieger f2a0e69162 [repacker] size buffer correctly. 2022-07-21 18:36:20 +00:00
Garret Rieger d520a6d522 [repack] fix incorrect extension object bounds. 2022-07-20 18:17:29 +00:00
Garret Rieger 5babfda3f2 [repack] fix new node bounds. 2022-07-20 03:26:29 +00:00
Garret Rieger c20b85cfed [repack] WIP implement extension promotion mechanism. 2022-07-19 23:33:16 +00:00
Garret Rieger d9295d88a7 [repacker] WIP extension promotion implementation. 2022-07-19 21:50:13 +00:00
619 changed files with 15197 additions and 60237 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,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

View File

@ -11,7 +11,7 @@ permissions:
jobs:
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3

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@v3
- 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@v3
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@v3
- 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@v3
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@v3
- uses: actions/setup-python@v4
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@v3
- 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.")
@ -107,17 +107,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 +208,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 +220,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 +240,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 +272,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,14 +300,12 @@ 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)
@ -566,7 +547,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 +701,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 +709,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 +720,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 +753,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 ()

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.

318
NEWS
View File

@ -1,321 +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
====================================

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.4.1],
[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)

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

@ -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,74 @@
</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-4-0" role="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" 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,25 +119,18 @@ 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
@ -161,9 +152,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 +179,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 +203,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>
@ -346,29 +264,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,124 +292,113 @@ 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
</SECTION>
@ -544,33 +449,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 +482,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 +501,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 +544,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 +554,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 +567,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 +589,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 +615,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 +632,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 +664,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 +686,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 +741,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 +758,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 +782,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

@ -1,9 +1,8 @@
project('harfbuzz', 'c', 'cpp',
meson_version: '>= 0.55.0',
version: '7.1.0',
version: '4.4.1',
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
@ -373,10 +320,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 +336,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 +350,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 +367,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

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

@ -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,18 +87,7 @@ 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 \
@ -104,17 +95,13 @@ HB_BASE_sources = \
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 \
@ -169,7 +156,6 @@ HB_BASE_sources = \
OT/Layout/GSUB/SingleSubst.hh \
OT/Layout/GSUB/SubstLookup.hh \
OT/Layout/GSUB/SubstLookupSubTable.hh \
OT/name/name.hh \
hb-ot-layout-gsubgpos.hh \
hb-ot-layout-jstf-table.hh \
hb-ot-layout.cc \
@ -225,7 +211,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 +246,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 +255,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 +286,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 +297,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 +330,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,8 +341,6 @@ 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 \
@ -368,15 +349,8 @@ HB_SUBSET_sources = \
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/gsubgpos-graph.cc \
graph/serialize.hh \
OT/Color/COLR/colrv1-closure.hh \
$(NULL)
HB_SUBSET_headers = \
@ -384,16 +358,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

@ -49,7 +49,7 @@ struct Coverage
HBUINT16 format; /* Format identifier */
CoverageFormat1_3<SmallTypes> format1;
CoverageFormat2_4<SmallTypes> format2;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
CoverageFormat1_3<MediumTypes>format3;
CoverageFormat2_4<MediumTypes>format4;
#endif
@ -65,7 +65,7 @@ struct Coverage
{
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return_trace (u.format3.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
#endif
@ -74,8 +74,10 @@ struct Coverage
}
/* Has interface. */
unsigned operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; }
static constexpr unsigned SENTINEL = NOT_COVERED;
typedef unsigned int value_t;
value_t operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
@ -85,7 +87,7 @@ struct Coverage
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
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.get_coverage (glyph_id);
case 4: return u.format4.get_coverage (glyph_id);
#endif
@ -93,19 +95,6 @@ struct Coverage
}
}
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)
@ -125,7 +114,7 @@ struct Coverage
}
u.format = count <= num_ranges * 3 ? 1 : 2;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
if (count && last > 0xFFFFu)
u.format += 2;
#endif
@ -134,7 +123,7 @@ struct Coverage
{
case 1: return_trace (u.format1.serialize (c, glyphs));
case 2: return_trace (u.format2.serialize (c, glyphs));
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return_trace (u.format3.serialize (c, glyphs));
case 4: return_trace (u.format4.serialize (c, glyphs));
#endif
@ -147,7 +136,6 @@ struct Coverage
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)
;
@ -165,7 +153,7 @@ struct Coverage
{
case 1: return u.format1.intersects (glyphs);
case 2: return u.format2.intersects (glyphs);
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.intersects (glyphs);
case 4: return u.format4.intersects (glyphs);
#endif
@ -178,7 +166,7 @@ struct Coverage
{
case 1: return u.format1.intersects_coverage (glyphs, index);
case 2: return u.format2.intersects_coverage (glyphs, index);
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.intersects_coverage (glyphs, index);
case 4: return u.format4.intersects_coverage (glyphs, index);
#endif
@ -195,7 +183,7 @@ struct Coverage
{
case 1: return u.format1.collect_coverage (glyphs);
case 2: return u.format2.collect_coverage (glyphs);
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.collect_coverage (glyphs);
case 4: return u.format4.collect_coverage (glyphs);
#endif
@ -203,17 +191,15 @@ struct Coverage
}
}
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
void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *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);
case 1: return u.format1.intersected_coverage_glyphs (glyphs, intersect_glyphs);
case 2: return u.format2.intersected_coverage_glyphs (glyphs, intersect_glyphs);
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.intersected_coverage_glyphs (glyphs, intersect_glyphs);
case 4: return u.format4.intersected_coverage_glyphs (glyphs, intersect_glyphs);
#endif
default:return ;
}
@ -224,13 +210,13 @@ struct Coverage
static constexpr bool is_sorted_iterator = true;
iter_t (const Coverage &c_ = Null (Coverage))
{
hb_memset (this, 0, sizeof (*this));
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
#ifndef HB_NO_BORING_EXPANSION
case 3: u.format3.init (c_.u.format3); return;
case 4: u.format4.init (c_.u.format4); return;
#endif
@ -241,11 +227,11 @@ struct Coverage
{
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__ ();
case 1: return u.format1.more ();
case 2: return u.format2.more ();
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.more ();
case 4: return u.format4.more ();
#endif
default:return false;
}
@ -254,11 +240,11 @@ struct Coverage
{
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;
case 1: u.format1.next (); break;
case 2: u.format2.next (); break;
#ifndef HB_NO_BORING_EXPANSION
case 3: u.format3.next (); break;
case 4: u.format4.next (); break;
#endif
default: break;
}
@ -272,7 +258,7 @@ struct Coverage
{
case 1: return u.format1.get_glyph ();
case 2: return u.format2.get_glyph ();
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3.get_glyph ();
case 4: return u.format4.get_glyph ();
#endif
@ -286,7 +272,7 @@ struct Coverage
{
case 1: return u.format1 != o.u.format1;
case 2: return u.format2 != o.u.format2;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return u.format3 != o.u.format3;
case 4: return u.format4 != o.u.format4;
#endif
@ -301,7 +287,7 @@ struct Coverage
{
case 1: it.u.format1 = u.format1.__end__ (); break;
case 2: it.u.format2 = u.format2.__end__ (); break;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: it.u.format3 = u.format3.__end__ (); break;
case 4: it.u.format4 = u.format4.__end__ (); break;
#endif
@ -313,7 +299,7 @@ struct Coverage
private:
unsigned int format;
union {
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
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

View File

@ -62,11 +62,6 @@ struct CoverageFormat1_3
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)
@ -77,14 +72,7 @@ struct CoverageFormat1_3
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;
}
/* TODO Speed up, using hb_set_next() and bsearch()? */
for (const auto& g : glyphArray.as_array ())
if (glyphs->has (g))
return true;
@ -93,14 +81,12 @@ struct CoverageFormat1_3
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
void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *intersect_glyphs) const
{
unsigned count = glyphArray.len;
for (unsigned i = 0; i < count; i++)
if (glyphs.has (glyphArray[i]))
intersect_glyphs << glyphArray[i];
if (glyphs->has (glyphArray[i]))
intersect_glyphs->add (glyphArray[i]);
}
template <typename set_t>
@ -112,8 +98,9 @@ struct CoverageFormat1_3
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++; }
void fini () {}
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; }

View File

@ -65,14 +65,6 @@ struct CoverageFormat2_4
: 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)
@ -80,6 +72,8 @@ struct CoverageFormat2_4
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
/* TODO(iter) Write more efficiently? */
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
for (auto g: glyphs)
@ -113,48 +107,47 @@ struct CoverageFormat2_4
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); }));
return hb_any (+ hb_iter (rangeRecord.as_array ())
| 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);
auto cmp = [] (const void *pk, const void *pr) -> int
{
unsigned index = * (const unsigned *) pk;
const RangeRecord<Types> &range = * (const RangeRecord<Types> *) pr;
if (index < range.value) return -1;
if (index > (unsigned int) range.value + (range.last - range.first)) return +1;
return 0;
};
auto arr = rangeRecord.as_array ();
unsigned idx;
if (hb_bsearch_impl (&idx, index,
arr.arrayZ, arr.length, sizeof (arr[0]),
(int (*)(const void *_key, const void *_item)) cmp))
return arr.arrayZ[idx].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
void intersected_coverage_glyphs (const hb_set_t *glyphs, hb_set_t *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)
for (const auto& range : rangeRecord.as_array ())
{
if (unlikely (range.first < last))
break;
last = range.last;
if (!range.intersects (glyphs)) continue;
unsigned last = range.last;
for (hb_codepoint_t g = range.first - 1;
glyphs.next (&g) && g <= last;)
intersect_glyphs << g;
glyphs->next (&g) && g <= last;)
intersect_glyphs->add (g);
}
}
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{
for (const auto& range: rangeRecord)
if (unlikely (!range.collect_coverage (glyphs)))
unsigned int count = rangeRecord.len;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!rangeRecord[i].collect_coverage (glyphs)))
return false;
return true;
}
@ -173,16 +166,16 @@ struct CoverageFormat2_4
{
/* Broken table. Skip. */
i = c->rangeRecord.len;
j = 0;
}
}
bool __more__ () const { return i < c->rangeRecord.len; }
void __next__ ()
void fini () {}
bool more () const { return i < c->rangeRecord.len; }
void next ()
{
if (j >= c->rangeRecord[i].last)
{
i++;
if (__more__ ())
if (more ())
{
unsigned int old = coverage;
j = c->rangeRecord[i].first;

View File

@ -51,14 +51,8 @@ struct RangeRecord
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); }
bool intersects (const hb_set_t *glyphs) const
{ return glyphs->intersects (first, last); }
template <typename set_t>
bool collect_coverage (set_t *glyphs) const

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

@ -58,7 +58,8 @@ struct Anchor
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));
case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
c->plan->layout_variation_idx_map))));
default:return_trace (false);
}
}

View File

@ -41,54 +41,24 @@ struct AnchorFormat3
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
}
bool subset (hb_subset_context_t *c) const
AnchorFormat3* copy (hb_serialize_context_t *c,
const hb_map_t *layout_variation_idx_map) 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);
TRACE_SERIALIZE (this);
if (!layout_variation_idx_map) return_trace (nullptr);
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);
}
}
auto *out = c->embed<AnchorFormat3> (this);
if (unlikely (!out)) return_trace (nullptr);
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);
out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_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);
(this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
(this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
}
};

View File

@ -22,8 +22,7 @@ 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);
const hb_map_t *layout_variation_idx_map);
}

View File

@ -19,8 +19,8 @@ struct CursivePos
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)...));
default:return_trace (c->default_return_value ());

View File

@ -140,14 +140,7 @@ struct CursivePosFormat1
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);
buffer->unsafe_to_break (i, j);
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);
@ -230,20 +223,7 @@ struct CursivePosFormat1
* 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);

View File

@ -39,7 +39,7 @@ struct GPOS : 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->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
return GSUBGPOS::subset<PosLookup> (&l);
}

View File

@ -39,13 +39,6 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
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);
@ -53,13 +46,6 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
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);
}
@ -97,11 +83,10 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
}
};
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 */)
static 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;

View File

@ -13,7 +13,7 @@ struct MarkBasePos
union {
HBUINT16 format; /* Format identifier */
MarkBasePosFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
MarkBasePosFormat1_2<MediumTypes> format2;
#endif
} u;
@ -22,11 +22,11 @@ struct MarkBasePos
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
#ifndef HB_NO_BORING_EXPANSION
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());

View File

@ -90,25 +90,6 @@ struct MarkBasePosFormat1_2
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);
@ -116,54 +97,48 @@ struct MarkBasePosFormat1_2
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. */
/* Now we search backwards for 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 (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)
do {
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
{
// 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;
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
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;
/* 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 */
if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
(skippy_iter.idx == 0 ||
_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) ||
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
_hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
_hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
_hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
))
break;
skippy_iter.reject ();
} while (true);
/* 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); }
//if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint);
unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
if (base_index == NOT_COVERED)
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
}
bool subset (hb_subset_context_t *c) const

View File

@ -13,7 +13,7 @@ struct MarkLigPos
union {
HBUINT16 format; /* Format identifier */
MarkLigPosFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
MarkLigPosFormat1_2<MediumTypes> format2;
#endif
} u;
@ -22,11 +22,11 @@ struct MarkLigPos
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
#ifndef HB_NO_BORING_EXPANSION
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());

View File

@ -100,41 +100,24 @@ struct MarkLigPosFormat1_2
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.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (c->last_base_until > buffer->idx)
unsigned unsafe_from;
if (!skippy_iter.prev (&unsafe_from))
{
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);
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, 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); }
//if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint);
unsigned int j = skippy_iter.idx;
unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
if (lig_index == NOT_COVERED)
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
@ -145,7 +128,7 @@ struct MarkLigPosFormat1_2
unsigned int comp_count = lig_attach.rows;
if (unlikely (!comp_count))
{
buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
@ -154,7 +137,7 @@ struct MarkLigPosFormat1_2
* 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 lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
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)
@ -162,7 +145,7 @@ struct MarkLigPosFormat1_2
else
comp_index = comp_count - 1;
return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
}
bool subset (hb_subset_context_t *c) const

View File

@ -13,7 +13,7 @@ struct MarkMarkPos
union {
HBUINT16 format; /* Format identifier */
MarkMarkPosFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
MarkMarkPosFormat1_2<MediumTypes> format2;
#endif
} u;
@ -22,11 +22,11 @@ struct MarkMarkPos
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
#ifndef HB_NO_BORING_EXPANSION
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());

View File

@ -9,7 +9,7 @@ struct MarkRecord
{
friend struct MarkArray;
public:
protected:
HBUINT16 klass; /* Class defined for this mark */
Offset16To<Anchor>
markAnchor; /* Offset to Anchor table--from

View File

@ -15,7 +15,7 @@ struct PairPos
HBUINT16 format; /* Format identifier */
PairPosFormat1_3<SmallTypes> format1;
PairPosFormat2_4<SmallTypes> format2;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
PairPosFormat1_3<MediumTypes> format3;
PairPosFormat2_4<MediumTypes> format4;
#endif
@ -25,12 +25,12 @@ struct PairPos
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)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
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

View File

@ -43,7 +43,7 @@ struct PairPosFormat1_3
{
valueFormat,
len1,
PairSet::get_size (len1, len2)
1 + len1 + len2
};
return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
@ -51,21 +51,8 @@ struct PairPosFormat1_3
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_zip (this+coverage, pairSet)
| hb_filter (*glyphs, hb_first)
| hb_map (hb_second)
| hb_map ([glyphs, this] (const typename Types::template OffsetTo<PairSet> &_)
@ -140,12 +127,6 @@ struct PairPosFormat1_3
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)
@ -177,21 +158,19 @@ struct PairPosFormat1_3
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
{
unsigned record_size = PairSet::get_size (valueFormat);
unsigned len1 = valueFormat[0].get_len ();
unsigned len2 = valueFormat[1].get_len ();
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
unsigned format1 = 0;
unsigned format2 = 0;
for (const auto & _ :
+ hb_zip (this+coverage, pairSet)
| hb_filter (glyphset, hb_first)
| hb_map (hb_second)
)
+ 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++)
for (unsigned i = 0; i < set.len; i++)
{
if (record->intersects (glyphset))
{
@ -200,9 +179,6 @@ struct PairPosFormat1_3
}
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
if (format1 == valueFormat[0] && format2 == valueFormat[1])
break;
}
return hb_pair (format1, format2);

View File

@ -49,7 +49,7 @@ struct PairPosFormat2_4
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int stride = HBUINT16::static_size * (len1 + len2);
unsigned int stride = 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,
@ -217,31 +217,10 @@ struct PairPosFormat2_4
}
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);
@ -249,15 +228,10 @@ struct PairPosFormat2_4
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;
if (len2)
buffer->idx++;
return_trace (true);
}
@ -287,19 +261,13 @@ struct PairPosFormat2_4
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);
valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
}
}
@ -322,7 +290,6 @@ struct PairPosFormat2_4
{
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
unsigned record_size = len1 + len2;
unsigned format1 = 0;
unsigned format2 = 0;
@ -331,13 +298,10 @@ struct PairPosFormat2_4
{
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
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);

View File

@ -24,22 +24,11 @@ struct PairSet
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 */
unsigned int stride; /* 1 + len1 + len2 */
};
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
@ -48,6 +37,7 @@ struct PairSet
if (!(c->check_struct (this)
&& c->check_range (&firstPairValueRecord,
len,
HBUINT16::static_size,
closure->stride))) return_trace (false);
unsigned int count = len;
@ -59,7 +49,9 @@ struct PairSet
bool intersects (const hb_set_t *glyphs,
const ValueFormat *valueFormats) const
{
unsigned record_size = get_size (valueFormats);
unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = &firstPairValueRecord;
unsigned int count = len;
@ -75,7 +67,9 @@ struct PairSet
void collect_glyphs (hb_collect_glyphs_context_t *c,
const ValueFormat *valueFormats) const
{
unsigned record_size = get_size (valueFormats);
unsigned int len1 = valueFormats[0].get_len ();
unsigned int len2 = valueFormats[1].get_len ();
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = &firstPairValueRecord;
c->input->add_array (&record->secondGlyph, len, record_size);
@ -84,7 +78,9 @@ struct PairSet
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats) const
{
unsigned record_size = get_size (valueFormats);
unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = &firstPairValueRecord;
unsigned count = len;
@ -105,7 +101,7 @@ struct PairSet
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);
unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
&firstPairValueRecord,
@ -113,42 +109,12 @@ struct PairSet
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);
}
pos++;
buffer->idx = pos;
return_trace (true);
}
@ -172,7 +138,7 @@ struct PairSet
unsigned len1 = valueFormats[0].get_len ();
unsigned len2 = valueFormats[1].get_len ();
unsigned record_size = get_size (len1, len2);
unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
typename PairValueRecord::context_t context =
{
@ -181,7 +147,7 @@ struct PairSet
newFormats,
len1,
&glyph_map,
&c->plan->layout_variation_idx_delta_map
c->plan->layout_variation_idx_map
};
const PairValueRecord *record = &firstPairValueRecord;

View File

@ -1,8 +1,6 @@
#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#include "ValueFormat.hh"
namespace OT {
namespace Layout {
namespace GPOS_impl {
@ -34,7 +32,7 @@ struct PairValueRecord
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;
const hb_map_t *layout_variation_idx_map;
};
bool subset (hb_subset_context_t *c,
@ -50,12 +48,12 @@ struct PairValueRecord
closure->valueFormats[0].copy_values (s,
closure->newFormats[0],
closure->base, &values[0],
closure->layout_variation_idx_delta_map);
closure->layout_variation_idx_map);
closure->valueFormats[1].copy_values (s,
closure->newFormats[1],
closure->base,
&values[closure->len1],
closure->layout_variation_idx_delta_map);
closure->layout_variation_idx_map);
return_trace (true);
}

View File

@ -38,18 +38,17 @@ struct SinglePos
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)
const hb_map_t *layout_variation_idx_map)
{
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);
new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
}
u.format = format;
switch (u.format) {
@ -57,13 +56,13 @@ struct SinglePos
src,
glyph_val_iter_pairs,
new_format,
layout_variation_idx_delta_map);
layout_variation_idx_map);
return;
case 2: u.format2.serialize (c,
src,
glyph_val_iter_pairs,
new_format,
layout_variation_idx_delta_map);
layout_variation_idx_map);
return;
default:return;
}
@ -72,8 +71,8 @@ struct SinglePos
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)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
@ -88,9 +87,8 @@ 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); }
const hb_map_t *layout_variation_idx_map)
{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
}

View File

@ -28,15 +28,7 @@ struct SinglePosFormat1
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
@ -47,10 +39,12 @@ struct SinglePosFormat1
{
if (!valueFormat.has_device ()) return;
hb_set_t intersection;
(this+coverage).intersect_set (*c->glyph_set, intersection);
if (!intersection) return;
auto it =
+ hb_iter (this+coverage)
| hb_filter (c->glyph_set)
;
if (!it) return;
valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
}
@ -68,44 +62,12 @@ struct SinglePosFormat1
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))>
@ -113,7 +75,7 @@ struct SinglePosFormat1
const SrcLookup *src,
Iterator it,
ValueFormat newFormat,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
const hb_map_t *layout_variation_idx_map)
{
if (unlikely (!c->extend_min (this))) return;
if (unlikely (!c->check_assign (valueFormat,
@ -122,7 +84,7 @@ struct SinglePosFormat1
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);
src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map);
// Only serialize the first entry in the iterator, the rest are assumed to
// be the same.
break;
@ -142,17 +104,15 @@ struct SinglePosFormat1
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_iter (this+coverage)
| hb_filter (glyphset)
| 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);
SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
return_trace (ret);
}
};

View File

@ -68,52 +68,16 @@ struct SinglePosFormat2
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);
}
if (likely (index >= valueCount)) return_trace (false);
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))>
@ -121,7 +85,7 @@ struct SinglePosFormat2
const SrcLookup *src,
Iterator it,
ValueFormat newFormat,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map)
const hb_map_t *layout_variation_idx_map)
{
auto out = c->extend_min (this);
if (unlikely (!out)) return;
@ -131,7 +95,7 @@ struct SinglePosFormat2
+ 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); })
{ src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
;
auto glyphs =
@ -163,7 +127,7 @@ struct SinglePosFormat2
;
bool ret = bool (it);
SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
return_trace (ret);
}
};

View File

@ -59,24 +59,6 @@ struct ValueFormat : HBUINT16
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,
@ -163,50 +145,30 @@ struct ValueFormat : HBUINT16
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
const hb_map_t *layout_variation_idx_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 & xPlacement) copy_value (c, new_format, xPlacement, *values++);
if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++);
if (format & yAdvance) 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);
}
if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
}
HBINT16* copy_value (hb_serialize_context_t *c,
unsigned int new_format,
Flags flag,
Value value) const
void 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));
if (!(new_format & flag)) return;
c->copy (value);
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
@ -221,40 +183,31 @@ struct ValueFormat : HBUINT16
if (format & yAdvance) i++;
if (format & xPlaDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
(base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
i++;
}
if (format & ValueFormat::yPlaDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
(base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
i++;
}
if (format & ValueFormat::xAdvDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
(base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
i++;
}
if (format & ValueFormat::yAdvDevice)
{
(base + get_device (&(values[i]))).collect_variation_indices (c);
(base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
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
{
@ -283,27 +236,9 @@ struct ValueFormat : HBUINT16
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
const Value *src_value, const hb_map_t *layout_variation_idx_map) const
{
// Filter by new format.
if (!(new_format & flag)) return true;
Value *dst_value = c->copy (*src_value);
if (!dst_value) return false;
@ -311,7 +246,7 @@ struct ValueFormat : HBUINT16
*dst_value = 0;
c->push ();
if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map))
if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
{
c->add_link (*dst_value, c->pop_pack ());
return true;
@ -371,7 +306,7 @@ struct ValueFormat : HBUINT16
for (unsigned int i = 0; i < count; i++) {
if (!sanitize_value_devices (c, base, values))
return_trace (false);
values = &StructAtOffset<const Value> (values, stride);
values += stride;
}
return_trace (true);

View File

@ -57,23 +57,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 +69,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

@ -14,7 +14,7 @@ struct AlternateSubst
union {
HBUINT16 format; /* Format identifier */
AlternateSubstFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
AlternateSubstFormat1_2<MediumTypes> format2;
#endif
} u;
@ -23,11 +23,11 @@ struct AlternateSubst
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
#ifndef HB_NO_BORING_EXPANSION
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());

View File

@ -42,6 +42,7 @@ struct AlternateSubstFormat1_2
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet<Types> &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}

View File

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

View File

@ -29,9 +29,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 +64,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 +85,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 +92,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

@ -34,18 +34,6 @@ struct LigatureSet
;
}
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_any
;
}
void closure (hb_closure_context_t *c) const
{
+ hb_iter (ligature)

View File

@ -14,7 +14,7 @@ struct LigatureSubst
union {
HBUINT16 format; /* Format identifier */
LigatureSubstFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
LigatureSubstFormat1_2<MediumTypes> format2;
#endif
} u;
@ -23,11 +23,11 @@ struct LigatureSubst
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
#ifndef HB_NO_BORING_EXPANSION
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());

View File

@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
| hb_filter (glyphset, hb_first)
| hb_filter ([&] (const LigatureSet<Types>& _) {
return _.intersects_lig_glyph (&glyphset);
return _.intersects (&glyphset);
}, hb_second)
| hb_map (hb_first)
| hb_sink (new_coverage);

View File

@ -14,7 +14,7 @@ struct MultipleSubst
union {
HBUINT16 format; /* Format identifier */
MultipleSubstFormat1_2<SmallTypes> format1;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
MultipleSubstFormat1_2<MediumTypes> format2;
#endif
} u;
@ -24,28 +24,30 @@ struct MultipleSubst
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
#ifndef HB_NO_BORING_EXPANSION
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#endif
default:return_trace (c->default_return_value ());
}
}
template<typename Iterator,
hb_requires (hb_is_sorted_iterator (Iterator))>
/* 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,
Iterator it)
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (u.format))) return_trace (false);
unsigned int format = 1;
u.format = format;
switch (u.format) {
case 1: return_trace (u.format1.serialize (c, it));
case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
default:return_trace (false);
}
}

View File

@ -71,31 +71,22 @@ struct MultipleSubstFormat1_2
return_trace ((this+sequence[index]).apply (c));
}
template<typename Iterator,
hb_requires (hb_is_sorted_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
Iterator it)
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
auto sequences =
+ it
| hb_map (hb_second)
;
auto glyphs =
+ it
| hb_map_retains_sorting (hb_first)
;
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!sequence.serialize (c, sequences.length))) return_trace (false);
for (auto& pair : hb_zip (sequences, sequence))
if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < glyphs.length; i++)
{
if (unlikely (!pair.second
.serialize_serialize (c, pair.first)))
unsigned int substitute_len = substitute_len_list[i];
if (unlikely (!sequence[i]
.serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
return_trace (false);
substitute_glyphs_list += substitute_len;
}
return_trace (coverage.serialize_serialize (c, glyphs));
}

View File

@ -20,8 +20,8 @@ struct ReverseChainSingleSubst
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)...));
default:return_trace (c->default_return_value ());

View File

@ -131,23 +131,7 @@ struct ReverseChainSingleSubstFormat1
c->buffer->idx + 1, &end_index))
{
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replacing glyph at %u (reverse chaining substitution)",
c->buffer->idx);
}
c->replace_glyph_inplace (substitute[index]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %u (reverse chaining substitution)",
c->buffer->idx);
}
/* Note: We DON'T decrease buffer->idx. The main loop does it
* for us. This is useful for preventing surprises if someone
* calls us through a Context lookup. */

View File

@ -40,58 +40,17 @@ struct Sequence
* as a "multiplied" 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 (multiple substitution)",
c->buffer->idx);
}
c->replace_glyph (substitute.arrayZ[0]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %u (multiple subtitution)",
c->buffer->idx - 1u);
}
return_trace (true);
}
/* Spec disallows this, but Uniscribe allows it.
* https://github.com/harfbuzz/harfbuzz/issues/253 */
else if (unlikely (count == 0))
{
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"deleting glyph at %u (multiple substitution)",
c->buffer->idx);
}
c->buffer->delete_glyph ();
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"deleted glyph at %u (multiple substitution)",
c->buffer->idx);
}
return_trace (true);
}
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"multiplying glyph at %u",
c->buffer->idx);
}
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
@ -106,26 +65,6 @@ struct Sequence
}
c->buffer->skip_glyph ();
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
char *p = buf;
for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
{
if (buf < p)
*p++ = ',';
snprintf (p, sizeof(buf) - (p - buf), "%u", i);
p += strlen(p);
}
c->buffer->message (c->font,
"multiplied glyphs at %s",
buf);
}
return_trace (true);
}

View File

@ -16,7 +16,7 @@ struct SingleSubst
HBUINT16 format; /* Format identifier */
SingleSubstFormat1_3<SmallTypes> format1;
SingleSubstFormat2_4<SmallTypes> format2;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
SingleSubstFormat1_3<MediumTypes> format3;
SingleSubstFormat2_4<MediumTypes> format4;
#endif
@ -27,12 +27,12 @@ struct SingleSubst
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)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
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
@ -55,7 +55,7 @@ struct SingleSubst
format = 1;
hb_codepoint_t mask = 0xFFFFu;
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
if (+ glyphs
| hb_map_retains_sorting (hb_first)
| hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
@ -78,7 +78,7 @@ struct SingleSubst
| hb_map_retains_sorting (hb_first),
delta));
case 2: return_trace (u.format2.serialize (c, glyphs));
#ifndef HB_NO_BEYOND_64K
#ifndef HB_NO_BORING_EXPANSION
case 3: return_trace (u.format3.serialize (c,
+ glyphs
| hb_map_retains_sorting (hb_first),

View File

@ -25,20 +25,9 @@ struct SingleSubstFormat1_3
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));
return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
}
hb_codepoint_t get_mask () const
{ return (1 << (8 * Types::size)) - 1; }
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
@ -47,33 +36,14 @@ struct SingleSubstFormat1_3
void closure (hb_closure_context_t *c) const
{
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
unsigned d = deltaGlyphID;
/* Help fuzzer avoid this function as much. */
unsigned pop = (this+coverage).get_population ();
if (pop >= mask)
return;
hb_set_t intersection;
(this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
/* In degenerate fuzzer-found fonts, but not real fonts,
* this table can keep adding new glyphs in each round of closure.
* Refuse to close-over, if it maps glyph range to overlapping range. */
hb_codepoint_t min_before = intersection.get_min ();
hb_codepoint_t max_before = intersection.get_max ();
hb_codepoint_t min_after = (min_before + d) & mask;
hb_codepoint_t max_after = (max_before + d) & mask;
if (intersection.get_population () == max_before - min_before + 1 &&
((min_before <= min_after && min_after <= max_before) ||
(min_before <= max_after && max_after <= max_before)))
return;
+ hb_iter (intersection)
| hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
+ hb_iter (this+coverage)
| hb_filter (c->parent_active_glyphs ())
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -81,11 +51,9 @@ struct SingleSubstFormat1_3
void collect_glyphs (hb_collect_glyphs_context_t *c) const
{
if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
unsigned d = deltaGlyphID;
+ hb_iter (this+coverage)
| hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output)
;
}
@ -95,34 +63,6 @@ struct SingleSubstFormat1_3
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
unsigned
get_glyph_alternates (hb_codepoint_t glyph_id,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED))
{
if (alternate_count)
*alternate_count = 0;
return 0;
}
if (alternate_count && *alternate_count)
{
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
glyph_id = (glyph_id + d) & mask;
*alternate_glyphs = glyph_id;
*alternate_count = 1;
}
return 1;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
@ -130,28 +70,11 @@ struct SingleSubstFormat1_3
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED)) return_trace (false);
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
glyph_id = (glyph_id + d) & mask;
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->sync_so_far ();
c->buffer->message (c->font,
"replacing glyph at %u (single substitution)",
c->buffer->idx);
}
/* According to the Adobe Annotated OpenType Suite, result is always
* limited to 16bit. */
glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
c->replace_glyph (glyph_id);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %u (single substitution)",
c->buffer->idx - 1u);
}
return_trace (true);
}
@ -174,17 +97,14 @@ struct SingleSubstFormat1_3
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();
hb_set_t intersection;
(this+coverage).intersect_set (glyphset, intersection);
hb_codepoint_t delta = deltaGlyphID;
auto it =
+ hb_iter (intersection)
| hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) {
+ hb_iter (this+coverage)
| hb_filter (glyphset)
| hb_map_retains_sorting ([&] (hb_codepoint_t g) {
return hb_codepoint_pair_t (g,
(g + d) & mask); })
(g + delta) & 0xFFFF); })
| hb_filter (glyphset, hb_second)
| hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })

View File

@ -36,27 +36,12 @@ struct SingleSubstFormat2_4
void closure (hb_closure_context_t *c) const
{
auto &cov = this+coverage;
auto &glyph_set = c->parent_active_glyphs ();
if (substitute.len > glyph_set.get_population () * 4)
{
for (auto g : glyph_set)
{
unsigned i = cov.get_coverage (g);
if (i == NOT_COVERED || i >= substitute.len)
continue;
c->output->add (substitute.arrayZ[i]);
}
return;
}
+ hb_zip (cov, substitute)
| hb_filter (glyph_set, hb_first)
+ hb_zip (this+coverage, substitute)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -75,31 +60,6 @@ struct SingleSubstFormat2_4
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
unsigned
get_glyph_alternates (hb_codepoint_t glyph_id,
unsigned start_offset,
unsigned *alternate_count /* IN/OUT. May be NULL. */,
hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
{
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (likely (index == NOT_COVERED))
{
if (alternate_count)
*alternate_count = 0;
return 0;
}
if (alternate_count && *alternate_count)
{
glyph_id = substitute[index];
*alternate_glyphs = glyph_id;
*alternate_count = 1;
}
return 1;
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
@ -108,23 +68,8 @@ struct SingleSubstFormat2_4
if (unlikely (index >= substitute.len)) 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 (single substitution)",
c->buffer->idx);
}
c->replace_glyph (substitute[index]);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
"replaced glyph at %u (single substitution)",
c->buffer->idx - 1u);
}
return_trace (true);
}

View File

@ -119,16 +119,19 @@ struct SubstLookup : Lookup
return_trace (false);
}
template<typename Iterator,
hb_requires (hb_is_sorted_iterator (Iterator))>
bool serialize (hb_serialize_context_t *c,
uint32_t lookup_props,
Iterator it)
bool serialize_multiple (hb_serialize_context_t *c,
uint32_t lookup_props,
hb_sorted_array_t<const HBGlyphID16> glyphs,
hb_array_t<const unsigned int> substitute_len_list,
hb_array_t<const HBGlyphID16> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
if (c->push<SubTable> ()->u.multiple.
serialize (c, it))
serialize (c,
glyphs,
substitute_len_list,
substitute_glyphs_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);

View File

@ -34,7 +34,6 @@ namespace Layout {
struct SmallTypes {
static constexpr unsigned size = 2;
using large_int = uint32_t;
using HBUINT = HBUINT16;
using HBGlyphID = HBGlyphID16;
using Offset = Offset16;
@ -48,7 +47,6 @@ struct SmallTypes {
struct MediumTypes {
static constexpr unsigned size = 3;
using large_int = uint64_t;
using HBUINT = HBUINT24;
using HBGlyphID = HBGlyphID24;
using Offset = Offset24;

View File

@ -3,7 +3,6 @@
#include "../../hb-open-type.hh"
#include "composite-iter.hh"
namespace OT {
@ -27,9 +26,7 @@ struct CompositeGlyphRecord
OVERLAP_COMPOUND = 0x0400,
SCALED_COMPONENT_OFFSET = 0x0800,
UNSCALED_COMPONENT_OFFSET = 0x1000,
#ifndef HB_NO_BEYOND_64K
GID_IS_24BIT = 0x2000
#endif
};
public:
@ -37,9 +34,7 @@ struct CompositeGlyphRecord
{
unsigned int size = min_size;
/* glyphIndex is 24bit instead of 16bit */
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
#endif
/* arg1 and 2 are int16 */
if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
/* arg1 and 2 are int8 */
@ -69,11 +64,9 @@ struct CompositeGlyphRecord
void get_anchor_points (unsigned int &point1, unsigned int &point2) const
{
const auto *p = &StructAfter<const HBUINT8> (flags);
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
#endif
p += HBGlyphID16::static_size;
if (flags & ARG_1_AND_2_ARE_WORDS)
{
@ -87,108 +80,38 @@ struct CompositeGlyphRecord
}
}
void transform_points (contour_point_vector_t &points,
const float (&matrix)[4],
const contour_point_t &trans) const
{
if (scaled_offsets ())
{
points.translate (trans);
points.transform (matrix);
}
else
{
points.transform (matrix);
points.translate (trans);
}
}
bool get_points (contour_point_vector_t &points) const
void transform_points (contour_point_vector_t &points) const
{
float matrix[4];
contour_point_t trans;
get_transformation (matrix, trans);
if (unlikely (!points.resize (points.length + 1))) return false;
points[points.length - 1] = trans;
return true;
}
unsigned compile_with_point (const contour_point_t &point,
char *out) const
{
const HBINT8 *p = &StructAfter<const HBINT8> (flags);
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
#endif
p += HBGlyphID16::static_size;
unsigned len = get_size ();
unsigned len_before_val = (const char *)p - (const char *)this;
if (flags & ARG_1_AND_2_ARE_WORDS)
if (get_transformation (matrix, trans))
{
// no overflow, copy value
hb_memcpy (out, this, len);
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
o[0] = roundf (point.x);
o[1] = roundf (point.y);
}
else
{
int new_x = roundf (point.x);
int new_y = roundf (point.y);
if (new_x <= 127 && new_x >= -128 &&
new_y <= 127 && new_y >= -128)
if (scaled_offsets ())
{
hb_memcpy (out, this, len);
HBINT8 *o = reinterpret_cast<HBINT8 *> (out + len_before_val);
o[0] = new_x;
o[1] = new_y;
points.translate (trans);
points.transform (matrix);
}
else
{
// new point value has an int8 overflow
hb_memcpy (out, this, len_before_val);
//update flags
CompositeGlyphRecord *o = reinterpret_cast<CompositeGlyphRecord *> (out);
o->flags = flags | ARG_1_AND_2_ARE_WORDS;
out += len_before_val;
HBINT16 new_value;
new_value = new_x;
hb_memcpy (out, &new_value, HBINT16::static_size);
out += HBINT16::static_size;
new_value = new_y;
hb_memcpy (out, &new_value, HBINT16::static_size);
out += HBINT16::static_size;
hb_memcpy (out, p+2, len - len_before_val - 2);
len += 2;
points.transform (matrix);
points.translate (trans);
}
}
return len;
}
protected:
bool scaled_offsets () const
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
public:
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
{
matrix[0] = matrix[3] = 1.f;
matrix[1] = matrix[2] = 0.f;
const auto *p = &StructAfter<const HBINT8> (flags);
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
#endif
p += HBGlyphID16::static_size;
int tx, ty;
if (flags & ARG_1_AND_2_ARE_WORDS)
@ -232,47 +155,23 @@ struct CompositeGlyphRecord
return tx || ty;
}
public:
hb_codepoint_t get_gid () const
{
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
return StructAfter<const HBGlyphID24> (flags);
else
#endif
return StructAfter<const HBGlyphID16> (flags);
}
void set_gid (hb_codepoint_t gid)
{
#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
StructAfter<HBGlyphID24> (flags) = gid;
else
#endif
/* TODO assert? */
StructAfter<HBGlyphID16> (flags) = gid;
}
#ifndef HB_NO_BEYOND_64K
void lower_gid_24_to_16 ()
{
hb_codepoint_t gid = get_gid ();
if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
return;
/* Lower the flag and move the rest of the struct down. */
unsigned size = get_size ();
char *end = (char *) this + size;
char *p = &StructAfter<char> (flags);
p += HBGlyphID24::static_size;
flags = flags & ~GID_IS_24BIT;
set_gid (gid);
memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
}
#endif
protected:
HBUINT16 flags;
HBUINT24 pad;
@ -280,7 +179,55 @@ struct CompositeGlyphRecord
DEFINE_SIZE_MIN (4);
};
using composite_iter_t = composite_iter_tmpl<CompositeGlyphRecord>;
struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphRecord &>
{
typedef const CompositeGlyphRecord *__item_t__;
composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
glyph (glyph_), current (nullptr), current_size (0)
{
set_current (current_);
}
composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
item_t __item__ () const { return *current; }
bool __more__ () const { return current; }
void __next__ ()
{
if (!current->has_more ()) { current = nullptr; return; }
set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size));
}
composite_iter_t __end__ () const { return composite_iter_t (); }
bool operator != (const composite_iter_t& o) const
{ return current != o.current; }
void set_current (__item_t__ current_)
{
if (!glyph.check_range (current_, CompositeGlyphRecord::min_size))
{
current = nullptr;
current_size = 0;
return;
}
unsigned size = current_->get_size ();
if (!glyph.check_range (current_, size))
{
current = nullptr;
current_size = 0;
return;
}
current = current_;
current_size = size;
}
private:
hb_bytes_t glyph;
__item_t__ current;
unsigned current_size;
};
struct CompositeGlyph
{
@ -329,66 +276,6 @@ struct CompositeGlyph
return;
glyph_chain.set_overlaps_flag ();
}
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
const contour_point_vector_t &points_with_deltas,
hb_bytes_t &dest_bytes /* OUT */)
{
if (source_bytes.length <= GlyphHeader::static_size ||
header.numberOfContours != -1)
{
dest_bytes = hb_bytes_t ();
return true;
}
unsigned source_len = source_bytes.length - GlyphHeader::static_size;
/* try to allocate more memories than source glyph bytes
* in case that there might be an overflow for int8 value
* and we would need to use int16 instead */
char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
if (unlikely (!o)) return false;
const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c);
char *p = o;
unsigned i = 0, source_comp_len = 0;
for (const auto &component : it)
{
/* last 4 points in points_with_deltas are phantom points and should not be included */
if (i >= points_with_deltas.length - 4) {
free (o);
return false;
}
unsigned comp_len = component.get_size ();
if (component.is_anchored ())
{
hb_memcpy (p, &component, comp_len);
p += comp_len;
}
else
{
unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
p += new_len;
}
i++;
source_comp_len += comp_len;
}
//copy instructions if any
if (source_len > source_comp_len)
{
unsigned instr_len = source_len - source_comp_len;
hb_memcpy (p, (const char *)c + source_comp_len, instr_len);
p += instr_len;
}
unsigned len = p - o;
dest_bytes = hb_bytes_t (o, len);
return true;
}
};

View File

@ -7,8 +7,6 @@
#include "GlyphHeader.hh"
#include "SimpleGlyph.hh"
#include "CompositeGlyph.hh"
#include "VarCompositeGlyph.hh"
#include "coord-setter.hh"
namespace OT {
@ -29,14 +27,7 @@ enum phantom_point_index_t
struct Glyph
{
enum glyph_type_t {
EMPTY,
SIMPLE,
COMPOSITE,
#ifndef HB_NO_VAR_COMPOSITES
VAR_COMPOSITE,
#endif
};
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
public:
composite_iter_t get_composite_iterator () const
@ -44,25 +35,12 @@ struct Glyph
if (type != COMPOSITE) return composite_iter_t ();
return CompositeGlyph (*header, bytes).iter ();
}
var_composite_iter_t get_var_composite_iterator () const
{
#ifndef HB_NO_VAR_COMPOSITES
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
return VarCompositeGlyph (*header, bytes).iter ();
#else
return var_composite_iter_t ();
#endif
}
const hb_bytes_t trim_padding () const
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
#endif
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
case EMPTY: return bytes;
default: return bytes;
}
}
@ -70,279 +48,67 @@ struct Glyph
void drop_hints ()
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
case EMPTY: return;
default: return;
}
}
void set_overlaps_flag ()
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No overlaps flag
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
case EMPTY: return;
default: return;
}
}
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
case EMPTY: return;
default: return;
}
}
void update_mtx (const hb_subset_plan_t *plan,
int xMin, int xMax,
int yMin, int yMax,
const contour_point_vector_t &all_points) const
{
hb_codepoint_t new_gid = 0;
if (!plan->new_gid_for_old_gid (gid, &new_gid))
return;
if (type != EMPTY)
{
plan->bounds_width_map.set (new_gid, xMax - xMin);
plan->bounds_height_map.set (new_gid, yMax - yMin);
}
unsigned len = all_points.length;
float leftSideX = all_points[len - 4].x;
float rightSideX = all_points[len - 3].x;
float topSideY = all_points[len - 2].y;
float bottomSideY = all_points[len - 1].y;
signed hori_aw = roundf (rightSideX - leftSideX);
if (hori_aw < 0) hori_aw = 0;
int lsb = roundf (xMin - leftSideX);
plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
//flag value should be computed using non-empty glyphs
if (type != EMPTY && lsb != xMin)
plan->head_maxp_info.allXMinIsLsb = false;
signed vert_aw = roundf (topSideY - bottomSideY);
if (vert_aw < 0) vert_aw = 0;
int tsb = roundf (topSideY - yMax);
plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
}
bool compile_header_bytes (const hb_subset_plan_t *plan,
const contour_point_vector_t &all_points,
hb_bytes_t &dest_bytes /* OUT */) const
{
GlyphHeader *glyph_header = nullptr;
if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
{
glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
if (unlikely (!glyph_header)) return false;
}
float xMin = 0, xMax = 0;
float yMin = 0, yMax = 0;
if (all_points.length > 4)
{
xMin = xMax = all_points[0].x;
yMin = yMax = all_points[0].y;
}
for (unsigned i = 1; i < all_points.length - 4; i++)
{
float x = all_points[i].x;
float y = all_points[i].y;
xMin = hb_min (xMin, x);
xMax = hb_max (xMax, x);
yMin = hb_min (yMin, y);
yMax = hb_max (yMax, y);
}
update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points);
int rounded_xMin = roundf (xMin);
int rounded_xMax = roundf (xMax);
int rounded_yMin = roundf (yMin);
int rounded_yMax = roundf (yMax);
if (type != EMPTY)
{
plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
}
/* when pinned at default, no need to compile glyph header
* and for empty glyphs: all_points only include phantom points.
* just update metrics and then return */
if (!glyph_header)
return true;
glyph_header->numberOfContours = header->numberOfContours;
glyph_header->xMin = rounded_xMin;
glyph_header->yMin = rounded_yMin;
glyph_header->xMax = rounded_xMax;
glyph_header->yMax = rounded_yMax;
dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
return true;
}
bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
hb_font_t *font,
const glyf_accelerator_t &glyf,
hb_bytes_t &dest_start, /* IN/OUT */
hb_bytes_t &dest_end /* OUT */)
{
contour_point_vector_t all_points, points_with_deltas;
unsigned composite_contours = 0;
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
unsigned *composite_contours_p = &composite_contours;
// don't compute head/maxp values when glyph has no contours(type is EMPTY)
// also ignore .notdef glyph when --notdef-outline is not enabled
if (type == EMPTY ||
(gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
{
head_maxp_info_p = nullptr;
composite_contours_p = nullptr;
}
if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
// it
if (gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
{
type = EMPTY;
dest_start = hb_bytes_t ();
dest_end = hb_bytes_t ();
}
//dont compile bytes when pinned at default, just recalculate bounds
if (!plan->pinned_at_default)
{
switch (type)
{
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
// TODO
dest_end = hb_bytes_t ();
break;
#endif
case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
points_with_deltas,
dest_end))
return false;
break;
case SIMPLE:
if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
dest_end))
return false;
break;
case EMPTY:
/* set empty bytes for empty glyph
* do not use source glyph's pointers */
dest_start = hb_bytes_t ();
dest_end = hb_bytes_t ();
break;
}
}
if (!compile_header_bytes (plan, all_points, dest_start))
{
dest_end.fini ();
return false;
}
return true;
}
/* Note: Recursively calls itself.
* all_points includes phantom points
*/
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
bool shift_points_hori = true,
bool use_my_metrics = true,
bool phantom_only = false,
hb_array_t<int> coords = hb_array_t<int> (),
unsigned int depth = 0,
unsigned *edge_count = nullptr) const
unsigned int depth = 0) const
{
if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
unsigned stack_edge_count = 0;
if (!edge_count) edge_count = &stack_edge_count;
if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
(*edge_count)++;
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
}
if (!coords)
coords = hb_array (font->coords, font->num_coords);
contour_point_vector_t stack_points;
bool inplace = type == SIMPLE && all_points.length == 0;
/* Load into all_points if it's empty, as an optimization. */
contour_point_vector_t &points = inplace ? all_points : stack_points;
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
if (depth > 0 && composite_contours)
*composite_contours += (unsigned) header->numberOfContours;
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
return false;
break;
case COMPOSITE:
{
for (auto &item : get_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
/* pseudo component points for each component in composite glyph */
unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
if (unlikely (!points.resize (num_points))) return false;
break;
}
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
for (auto &item : get_var_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
}
#endif
case EMPTY:
case SIMPLE:
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
return false;
break;
}
/* Init phantom points */
if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
{
int lsb = 0;
int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
(int) header->xMin - lsb : 0;
HB_UNUSED int tsb = 0;
int tsb = 0;
int v_orig = (int) header->yMax +
#ifndef HB_NO_VERTICAL
((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
@ -359,29 +125,17 @@ struct Glyph
#endif
;
phantoms[PHANTOM_LEFT].x = h_delta;
phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
phantoms[PHANTOM_TOP].y = v_orig;
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
#ifndef HB_NO_VAR
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ());
glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ());
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
// with child glyphs' points
if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
{
if (unlikely (!points_with_deltas->resize (points.length))) return false;
points_with_deltas->copy_vector (points);
}
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
if (!inplace)
all_points.extend (points.as_array ());
break;
@ -393,31 +147,20 @@ struct Glyph
{
comp_points.reset ();
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font,
glyf_accelerator,
comp_points,
points_with_deltas,
head_maxp_info,
composite_contours,
shift_points_hori,
use_my_metrics,
phantom_only,
coords,
depth + 1,
edge_count)))
.get_points (font, glyf_accelerator, comp_points,
phantom_only, depth + 1)))
return false;
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
if (item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
float matrix[4];
contour_point_t default_trans;
item.get_transformation (matrix, default_trans);
/* Apply component transformation & translation */
item.transform_points (comp_points);
/* Apply component transformation & translation (with deltas applied) */
item.transform_points (comp_points, matrix, points[comp_index]);
/* Apply translation from gvar */
comp_points.translate (points[comp_index]);
if (item.is_anchored ())
{
@ -433,80 +176,18 @@ struct Glyph
}
}
all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
if (all_points.length > HB_GLYF_MAX_POINTS)
return false;
all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
comp_index++;
}
if (head_maxp_info && depth == 0)
{
if (composite_contours)
head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
}
all_points.extend (phantoms);
} break;
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
contour_point_vector_t comp_points;
hb_array_t<contour_point_t> points_left = points.as_array ();
for (auto &item : get_var_composite_iterator ())
{
hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ());
comp_points.reset ();
auto component_coords = coords;
if (item.is_reset_unspecified_axes ())
component_coords = hb_array<int> ();
coord_setter_t coord_setter (component_coords);
item.set_variations (coord_setter, record_points);
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
.get_points (font,
glyf_accelerator,
comp_points,
points_with_deltas,
head_maxp_info,
nullptr,
shift_points_hori,
use_my_metrics,
phantom_only,
coord_setter.get_coords (),
depth + 1,
edge_count)))
return false;
/* Apply component transformation */
item.transform_points (record_points, comp_points);
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
if (all_points.length > HB_GLYF_MAX_POINTS)
return false;
points_left += item.get_num_points ();
}
default:
all_points.extend (phantoms);
} break;
#endif
case EMPTY:
all_points.extend (phantoms);
break;
}
if (depth == 0 && shift_points_hori) /* Apply at top level */
if (depth == 0) /* Apply at top level */
{
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
@ -527,26 +208,15 @@ struct Glyph
}
hb_bytes_t get_bytes () const { return bytes; }
glyph_type_t get_type () const { return type; }
const GlyphHeader *get_header () const { return header; }
Glyph () : bytes (),
header (bytes.as<GlyphHeader> ()),
gid (-1),
type(EMPTY)
{}
Glyph (hb_bytes_t bytes_,
hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
header (bytes.as<GlyphHeader> ()),
gid (gid_)
Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_),
header (bytes.as<GlyphHeader> ()),
gid (gid_)
{
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
#ifndef HB_NO_VAR_COMPOSITES
else if (num_contours == -2) type = VAR_COMPOSITE;
#endif
else type = COMPOSITE; /* negative numbers */
}
@ -554,7 +224,7 @@ struct Glyph
hb_bytes_t bytes;
const GlyphHeader *header;
hb_codepoint_t gid;
glyph_type_t type;
unsigned type;
};

View File

@ -21,12 +21,10 @@ struct GlyphHeader
/* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
int lsb = hb_min (xMin, xMax);
(void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
extents->x_bearing = lsb;
extents->y_bearing = hb_max (yMin, yMax);
extents->width = hb_max (xMin, xMax) - hb_min (xMin, xMax);
extents->height = hb_min (yMin, yMax) - hb_max (yMin, yMax);
font->scale_glyph_extents (extents);
extents->x_bearing = font->em_scale_x (lsb);
extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
return true;
}

View File

@ -20,7 +20,7 @@ struct SimpleGlyph
FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20,
FLAG_OVERLAP_SIMPLE = 0x40,
FLAG_CUBIC = 0x80
FLAG_RESERVED2 = 0x80
};
const GlyphHeader &header;
@ -34,11 +34,6 @@ struct SimpleGlyph
unsigned int length (unsigned int instruction_len) const
{ return instruction_len_offset () + 2 + instruction_len; }
bool has_instructions_length () const
{
return instruction_len_offset () + 2 <= bytes.length;
}
unsigned int instructions_length () const
{
unsigned int instruction_length_offset = instruction_len_offset ();
@ -99,7 +94,6 @@ struct SimpleGlyph
/* zero instruction length */
void drop_hints ()
{
if (!has_instructions_length ()) return;
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
}
@ -138,8 +132,8 @@ struct SimpleGlyph
if (unlikely (p + 1 > end)) return false;
unsigned int repeat_count = *p++;
unsigned stop = hb_min (i + repeat_count, count);
for (; i < stop; i++)
points_.arrayZ[i].flag = flag;
for (; i < stop;)
points_.arrayZ[i++].flag = flag;
}
}
return true;
@ -190,7 +184,7 @@ struct SimpleGlyph
if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy
if (!points_.resize (num_points)) return false;
if (phantom_only) return true;
@ -212,129 +206,6 @@ struct SimpleGlyph
&& read_points (p, points_, end, &contour_point_t::y,
FLAG_Y_SHORT, FLAG_Y_SAME);
}
static void encode_coord (int value,
uint8_t &flag,
const simple_glyph_flag_t short_flag,
const simple_glyph_flag_t same_flag,
hb_vector_t<uint8_t> &coords /* OUT */)
{
if (value == 0)
{
flag |= same_flag;
}
else if (value >= -255 && value <= 255)
{
flag |= short_flag;
if (value > 0) flag |= same_flag;
else value = -value;
coords.arrayZ[coords.length++] = (uint8_t) value;
}
else
{
int16_t val = value;
coords.arrayZ[coords.length++] = val >> 8;
coords.arrayZ[coords.length++] = val & 0xff;
}
}
static void encode_flag (uint8_t &flag,
uint8_t &repeat,
uint8_t lastflag,
hb_vector_t<uint8_t> &flags /* OUT */)
{
if (flag == lastflag && repeat != 255)
{
repeat++;
if (repeat == 1)
{
/* We know there's room. */
flags.arrayZ[flags.length++] = flag;
}
else
{
unsigned len = flags.length;
flags.arrayZ[len-2] = flag | FLAG_REPEAT;
flags.arrayZ[len-1] = repeat;
}
}
else
{
repeat = 0;
flags.push (flag);
}
}
bool compile_bytes_with_deltas (const contour_point_vector_t &all_points,
bool no_hinting,
hb_bytes_t &dest_bytes /* OUT */)
{
if (header.numberOfContours == 0 || all_points.length <= 4)
{
dest_bytes = hb_bytes_t ();
return true;
}
unsigned num_points = all_points.length - 4;
hb_vector_t<uint8_t> flags, x_coords, y_coords;
if (unlikely (!flags.alloc (num_points, true))) return false;
if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
uint8_t lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0;
for (unsigned i = 0; i < num_points; i++)
{
uint8_t flag = all_points.arrayZ[i].flag;
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
int cur_x = roundf (all_points.arrayZ[i].x);
int cur_y = roundf (all_points.arrayZ[i].y);
encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
encode_flag (flag, repeat, lastflag, flags);
prev_x = cur_x;
prev_y = cur_y;
lastflag = flag;
}
unsigned len_before_instrs = 2 * header.numberOfContours + 2;
unsigned len_instrs = instructions_length ();
unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length;
if (!no_hinting)
total_len += len_instrs;
char *p = (char *) hb_malloc (total_len);
if (unlikely (!p)) return false;
const char *src = bytes.arrayZ + GlyphHeader::static_size;
char *cur = p;
hb_memcpy (p, src, len_before_instrs);
cur += len_before_instrs;
src += len_before_instrs;
if (!no_hinting)
{
hb_memcpy (cur, src, len_instrs);
cur += len_instrs;
}
hb_memcpy (cur, flags.arrayZ, flags.length);
cur += flags.length;
hb_memcpy (cur, x_coords.arrayZ, x_coords.length);
cur += x_coords.length;
hb_memcpy (cur, y_coords.arrayZ, y_coords.length);
dest_bytes = hb_bytes_t (p, total_len);
return true;
}
};

View File

@ -6,35 +6,27 @@
namespace OT {
struct glyf_accelerator_t;
namespace glyf_impl {
struct SubsetGlyph
{
hb_codepoint_t new_gid;
hb_codepoint_t old_gid;
Glyph source_glyph;
hb_bytes_t dest_start; /* region of source_glyph to copy first */
hb_bytes_t dest_end; /* region of source_glyph to copy second */
bool allocated;
bool serialize (hb_serialize_context_t *c,
bool use_short_loca,
const hb_subset_plan_t *plan)
const hb_subset_plan_t *plan) const
{
TRACE_SERIALIZE (this);
hb_bytes_t dest_glyph = dest_start.copy (c);
hb_bytes_t end_copy = dest_end.copy (c);
if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
return false;
}
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
unsigned int pad_length = use_short_loca ? padding () : 0;
DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
HBUINT8 pad;
pad = 0;
@ -46,68 +38,13 @@ struct SubsetGlyph
if (unlikely (!dest_glyph.length)) return_trace (true);
/* update components gids. */
/* update components gids */
for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
}
#ifndef HB_NO_VAR_COMPOSITES
for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
}
#endif
#ifndef HB_NO_BEYOND_64K
auto it = Glyph (dest_glyph).get_composite_iterator ();
if (it)
{
/* lower GID24 to GID16 in components if possible.
*
* TODO: VarComposite. Not as critical, since VarComposite supports
* gid24 from the first version. */
char *p = it ? (char *) &*it : nullptr;
char *q = p;
const char *end = dest_glyph.arrayZ + dest_glyph.length;
while (it)
{
auto &rec = const_cast<CompositeGlyphRecord &> (*it);
++it;
q += rec.get_size ();
rec.lower_gid_24_to_16 ();
unsigned size = rec.get_size ();
memmove (p, &rec, size);
p += size;
}
memmove (p, q, end - q);
p += end - q;
/* We want to shorten the glyph, but we can't do that without
* updating the length in the loca table, which is already
* written out :-(. So we just fill the rest of the glyph with
* harmless instructions, since that's what they will be
* interpreted as.
*
* Should move the lowering to _populate_subset_glyphs() to
* fix this issue. */
hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
p += end - p;
dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);
// TODO: Padding; & trim serialized bytes.
// TODO: Update length in loca. Ugh.
}
#endif
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
Glyph (dest_glyph).drop_hints ();
@ -118,23 +55,6 @@ struct SubsetGlyph
return_trace (true);
}
bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
hb_font_t *font,
const glyf_accelerator_t &glyf)
{
allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end);
return allocated;
}
void free_compiled_bytes ()
{
if (likely (allocated)) {
allocated = false;
dest_start.fini ();
dest_end.fini ();
}
}
void drop_hints_bytes ()
{ source_glyph.drop_hints_bytes (dest_start, dest_end); }

View File

@ -1,369 +0,0 @@
#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH
#define OT_GLYF_VARCOMPOSITEGLYPH_HH
#include "../../hb-open-type.hh"
#include "coord-setter.hh"
namespace OT {
namespace glyf_impl {
struct VarCompositeGlyphRecord
{
protected:
enum var_composite_glyph_flag_t
{
USE_MY_METRICS = 0x0001,
AXIS_INDICES_ARE_SHORT = 0x0002,
UNIFORM_SCALE = 0x0004,
HAVE_TRANSLATE_X = 0x0008,
HAVE_TRANSLATE_Y = 0x0010,
HAVE_ROTATION = 0x0020,
HAVE_SCALE_X = 0x0040,
HAVE_SCALE_Y = 0x0080,
HAVE_SKEW_X = 0x0100,
HAVE_SKEW_Y = 0x0200,
HAVE_TCENTER_X = 0x0400,
HAVE_TCENTER_Y = 0x0800,
GID_IS_24BIT = 0x1000,
AXES_HAVE_VARIATION = 0x2000,
RESET_UNSPECIFIED_AXES = 0x4000,
};
public:
unsigned int get_size () const
{
unsigned int size = min_size;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
size += numAxes * axis_width;
// gid
size += 2;
if (flags & GID_IS_24BIT) size += 1;
if (flags & HAVE_TRANSLATE_X) size += 2;
if (flags & HAVE_TRANSLATE_Y) size += 2;
if (flags & HAVE_ROTATION) size += 2;
if (flags & HAVE_SCALE_X) size += 2;
if (flags & HAVE_SCALE_Y) size += 2;
if (flags & HAVE_SKEW_X) size += 2;
if (flags & HAVE_SKEW_Y) size += 2;
if (flags & HAVE_TCENTER_X) size += 2;
if (flags & HAVE_TCENTER_Y) size += 2;
return size;
}
bool has_more () const { return true; }
bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; }
hb_codepoint_t get_gid () const
{
if (flags & GID_IS_24BIT)
return StructAfter<const HBGlyphID24> (numAxes);
else
return StructAfter<const HBGlyphID16> (numAxes);
}
void set_gid (hb_codepoint_t gid)
{
if (flags & GID_IS_24BIT)
StructAfter<HBGlyphID24> (numAxes) = gid;
else
StructAfter<HBGlyphID16> (numAxes) = gid;
}
unsigned get_numAxes () const
{
return numAxes;
}
unsigned get_num_points () const
{
unsigned num = 0;
if (flags & AXES_HAVE_VARIATION) num += numAxes;
if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
if (flags & HAVE_ROTATION) num++;
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
return num;
}
void transform_points (hb_array_t<contour_point_t> record_points,
contour_point_vector_t &points) const
{
float matrix[4];
contour_point_t trans;
get_transformation_from_points (record_points, matrix, trans);
points.transform (matrix);
points.translate (trans);
}
static inline void transform (float (&matrix)[4], contour_point_t &trans,
float (other)[6])
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268
float xx1 = other[0];
float xy1 = other[1];
float yx1 = other[2];
float yy1 = other[3];
float dx1 = other[4];
float dy1 = other[5];
float xx2 = matrix[0];
float xy2 = matrix[1];
float yx2 = matrix[2];
float yy2 = matrix[3];
float dx2 = trans.x;
float dy2 = trans.y;
matrix[0] = xx1*xx2 + xy1*yx2;
matrix[1] = xx1*xy2 + xy1*yy2;
matrix[2] = yx1*xx2 + yy1*yx2;
matrix[3] = yx1*xy2 + yy1*yy2;
trans.x = xx2*dx1 + yx2*dy1 + dx2;
trans.y = xy2*dx1 + yy2*dy1 + dy2;
}
static void translate (float (&matrix)[4], contour_point_t &trans,
float translateX, float translateY)
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213
float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY};
transform (matrix, trans, other);
}
static void scale (float (&matrix)[4], contour_point_t &trans,
float scaleX, float scaleY)
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224
float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f};
transform (matrix, trans, other);
}
static void rotate (float (&matrix)[4], contour_point_t &trans,
float rotation)
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
rotation = rotation * HB_PI;
float c = cosf (rotation);
float s = sinf (rotation);
float other[6] = {c, s, -s, c, 0.f, 0.f};
transform (matrix, trans, other);
}
static void skew (float (&matrix)[4], contour_point_t &trans,
float skewX, float skewY)
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
skewX = skewX * HB_PI;
skewY = skewY * HB_PI;
float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f};
transform (matrix, trans, other);
}
bool get_points (contour_point_vector_t &points) const
{
float translateX = 0.f;
float translateY = 0.f;
float rotation = 0.f;
float scaleX = 1.f * (1 << 10);
float scaleY = 1.f * (1 << 10);
float skewX = 0.f;
float skewY = 0.f;
float tCenterX = 0.f;
float tCenterY = 0.f;
if (unlikely (!points.resize (points.length + get_num_points ()))) return false;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
unsigned axes_size = numAxes * axis_width;
const F2DOT14 *q = (const F2DOT14 *) (axes_size +
(flags & GID_IS_24BIT ? 3 : 2) +
&StructAfter<const HBUINT8> (numAxes));
hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ());
unsigned count = numAxes;
if (flags & AXES_HAVE_VARIATION)
{
for (unsigned i = 0; i < count; i++)
rec_points[i].x = q++->to_int ();
rec_points += count;
}
else
q += count;
const HBUINT16 *p = (const HBUINT16 *) q;
if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++;
if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++;
if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int ();
if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int ();
if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int ();
if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++;
if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++;
if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y))
scaleY = scaleX;
if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
rec_points[0].x = translateX;
rec_points[0].y = translateY;
rec_points++;
}
if (flags & HAVE_ROTATION)
{
rec_points[0].x = rotation;
rec_points++;
}
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
rec_points[0].x = scaleX;
rec_points[0].y = scaleY;
rec_points++;
}
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
rec_points[0].x = skewX;
rec_points[0].y = skewY;
rec_points++;
}
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
rec_points[0].x = tCenterX;
rec_points[0].y = tCenterY;
rec_points++;
}
assert (!rec_points);
return true;
}
void get_transformation_from_points (hb_array_t<contour_point_t> rec_points,
float (&matrix)[4], contour_point_t &trans) const
{
if (flags & AXES_HAVE_VARIATION)
rec_points += numAxes;
matrix[0] = matrix[3] = 1.f;
matrix[1] = matrix[2] = 0.f;
trans.init (0.f, 0.f);
float translateX = 0.f;
float translateY = 0.f;
float rotation = 0.f;
float scaleX = 1.f;
float scaleY = 1.f;
float skewX = 0.f;
float skewY = 0.f;
float tCenterX = 0.f;
float tCenterY = 0.f;
if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
translateX = rec_points[0].x;
translateY = rec_points[0].y;
rec_points++;
}
if (flags & HAVE_ROTATION)
{
rotation = rec_points[0].x / (1 << 12);
rec_points++;
}
if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
scaleX = rec_points[0].x / (1 << 10);
scaleY = rec_points[0].y / (1 << 10);
rec_points++;
}
if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
skewX = rec_points[0].x / (1 << 12);
skewY = rec_points[0].y / (1 << 12);
rec_points++;
}
if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
tCenterX = rec_points[0].x;
tCenterY = rec_points[0].y;
rec_points++;
}
assert (!rec_points);
translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
rotate (matrix, trans, rotation);
scale (matrix, trans, scaleX, scaleY);
skew (matrix, trans, -skewX, skewY);
translate (matrix, trans, -tCenterX, -tCenterY);
}
void set_variations (coord_setter_t &setter,
hb_array_t<contour_point_t> rec_points) const
{
bool have_variations = flags & AXES_HAVE_VARIATION;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes)));
unsigned count = numAxes;
for (unsigned i = 0; i < count; i++)
{
unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
signed v = have_variations ? rec_points[i].x : a++->to_int ();
v = hb_clamp (v, -(1<<14), (1<<14));
setter[axis_index] = v;
}
}
protected:
HBUINT16 flags;
HBUINT8 numAxes;
public:
DEFINE_SIZE_MIN (3);
};
using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
struct VarCompositeGlyph
{
const GlyphHeader &header;
hb_bytes_t bytes;
VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
header (header_), bytes (bytes_) {}
var_composite_iter_t iter () const
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
const hb_bytes_t trim_padding () const
{
unsigned length = GlyphHeader::static_size;
for (auto &comp : iter ())
length += comp.get_size ();
return bytes.sub_array (0, length);
}
};
} /* namespace glyf_impl */
} /* namespace OT */
#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */

View File

@ -1,68 +0,0 @@
#ifndef OT_GLYF_COMPOSITE_ITER_HH
#define OT_GLYF_COMPOSITE_ITER_HH
#include "../../hb.hh"
namespace OT {
namespace glyf_impl {
template <typename CompositeGlyphRecord>
struct composite_iter_tmpl : hb_iter_with_fallback_t<composite_iter_tmpl<CompositeGlyphRecord>,
const CompositeGlyphRecord &>
{
typedef const CompositeGlyphRecord *__item_t__;
composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) :
glyph (glyph_), current (nullptr), current_size (0)
{
set_current (current_);
}
composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
const CompositeGlyphRecord & __item__ () const { return *current; }
bool __more__ () const { return current; }
void __next__ ()
{
if (!current->has_more ()) { current = nullptr; return; }
set_current (&StructAtOffset<CompositeGlyphRecord> (current, current_size));
}
composite_iter_tmpl __end__ () const { return composite_iter_tmpl (); }
bool operator != (const composite_iter_tmpl& o) const
{ return current != o.current; }
void set_current (__item_t__ current_)
{
if (!glyph.check_range (current_, CompositeGlyphRecord::min_size))
{
current = nullptr;
current_size = 0;
return;
}
unsigned size = current_->get_size ();
if (!glyph.check_range (current_, size))
{
current = nullptr;
current_size = 0;
return;
}
current = current_;
current_size = size;
}
private:
hb_bytes_t glyph;
__item_t__ current;
unsigned current_size;
};
} /* namespace glyf_impl */
} /* namespace OT */
#endif /* OT_GLYF_COMPOSITE_ITER_HH */

View File

@ -1,34 +0,0 @@
#ifndef OT_GLYF_COORD_SETTER_HH
#define OT_GLYF_COORD_SETTER_HH
#include "../../hb.hh"
namespace OT {
namespace glyf_impl {
struct coord_setter_t
{
coord_setter_t (hb_array_t<int> coords) :
coords (coords) {}
int& operator [] (unsigned idx)
{
if (coords.length < idx + 1)
coords.resize (idx + 1);
return coords[idx];
}
hb_array_t<int> get_coords ()
{ return coords.as_array (); }
hb_vector_t<int> coords;
};
} /* namespace glyf_impl */
} /* namespace OT */
#endif /* OT_GLYF_COORD_SETTER_HH */

View File

@ -16,7 +16,7 @@ template<typename IteratorIn, typename IteratorOut,
hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
static void
_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
_write_loca (IteratorIn it, bool short_offsets, IteratorOut dest)
{
unsigned right_shift = short_offsets ? 1 : 0;
unsigned int offset = 0;
@ -25,7 +25,7 @@ _write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
| hb_map ([=, &offset] (unsigned int padded_size)
{
offset += padded_size;
DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset);
DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
return offset >> right_shift;
})
| hb_sink (dest)
@ -44,20 +44,6 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
if (plan->normalized_coords)
{
head_prime->xMin = plan->head_maxp_info.xMin;
head_prime->xMax = plan->head_maxp_info.xMax;
head_prime->yMin = plan->head_maxp_info.yMin;
head_prime->yMax = plan->head_maxp_info.yMax;
unsigned orig_flag = head_prime->flags;
if (plan->head_maxp_info.allXMinIsLsb)
orig_flag |= 1 << 1;
else
orig_flag &= ~(1 << 1);
head_prime->flags = orig_flag;
}
bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
hb_blob_destroy (head_prime_blob);
@ -75,7 +61,7 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
if (unlikely (!loca_prime_data)) return false;
DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u",
DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d",
entry_size, num_offsets, entry_size * num_offsets);
if (use_short_loca)

View File

@ -7,7 +7,6 @@
#include "../../hb-ot-hmtx-table.hh"
#include "../../hb-ot-var-gvar-table.hh"
#include "../../hb-draw.hh"
#include "../../hb-paint.hh"
#include "glyf-helpers.hh"
#include "Glyph.hh"
@ -25,18 +24,13 @@ namespace OT {
*/
#define HB_OT_TAG_glyf HB_TAG('g','l','y','f')
struct glyf
{
friend struct glyf_accelerator_t;
static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
static bool has_valid_glyf_format(const hb_face_t* face)
{
const OT::head &head = *face->table.head;
return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1;
}
bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
{
TRACE_SANITIZE (this);
@ -52,11 +46,8 @@ struct glyf
const hb_subset_plan_t *plan)
{
TRACE_SERIALIZE (this);
unsigned init_len = c->length ();
for (auto &_ : it)
if (unlikely (!_.serialize (c, use_short_loca, plan)))
return false;
for (const auto &_ : it) _.serialize (c, use_short_loca, plan);
/* As a special case when all glyph in the font are empty, add a zero byte
* to the table, so that OTS doesnt reject it, and to make the table work
@ -78,83 +69,39 @@ struct glyf
{
TRACE_SUBSET (this);
if (!has_valid_glyf_format (c->plan->source)) {
// glyf format is unknown don't attempt to subset it.
DEBUG_MSG (SUBSET, nullptr,
"unkown glyf format, dropping from subset.");
return_trace (false);
}
glyf *glyf_prime = c->serializer->start_embed <glyf> ();
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
hb_font_t *font = nullptr;
if (c->plan->normalized_coords)
{
font = _create_font_for_instancing (c->plan);
if (unlikely (!font)) return false;
}
hb_vector_t<unsigned> padded_offsets;
unsigned num_glyphs = c->plan->num_output_glyphs ();
if (unlikely (!padded_offsets.resize (num_glyphs)))
{
hb_font_destroy (font);
return false;
}
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
if (!_populate_subset_glyphs (c->plan, font, glyphs))
{
hb_font_destroy (font);
return false;
}
_populate_subset_glyphs (c->plan, &glyphs);
if (font)
hb_font_destroy (font);
auto padded_offsets =
+ hb_iter (glyphs)
| hb_map (&glyf_impl::SubsetGlyph::padded_size)
;
unsigned max_offset = 0;
for (unsigned i = 0; i < num_glyphs; i++)
{
padded_offsets[i] = glyphs[i].padded_size ();
max_offset += padded_offsets[i];
}
unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
bool use_short_loca = max_offset < 0x1FFFF;
bool use_short_loca = false;
if (likely (!c->plan->force_long_loca))
use_short_loca = max_offset < 0x1FFFF;
glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
if (!use_short_loca) {
for (unsigned i = 0; i < num_glyphs; i++)
padded_offsets[i] = glyphs[i].length ();
padded_offsets =
+ hb_iter (glyphs)
| hb_map (&glyf_impl::SubsetGlyph::length)
;
}
bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
if (c->plan->normalized_coords && !c->plan->pinned_at_default)
_free_compiled_subset_glyphs (glyphs);
if (!result) return false;
if (unlikely (c->serializer->in_error ())) return_trace (false);
return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
padded_offsets.iter (),
padded_offsets,
use_short_loca)));
}
bool
void
_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
hb_font_t *
_create_font_for_instancing (const hb_subset_plan_t *plan) const;
void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const
{
for (unsigned i = 0; i < glyphs.length; i++)
glyphs[i].free_compiled_bytes ();
}
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
protected:
UnsizedArrayOf<HBUINT8>
@ -181,7 +128,7 @@ struct glyf_accelerator_t
vmtx = nullptr;
#endif
const OT::head &head = *face->table.head;
if (!glyf::has_valid_glyf_format (face))
if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
return;
short_offset = 0 == head.indexToLocFormat;
@ -219,7 +166,7 @@ struct glyf_accelerator_t
contour_point_vector_t all_points;
bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only)))
return false;
if (consumer.is_consuming_contour_points ())
@ -241,8 +188,6 @@ struct glyf_accelerator_t
return true;
}
public:
#ifndef HB_NO_VAR
struct points_aggregator_t
{
@ -275,14 +220,19 @@ struct glyf_accelerator_t
extents->y_bearing = 0;
return;
}
if (scaled)
{
extents->x_bearing = font->em_scalef_x (min_x);
extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
extents->y_bearing = font->em_scalef_y (max_y);
extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
}
else
{
extents->x_bearing = roundf (min_x);
extents->width = roundf (max_x - extents->x_bearing);
extents->y_bearing = roundf (max_y);
extents->height = roundf (min_y - extents->y_bearing);
if (scaled)
font->scale_glyph_extents (extents);
}
}
@ -306,6 +256,7 @@ struct glyf_accelerator_t
contour_point_t *get_phantoms_sink () { return phantoms; }
};
public:
unsigned
get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
{
@ -347,15 +298,6 @@ struct glyf_accelerator_t
}
#endif
bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
{
if (unlikely (gid >= num_glyphs)) return false;
if (is_vertical) return false; // TODO Humm, what to do here?
*lsb = glyph_for_gid (gid).get_header ()->xMin;
return true;
}
public:
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
{
@ -368,15 +310,6 @@ struct glyf_accelerator_t
return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
}
bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
{
funcs->push_clip_glyph (data, gid, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
return true;
}
const glyf_impl::Glyph
glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
{
@ -425,77 +358,37 @@ struct glyf_accelerator_t
};
inline bool
inline void
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
unsigned num_glyphs = plan->num_output_glyphs ();
if (!glyphs.resize (num_glyphs)) return false;
for (auto p : plan->glyph_map->iter ())
{
unsigned new_gid = p.second;
glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
subset_glyph.old_gid = p.first;
+ hb_range (plan->num_output_glyphs ())
| hb_map ([&] (hb_codepoint_t new_gid)
{
glyf_impl::SubsetGlyph subset_glyph = {0};
subset_glyph.new_gid = new_gid;
if (unlikely (new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
!plan->normalized_coords)
subset_glyph.source_glyph = glyf_impl::Glyph ();
else
{
/* If plan has an accelerator, the preprocessing step already trimmed glyphs.
* Don't trim them again! */
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator);
}
/* should never fail: all old gids should be mapped */
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
return subset_glyph;
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
subset_glyph.drop_hints_bytes ();
else
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
if (font)
{
if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
{
// when pinned at default, only bounds are updated, thus no need to free
if (!plan->pinned_at_default)
_free_compiled_subset_glyphs (glyphs);
return false;
}
}
}
return true;
if (new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
subset_glyph.source_glyph = glyf_impl::Glyph ();
else
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
subset_glyph.drop_hints_bytes ();
else
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
return subset_glyph;
})
| hb_sink (glyphs)
;
}
inline hb_font_t *
glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
{
hb_font_t *font = hb_font_create (plan->source);
if (unlikely (font == hb_font_get_empty ())) return nullptr;
hb_vector_t<hb_variation_t> vars;
if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
{
hb_font_destroy (font);
return nullptr;
}
for (auto _ : plan->user_axes_location)
{
hb_variation_t var;
var.tag = _.first;
var.value = _.second;
vars.push (var);
}
#ifndef HB_NO_VAR
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
#endif
return font;
}
} /* namespace OT */

View File

@ -26,29 +26,22 @@ struct path_builder_t
optional_point_t lerp (optional_point_t p, float t)
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
} first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
} first_oncurve, first_offcurve, last_offcurve;
path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
{
font = font_;
draw_session = &draw_session_;
first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t ();
first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
}
/* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
See also:
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
* https://stackoverflow.com/a/20772557
*
* Cubic support added. */
* https://stackoverflow.com/a/20772557 */
void consume_point (const contour_point_t &point)
{
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
#ifdef HB_NO_CUBIC_GLYF
bool is_cubic = false;
#else
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif
optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
if (!first_oncurve)
{
@ -59,12 +52,7 @@ struct path_builder_t
}
else
{
if (is_cubic && !first_offcurve2)
{
first_offcurve2 = first_offcurve;
first_offcurve = p;
}
else if (first_offcurve)
if (first_offcurve)
{
optional_point_t mid = first_offcurve.lerp (p, .5f);
first_oncurve = mid;
@ -81,41 +69,16 @@ struct path_builder_t
{
if (is_on_curve)
{
if (last_offcurve2)
{
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
p.x, p.y);
last_offcurve2 = optional_point_t ();
}
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
p.x, p.y);
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
p.x, p.y);
last_offcurve = optional_point_t ();
}
else
{
if (is_cubic && !last_offcurve2)
{
last_offcurve2 = last_offcurve;
last_offcurve = p;
}
else
{
optional_point_t mid = last_offcurve.lerp (p, .5f);
if (is_cubic)
{
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve2 = optional_point_t ();
}
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = p;
}
optional_point_t mid = last_offcurve.lerp (p, .5f);
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = p;
}
}
else
@ -131,40 +94,19 @@ struct path_builder_t
{
if (first_offcurve && last_offcurve)
{
optional_point_t mid = last_offcurve.lerp (first_offcurve2 ?
first_offcurve2 :
first_offcurve, .5f);
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
mid.x, mid.y);
last_offcurve = optional_point_t ();
/* now check the rest */
}
/* now check the rest */
if (first_offcurve && first_oncurve)
{
if (first_offcurve2)
draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
first_oncurve.x, first_oncurve.y);
else if (last_offcurve && first_oncurve)
{
if (last_offcurve2)
draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
else
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
}
draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
first_oncurve.x, first_oncurve.y);
else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve)
@ -175,7 +117,7 @@ struct path_builder_t
}
/* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
draw_session->close_path ();
}
}

View File

@ -1,589 +0,0 @@
/*
* Copyright © 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.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef OT_NAME_NAME_HH
#define OT_NAME_NAME_HH
#include "../../hb-open-type.hh"
#include "../../hb-ot-name-language.hh"
#include "../../hb-aat-layout.hh"
#include "../../hb-utf.hh"
namespace OT {
template <typename in_utf_t, typename out_utf_t>
inline unsigned int
hb_ot_name_convert_utf (hb_bytes_t bytes,
unsigned int *text_size /* IN/OUT */,
typename out_utf_t::codepoint_t *text /* OUT */)
{
unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
const typename in_utf_t::codepoint_t *src_end = src + src_len;
typename out_utf_t::codepoint_t *dst = text;
hb_codepoint_t unicode;
const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
if (text_size && *text_size)
{
(*text_size)--; /* Save room for NUL-termination. */
const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
while (src < src_end && dst < dst_end)
{
const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
if (dst_next == dst)
break; /* Out-of-room. */
dst = dst_next;
src = src_next;
}
*text_size = dst - text;
*dst = 0; /* NUL-terminate. */
}
/* Accumulate length of rest. */
unsigned int dst_len = dst - text;
while (src < src_end)
{
src = in_utf_t::next (src, src_end, &unicode, replacement);
dst_len += out_utf_t::encode_len (unicode);
}
return dst_len;
}
#define entry_score var.u16[0]
#define entry_index var.u16[1]
/*
* name -- Naming
* https://docs.microsoft.com/en-us/typography/opentype/spec/name
*/
#define HB_OT_TAG_name HB_TAG('n','a','m','e')
#define UNSUPPORTED 42
struct NameRecord
{
hb_language_t language (hb_face_t *face) const
{
#ifndef HB_NO_OT_NAME_LANGUAGE
unsigned int p = platformID;
unsigned int l = languageID;
if (p == 3)
return _hb_ot_name_language_for_ms_code (l);
if (p == 1)
return _hb_ot_name_language_for_mac_code (l);
#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
if (p == 0)
return face->table.ltag->get_language (l);
#endif
#endif
return HB_LANGUAGE_INVALID;
}
uint16_t score () const
{
/* Same order as in cmap::find_best_subtable(). */
unsigned int p = platformID;
unsigned int e = encodingID;
/* 32-bit. */
if (p == 3 && e == 10) return 0;
if (p == 0 && e == 6) return 1;
if (p == 0 && e == 4) return 2;
/* 16-bit. */
if (p == 3 && e == 1) return 3;
if (p == 0 && e == 3) return 4;
if (p == 0 && e == 2) return 5;
if (p == 0 && e == 1) return 6;
if (p == 0 && e == 0) return 7;
/* Symbol. */
if (p == 3 && e == 0) return 8;
/* We treat all Mac Latin names as ASCII only. */
if (p == 1 && e == 0) return 10; /* 10 is magic number :| */
return UNSUPPORTED;
}
NameRecord* copy (hb_serialize_context_t *c, const void *base
#ifdef HB_EXPERIMENTAL_API
, const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
#endif
) const
{
TRACE_SERIALIZE (this);
HB_UNUSED auto snap = c->snapshot ();
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
#ifdef HB_EXPERIMENTAL_API
hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID);
hb_bytes_t* name_bytes;
if (name_table_overrides->has (record_ids, &name_bytes)) {
hb_bytes_t encoded_bytes = *name_bytes;
char *name_str_utf16_be = nullptr;
if (platformID != 1)
{
unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
if (!name_str_utf16_be)
{
c->revert (snap);
return_trace (nullptr);
}
hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
(hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
c->revert (snap);
hb_free (name_str_utf16_be);
return_trace (nullptr);
}
encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
}
else
{
// mac platform, copy the UTF-8 string(all ascii characters) as is
if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
c->revert (snap);
return_trace (nullptr);
}
}
out->offset = 0;
c->push ();
encoded_bytes.copy (c);
c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0);
hb_free (name_str_utf16_be);
}
else
#endif
{
out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
}
return_trace (out);
}
bool isUnicode () const
{
unsigned int p = platformID;
unsigned int e = encodingID;
return (p == 0 ||
(p == 3 && (e == 0 || e == 1 || e == 10)));
}
static int cmp (const void *pa, const void *pb)
{
const NameRecord *a = (const NameRecord *)pa;
const NameRecord *b = (const NameRecord *)pb;
if (a->platformID != b->platformID)
return a->platformID - b->platformID;
if (a->encodingID != b->encodingID)
return a->encodingID - b->encodingID;
if (a->languageID != b->languageID)
return a->languageID - b->languageID;
if (a->nameID != b->nameID)
return a->nameID - b->nameID;
if (a->length != b->length)
return a->length - b->length;
return 0;
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
}
HBUINT16 platformID; /* Platform ID. */
HBUINT16 encodingID; /* Platform-specific encoding ID. */
HBUINT16 languageID; /* Language ID. */
HBUINT16 nameID; /* Name ID. */
HBUINT16 length; /* String length (in bytes). */
NNOffset16To<UnsizedArrayOf<HBUINT8>>
offset; /* String offset from start of storage area (in bytes). */
public:
DEFINE_SIZE_STATIC (12);
};
static int
_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact)
{
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
/* Compare by name_id, then language. */
if (a->name_id != b->name_id)
return a->name_id - b->name_id;
if (a->language == b->language) return 0;
if (!a->language) return -1;
if (!b->language) return +1;
const char *astr = hb_language_to_string (a->language);
const char *bstr = hb_language_to_string (b->language);
signed c = strcmp (astr, bstr);
// 'a' is the user request, and 'b' is string in the font.
// If eg. user asks for "en-us" and font has "en", approve.
if (!exact && c &&
hb_language_matches (b->language, a->language))
return 0;
return c;
}
static int
_hb_ot_name_entry_cmp (const void *pa, const void *pb)
{
/* Compare by name_id, then language, then score, then index. */
int v = _hb_ot_name_entry_cmp_key (pa, pb, true);
if (v)
return v;
const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
if (a->entry_score != b->entry_score)
return a->entry_score - b->entry_score;
if (a->entry_index != b->entry_index)
return a->entry_index - b->entry_index;
return 0;
}
struct name
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
unsigned int get_size () const
{ return min_size + count * nameRecordZ.item_size; }
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
bool serialize (hb_serialize_context_t *c,
Iterator it,
const void *src_string_pool
#ifdef HB_EXPERIMENTAL_API
, const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records
, const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
#endif
)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
unsigned total_count = it.len ()
#ifdef HB_EXPERIMENTAL_API
+ insert_name_records.length
#endif
;
this->format = 0;
if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return false;
NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size);
if (unlikely (!name_records)) return_trace (false);
hb_array_t<NameRecord> records (name_records, total_count);
for (const NameRecord& record : it)
{
hb_memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
#ifdef HB_EXPERIMENTAL_API
for (unsigned i = 0; i < insert_name_records.length; i++)
{
const hb_ot_name_record_ids_t& ids = insert_name_records[i];
NameRecord record;
record.platformID = ids.platform_id;
record.encodingID = ids.encoding_id;
record.languageID = ids.language_id;
record.nameID = ids.name_id;
record.length = 0; // handled in NameRecord copy()
record.offset = 0;
memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
#endif
records.qsort ();
c->copy_all (records,
src_string_pool
#ifdef HB_EXPERIMENTAL_API
, name_table_overrides
#endif
);
hb_free (records.arrayZ);
if (unlikely (c->ran_out_of_room ())) return_trace (false);
this->stringOffset = c->length ();
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
name *name_prime = c->serializer->start_embed<name> ();
if (unlikely (!name_prime)) return_trace (false);
#ifdef HB_EXPERIMENTAL_API
const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
&c->plan->name_table_overrides;
#endif
auto it =
+ nameRecordZ.as_array (count)
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
| hb_filter (c->plan->name_languages, &NameRecord::languageID)
| hb_filter ([&] (const NameRecord& namerecord) {
return
(c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
|| namerecord.isUnicode ();
})
#ifdef HB_EXPERIMENTAL_API
| hb_filter ([&] (const NameRecord& namerecord) {
if (name_table_overrides->is_empty ())
return true;
hb_ot_name_record_ids_t rec_ids (namerecord.platformID,
namerecord.encodingID,
namerecord.languageID,
namerecord.nameID);
hb_bytes_t *p;
if (name_table_overrides->has (rec_ids, &p) &&
(*p).length == 0)
return false;
return true;
})
#endif
;
#ifdef HB_EXPERIMENTAL_API
hb_hashmap_t<hb_ot_name_record_ids_t, unsigned> retained_name_record_ids;
for (const NameRecord& rec : it)
{
hb_ot_name_record_ids_t rec_ids (rec.platformID,
rec.encodingID,
rec.languageID,
rec.nameID);
retained_name_record_ids.set (rec_ids, 1);
}
hb_vector_t<hb_ot_name_record_ids_t> insert_name_records;
if (!name_table_overrides->is_empty ())
{
if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
return_trace (false);
for (const auto& record_ids : name_table_overrides->keys ())
{
if (name_table_overrides->get (record_ids).length == 0)
continue;
if (retained_name_record_ids.has (record_ids))
continue;
insert_name_records.push (record_ids);
}
}
#endif
return (name_prime->serialize (c->serializer, it,
std::addressof (this + stringOffset)
#ifdef HB_EXPERIMENTAL_API
, insert_name_records
, name_table_overrides
#endif
));
}
bool sanitize_records (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
const void *string_pool = (this+stringOffset).arrayZ;
return_trace (nameRecordZ.sanitize (c, count, string_pool));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (format == 0 || format == 1) &&
c->check_array (nameRecordZ.arrayZ, count) &&
c->check_range (this, stringOffset) &&
sanitize_records (c));
}
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<name> (face);
assert (this->table.get_length () >= this->table->stringOffset);
this->pool = (const char *) (const void *) (this->table+this->table->stringOffset);
this->pool_len = this->table.get_length () - this->table->stringOffset;
const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
this->table->count);
this->names.alloc (all_names.length, true);
for (unsigned int i = 0; i < all_names.length; i++)
{
hb_ot_name_entry_t *entry = this->names.push ();
entry->name_id = all_names[i].nameID;
entry->language = all_names[i].language (face);
entry->entry_score = all_names[i].score ();
entry->entry_index = i;
}
this->names.qsort (_hb_ot_name_entry_cmp);
/* Walk and pick best only for each name_id,language pair,
* while dropping unsupported encodings. */
unsigned int j = 0;
for (unsigned int i = 0; i < this->names.length; i++)
{
if (this->names[i].entry_score == UNSUPPORTED ||
this->names[i].language == HB_LANGUAGE_INVALID)
continue;
if (i &&
this->names[i - 1].name_id == this->names[i].name_id &&
this->names[i - 1].language == this->names[i].language)
continue;
this->names[j++] = this->names[i];
}
this->names.resize (j);
}
~accelerator_t ()
{
this->table.destroy ();
}
int get_index (hb_ot_name_id_t name_id,
hb_language_t language,
unsigned int *width=nullptr) const
{
const hb_ot_name_entry_t key = {name_id, {0}, language};
const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
this->names.length,
sizeof (hb_ot_name_entry_t),
_hb_ot_name_entry_cmp_key,
true);
if (!entry)
{
entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
this->names.length,
sizeof (hb_ot_name_entry_t),
_hb_ot_name_entry_cmp_key,
false);
}
if (!entry)
return -1;
if (width)
*width = entry->entry_score < 10 ? 2 : 1;
return entry->entry_index;
}
hb_bytes_t get_name (unsigned int idx) const
{
const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count);
const NameRecord &record = all_names[idx];
const hb_bytes_t string_pool (pool, pool_len);
return string_pool.sub_array (record.offset, record.length);
}
private:
const char *pool;
unsigned int pool_len;
public:
hb_blob_ptr_t<name> table;
hb_vector_t<hb_ot_name_entry_t> names;
};
public:
/* We only implement format 0 for now. */
HBUINT16 format; /* Format selector (=0/1). */
HBUINT16 count; /* Number of name records. */
NNOffset16To<UnsizedArrayOf<HBUINT8>>
stringOffset; /* Offset to start of string storage (from start of table). */
UnsizedArrayOf<NameRecord>
nameRecordZ; /* The name records where count is the number of records. */
public:
DEFINE_SIZE_ARRAY (6, nameRecordZ);
};
#undef entry_index
#undef entry_score
struct name_accelerator_t : name::accelerator_t {
name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {}
};
} /* namespace OT */
#endif /* OT_NAME_NAME_HH */

View File

@ -19,7 +19,7 @@ stat = 0
tested = False
# harfbuzz-icu links to libstdc++ because icu does.
for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject', 'harfbuzz-cairo']:
for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']:
for suffix in ['so', 'dylib']:
so = os.path.join (libs, 'lib%s.%s' % (soname, suffix))
if not os.path.exists (so): continue

View File

@ -22,7 +22,7 @@ cxxfilt = shutil.which ('c++filt')
tested = False
stat = 0
for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']:
for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']:
for suffix in ['so', 'dylib']:
so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
if not os.path.exists (so): continue
@ -31,7 +31,7 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
symprefix = '_' if suffix == 'dylib' else ''
EXPORTED_SYMBOLS = [s.split ()[2]
for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
# run again c++filt also if is available

View File

@ -19,10 +19,7 @@ symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re
if '--experimental-api' not in sys.argv:
# Move these to harfbuzz-sections.txt when got stable
experimental_symbols = \
"""hb_shape_justify
hb_subset_repack_or_fail
hb_subset_input_override_name_table
""".splitlines ()
"""hb_subset_repack_or_fail""".splitlines ()
symbols = [x for x in symbols if x not in experimental_symbols]
symbols = "\n".join (symbols)

View File

@ -65,7 +65,7 @@ for typ, s in ranges.items():
for i in range(start, end + 1):
arr[i] = 1
sol = packTab.pack_table(arr, 0, compression=9)
sol = packTab.pack_table(arr, 0, compression=3)
code = packTab.Code('_hb_emoji')
sol.genCode(code, 'is_'+typ)
code.print_c(linkage='static inline')
@ -91,8 +91,8 @@ with open(sys.argv[2]) as f:
continue
sequences.append(line)
with open("../test/shape/data/in-house/tests/emoji-clusters.tests", "w") as f:
with open("../test/shaping/data/in-house/tests/emoji-clusters.tests", "w") as f:
for sequence in sequences:
f.write("../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot")
f.write(";" + ",".join(sequence))
f.write(";[" + "|".join("1=0" for c in sequence) + "]\n")
f.write("../fonts/AdobeBlank2.ttf:--no-glyph-names --no-positions --font-funcs=ot")
f.write(":" + ",".join(sequence))
f.write(":[" + "|".join("1=0" for c in sequence) + "]\n")

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