Compare commits
19 Commits
main
...
extension_
Author | SHA1 | Date |
---|---|---|
Garret Rieger | f2b9065246 | |
Garret Rieger | e4fd5ff727 | |
Garret Rieger | 0a5b69b255 | |
Garret Rieger | fa177b7f33 | |
Garret Rieger | 156105b0f0 | |
Garret Rieger | e6dda54c88 | |
Garret Rieger | ffb0f7936f | |
Garret Rieger | 7ebc92f2e0 | |
Garret Rieger | 8c6afa69d5 | |
Garret Rieger | 514fcea0aa | |
Garret Rieger | 2f63f0c861 | |
Garret Rieger | a8887b2740 | |
Garret Rieger | ede7b74584 | |
Garret Rieger | c61c05e431 | |
Garret Rieger | f2a0e69162 | |
Garret Rieger | d520a6d522 | |
Garret Rieger | 5babfda3f2 | |
Garret Rieger | c20b85cfed | |
Garret Rieger | d9295d88a7 |
|
@ -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 \
|
||||
$@
|
||||
|
||||
|
|
|
@ -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 \
|
||||
$@
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
comment: false
|
||||
comment: off
|
||||
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
informational: true
|
||||
patch:
|
||||
default:
|
||||
informational: true
|
||||
threshold: 1%
|
||||
patch: off
|
||||
|
|
|
@ -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
|
|
@ -1,9 +1,5 @@
|
|||
name: CIFuzz
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
Fuzzing:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
@ -11,7 +11,7 @@ permissions:
|
|||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
29
BUILD.md
29
BUILD.md
|
@ -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.
|
||||
|
|
|
@ -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
20
COPYING
|
@ -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
318
NEWS
|
@ -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
|
||||
====================================
|
||||
- Don’t 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_Face’s 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
|
||||
====================================
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
20
SECURITY.md
20
SECURITY.md
|
@ -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.
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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%
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
115
meson.build
115
meson.build
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
10000
perf/texts/fa-words.txt
10000
perf/texts/fa-words.txt
File diff suppressed because it is too large
Load Diff
10000
perf/texts/hi-words.txt
10000
perf/texts/hi-words.txt
File diff suppressed because it is too large
Load Diff
102
src/Makefile.am
102
src/Makefile.am
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
;
|
||||
}
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ());
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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]); })
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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)
|
||||
|
|
|
@ -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 doesn’t 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 */
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue