Compare commits

..

No commits in common. "main" and "10.0.1" have entirely different histories.
main ... 10.0.1

1138 changed files with 13248 additions and 64865 deletions

View file

@ -1,48 +0,0 @@
#!/bin/bash
set -ex
if [ "$#" -lt 1 ]
then
echo "Usage $0 ARCH (ARCH can be 32 or 64)"
exit 1
fi
ARCH=$1
shift
BUILD=build-win${ARCH}
INSTALL=install-win${ARCH}
DIST=harfbuzz-win${ARCH}
meson setup \
--buildtype=release \
--prefix="${PWD}/${BUILD}/${INSTALL}" \
--cross-file=.ci/win${ARCH}-cross-file.txt \
--wrap-mode=default \
--strip \
-Dtests=enabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dlibffi:tests=false \
-Dfreetype=disabled \
-Dicu=disabled \
-Dchafa=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
${BUILD} \
"$@"
# building with all the cores won't work fine with CricleCI for some reason
meson compile -C ${BUILD} -j3
meson install -C ${BUILD}
mkdir ${BUILD}/${DIST}
cp ${BUILD}/${INSTALL}/bin/hb-*.exe ${BUILD}/${DIST}
cp ${BUILD}/${INSTALL}/bin/*.dll ${BUILD}/${DIST}
rm -f ${DIST}.zip
(cd ${BUILD} && zip -r ../${DIST}.zip ${DIST})
echo "${DIST}.zip is ready."

28
.ci/build-win32.sh Executable file
View file

@ -0,0 +1,28 @@
#!/bin/bash
set -e
meson --cross-file=.ci/win32-cross-file.txt \
--wrap-mode=default \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
win32build \
$@
ninja -Cwin32build -j3 # building with all the cores won't work fine with CricleCI for some reason
rm -rf win32build/harfbuzz-win32
mkdir win32build/harfbuzz-win32
cp win32build/util/hb-*.exe win32build/harfbuzz-win32
find win32build -name '*.dll' -exec cp {} win32build/harfbuzz-win32 \;
i686-w64-mingw32-strip win32build/harfbuzz-win32/*.{dll,exe}
rm -f harfbuzz-win32.zip
(cd win32build && zip -r ../harfbuzz-win32.zip harfbuzz-win32)
echo "harfbuzz-win32.zip is ready."

28
.ci/build-win64.sh Normal file
View file

@ -0,0 +1,28 @@
#!/bin/bash
set -e
meson --cross-file=.ci/win64-cross-file.txt \
--wrap-mode=default \
-Dtests=disabled \
-Dcairo=enabled \
-Dcairo:fontconfig=disabled \
-Dcairo:freetype=disabled \
-Dcairo:dwrite=disabled \
-Dcairo:tests=disabled \
-Dglib=enabled \
-Dfreetype=disabled \
-Dgdi=enabled \
-Ddirectwrite=enabled \
win64build \
$@
ninja -Cwin64build -j3 # building with all the cores won't work fine with CricleCI for some reason
rm -rf win64build/harfbuzz-win64
mkdir win64build/harfbuzz-win64
cp win64build/util/hb-*.exe win64build/harfbuzz-win64
find win64build -name '*.dll' -exec cp {} win64build/harfbuzz-win64 \;
x86_64-w64-mingw32-strip win64build/harfbuzz-win64/*.{dll,exe}
rm -f harfbuzz-win64.zip
(cd win64build && zip -r ../harfbuzz-win64.zip harfbuzz-win64)
echo "harfbuzz-win64.zip is ready."

View file

@ -11,11 +11,12 @@ fi
if ! hash ghr 2> /dev/null; then
_GHR_VER=v0.14.0
_GHR=ghr_${_GHR_VER}_linux_amd64
mkdir -p $HOME/.local/bin
curl -sfL https://github.com/tcnksm/ghr/releases/download/$_GHR_VER/$_GHR.tar.gz |
tar xz -C . --strip-components=1 $_GHR/ghr
tar xz -C $HOME/.local/bin --strip-components=1 $_GHR/ghr
fi
./ghr -replace \
ghr -replace \
-u $CIRCLE_PROJECT_USERNAME \
-r $CIRCLE_PROJECT_REPONAME \
$CIRCLE_TAG \

View file

@ -4,55 +4,47 @@
#
# pip-compile --generate-hashes .ci/requirements-fonttools.in
#
fonttools==4.57.0 \
--hash=sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e \
--hash=sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92 \
--hash=sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1 \
--hash=sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d \
--hash=sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f \
--hash=sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab \
--hash=sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4 \
--hash=sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746 \
--hash=sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd \
--hash=sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef \
--hash=sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888 \
--hash=sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f \
--hash=sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817 \
--hash=sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6 \
--hash=sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654 \
--hash=sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc \
--hash=sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9 \
--hash=sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1 \
--hash=sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595 \
--hash=sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de \
--hash=sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3 \
--hash=sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13 \
--hash=sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db \
--hash=sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02 \
--hash=sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6 \
--hash=sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8 \
--hash=sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31 \
--hash=sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199 \
--hash=sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683 \
--hash=sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344 \
--hash=sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213 \
--hash=sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8 \
--hash=sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9 \
--hash=sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c \
--hash=sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c \
--hash=sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41 \
--hash=sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c \
--hash=sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8 \
--hash=sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36 \
--hash=sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec \
--hash=sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9 \
--hash=sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481 \
--hash=sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f \
--hash=sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9 \
--hash=sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9 \
--hash=sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98 \
--hash=sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72 \
--hash=sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e \
--hash=sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3 \
--hash=sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac
fonttools==4.53.1 \
--hash=sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122 \
--hash=sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397 \
--hash=sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f \
--hash=sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d \
--hash=sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60 \
--hash=sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169 \
--hash=sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8 \
--hash=sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31 \
--hash=sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923 \
--hash=sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2 \
--hash=sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb \
--hash=sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab \
--hash=sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb \
--hash=sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a \
--hash=sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670 \
--hash=sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8 \
--hash=sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407 \
--hash=sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671 \
--hash=sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88 \
--hash=sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f \
--hash=sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f \
--hash=sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0 \
--hash=sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb \
--hash=sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2 \
--hash=sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d \
--hash=sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c \
--hash=sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3 \
--hash=sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719 \
--hash=sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749 \
--hash=sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4 \
--hash=sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f \
--hash=sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02 \
--hash=sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58 \
--hash=sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1 \
--hash=sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41 \
--hash=sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4 \
--hash=sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb \
--hash=sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb \
--hash=sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3 \
--hash=sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d \
--hash=sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d \
--hash=sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2
# via -r requirements-fonttools.in

View file

@ -1,4 +1,5 @@
-r requirements-fonttools.in
meson==1.7.0
meson==1.5.2
gcovr==5.0
ninja
setuptools # https://github.com/harfbuzz/harfbuzz/issues/4475

View file

@ -4,84 +4,242 @@
#
# pip-compile --allow-unsafe --generate-hashes --output-file=.ci/requirements.txt .ci/requirements.in
#
fonttools==4.57.0 \
--hash=sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e \
--hash=sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92 \
--hash=sha256:05efceb2cb5f6ec92a4180fcb7a64aa8d3385fd49cfbbe459350229d1974f0b1 \
--hash=sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d \
--hash=sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f \
--hash=sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab \
--hash=sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4 \
--hash=sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746 \
--hash=sha256:3cf97236b192a50a4bf200dc5ba405aa78d4f537a2c6e4c624bb60466d5b03bd \
--hash=sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef \
--hash=sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888 \
--hash=sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f \
--hash=sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817 \
--hash=sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6 \
--hash=sha256:541cb48191a19ceb1a2a4b90c1fcebd22a1ff7491010d3cf840dd3a68aebd654 \
--hash=sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc \
--hash=sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9 \
--hash=sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1 \
--hash=sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595 \
--hash=sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de \
--hash=sha256:7339e6a3283e4b0ade99cade51e97cde3d54cd6d1c3744459e886b66d630c8b3 \
--hash=sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13 \
--hash=sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db \
--hash=sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02 \
--hash=sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6 \
--hash=sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8 \
--hash=sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31 \
--hash=sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199 \
--hash=sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683 \
--hash=sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344 \
--hash=sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213 \
--hash=sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8 \
--hash=sha256:a2a722c0e4bfd9966a11ff55c895c817158fcce1b2b6700205a376403b546ad9 \
--hash=sha256:a97bb05eb24637714a04dee85bdf0ad1941df64fe3b802ee4ac1c284a5f97b7c \
--hash=sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c \
--hash=sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41 \
--hash=sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c \
--hash=sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8 \
--hash=sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36 \
--hash=sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec \
--hash=sha256:cdef9a056c222d0479a1fdb721430f9efd68268014c54e8166133d2643cb05d9 \
--hash=sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481 \
--hash=sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f \
--hash=sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9 \
--hash=sha256:e952c684274a7714b3160f57ec1d78309f955c6335c04433f07d36c5eb27b1f9 \
--hash=sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98 \
--hash=sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72 \
--hash=sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e \
--hash=sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3 \
--hash=sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac
fonttools==4.53.1 \
--hash=sha256:02569e9a810f9d11f4ae82c391ebc6fb5730d95a0657d24d754ed7763fb2d122 \
--hash=sha256:0679a30b59d74b6242909945429dbddb08496935b82f91ea9bf6ad240ec23397 \
--hash=sha256:10f5e6c3510b79ea27bb1ebfcc67048cde9ec67afa87c7dd7efa5c700491ac7f \
--hash=sha256:2af40ae9cdcb204fc1d8f26b190aa16534fcd4f0df756268df674a270eab575d \
--hash=sha256:32f029c095ad66c425b0ee85553d0dc326d45d7059dbc227330fc29b43e8ba60 \
--hash=sha256:35250099b0cfb32d799fb5d6c651220a642fe2e3c7d2560490e6f1d3f9ae9169 \
--hash=sha256:3b3c8ebafbee8d9002bd8f1195d09ed2bd9ff134ddec37ee8f6a6375e6a4f0e8 \
--hash=sha256:4824c198f714ab5559c5be10fd1adf876712aa7989882a4ec887bf1ef3e00e31 \
--hash=sha256:5ff7e5e9bad94e3a70c5cd2fa27f20b9bb9385e10cddab567b85ce5d306ea923 \
--hash=sha256:651390c3b26b0c7d1f4407cad281ee7a5a85a31a110cbac5269de72a51551ba2 \
--hash=sha256:6e08f572625a1ee682115223eabebc4c6a2035a6917eac6f60350aba297ccadb \
--hash=sha256:6ed170b5e17da0264b9f6fae86073be3db15fa1bd74061c8331022bca6d09bab \
--hash=sha256:73379d3ffdeecb376640cd8ed03e9d2d0e568c9d1a4e9b16504a834ebadc2dfb \
--hash=sha256:75a157d8d26c06e64ace9df037ee93a4938a4606a38cb7ffaf6635e60e253b7a \
--hash=sha256:791b31ebbc05197d7aa096bbc7bd76d591f05905d2fd908bf103af4488e60670 \
--hash=sha256:7b6b35e52ddc8fb0db562133894e6ef5b4e54e1283dff606fda3eed938c36fc8 \
--hash=sha256:84ec3fb43befb54be490147b4a922b5314e16372a643004f182babee9f9c3407 \
--hash=sha256:8959a59de5af6d2bec27489e98ef25a397cfa1774b375d5787509c06659b3671 \
--hash=sha256:9dfdae43b7996af46ff9da520998a32b105c7f098aeea06b2226b30e74fbba88 \
--hash=sha256:9e6ceba2a01b448e36754983d376064730690401da1dd104ddb543519470a15f \
--hash=sha256:9efd176f874cb6402e607e4cc9b4a9cd584d82fc34a4b0c811970b32ba62501f \
--hash=sha256:a1c7c5aa18dd3b17995898b4a9b5929d69ef6ae2af5b96d585ff4005033d82f0 \
--hash=sha256:aae7bd54187e8bf7fd69f8ab87b2885253d3575163ad4d669a262fe97f0136cb \
--hash=sha256:b21952c092ffd827504de7e66b62aba26fdb5f9d1e435c52477e6486e9d128b2 \
--hash=sha256:b96cd370a61f4d083c9c0053bf634279b094308d52fdc2dd9a22d8372fdd590d \
--hash=sha256:becc5d7cb89c7b7afa8321b6bb3dbee0eec2b57855c90b3e9bf5fb816671fa7c \
--hash=sha256:bee32ea8765e859670c4447b0817514ca79054463b6b79784b08a8df3a4d78e3 \
--hash=sha256:c6e7170d675d12eac12ad1a981d90f118c06cf680b42a2d74c6c931e54b50719 \
--hash=sha256:c818c058404eb2bba05e728d38049438afd649e3c409796723dfc17cd3f08749 \
--hash=sha256:c8696544c964500aa9439efb6761947393b70b17ef4e82d73277413f291260a4 \
--hash=sha256:c9cd19cf4fe0595ebdd1d4915882b9440c3a6d30b008f3cc7587c1da7b95be5f \
--hash=sha256:d4d0096cb1ac7a77b3b41cd78c9b6bc4a400550e21dc7a92f2b5ab53ed74eb02 \
--hash=sha256:d92d3c2a1b39631a6131c2fa25b5406855f97969b068e7e08413325bc0afba58 \
--hash=sha256:da33440b1413bad53a8674393c5d29ce64d8c1a15ef8a77c642ffd900d07bfe1 \
--hash=sha256:e013aae589c1c12505da64a7d8d023e584987e51e62006e1bb30d72f26522c41 \
--hash=sha256:e128778a8e9bc11159ce5447f76766cefbd876f44bd79aff030287254e4752c4 \
--hash=sha256:e54f1bba2f655924c1138bbc7fa91abd61f45c68bd65ab5ed985942712864bbb \
--hash=sha256:e5b708073ea3d684235648786f5f6153a48dc8762cdfe5563c57e80787c29fbb \
--hash=sha256:e8bf06b94694251861ba7fdeea15c8ec0967f84c3d4143ae9daf42bbc7717fe3 \
--hash=sha256:f08df60fbd8d289152079a65da4e66a447efc1d5d5a4d3f299cdd39e3b2e4a7d \
--hash=sha256:f1f8758a2ad110bd6432203a344269f445a2907dc24ef6bccfd0ac4e14e0d71d \
--hash=sha256:f677ce218976496a587ab17140da141557beb91d2a5c1a14212c994093f2eae2
# via -r requirements-fonttools.in
meson==1.7.0 \
--hash=sha256:08efbe84803eed07f863b05092d653a9d348f7038761d900412fddf56deb0284 \
--hash=sha256:ae3f12953045f3c7c60e27f2af1ad862f14dee125b4ed9bcb8a842a5080dbf85
gcovr==5.0 \
--hash=sha256:1d80264cbaadff356b3dda71b8c62b3aa803e5b3eb6d526a24932cd6660a2576 \
--hash=sha256:8c49ebcfc5a98b56dd900c687aad0258ac86093d2f81a1417905193ab45fe69f
# via -r requirements.in
ninja==1.11.1.4 \
--hash=sha256:055f386fb550c2c9d6157e45e20a84d29c47968876b9c5794ae2aec46f952306 \
--hash=sha256:096487995473320de7f65d622c3f1d16c3ad174797602218ca8c967f51ec38a0 \
--hash=sha256:2ab67a41c90bea5ec4b795bab084bc0b3b3bb69d3cd21ca0294fc0fc15a111eb \
--hash=sha256:4617b3c12ff64b611a7d93fd9e378275512bb36eff8babff7c83f5116b4f8d66 \
--hash=sha256:5713cf50c5be50084a8693308a63ecf9e55c3132a78a41ab1363a28b6caaaee1 \
--hash=sha256:6aa39f6e894e0452e5b297327db00019383ae55d5d9c57c73b04f13bf79d438a \
--hash=sha256:9c29bb66d2aa46a2409ab369ea804c730faec7652e8c22c1e428cc09216543e5 \
--hash=sha256:b33923c8da88e8da20b6053e38deb433f53656441614207e01d283ad02c5e8e7 \
--hash=sha256:c3b96bd875f3ef1db782470e9e41d7508905a0986571f219d20ffed238befa15 \
--hash=sha256:cede0af00b58e27b31f2482ba83292a8e9171cdb9acc2c867a3b6e40b3353e43 \
--hash=sha256:cf4453679d15babc04ba023d68d091bb613091b67101c88f85d2171c6621c6eb \
--hash=sha256:cf554e73f72c04deb04d0cf51f5fdb1903d9c9ca3d2344249c8ce3bd616ebc02 \
--hash=sha256:cfdd09776436a1ff3c4a2558d3fc50a689fb9d7f1bdbc3e6f7b8c2991341ddb3 \
--hash=sha256:d3090d4488fadf6047d0d7a1db0c9643a8d391f0d94729554dbb89b5bdc769d7 \
--hash=sha256:d4a6f159b08b0ac4aca5ee1572e3e402f969139e71d85d37c0e2872129098749 \
--hash=sha256:ecce44a00325a93631792974659cf253a815cc6da4ec96f89742925dfc295a0d \
--hash=sha256:f6186d7607bb090c3be1e10c8a56b690be238f953616626f5032238c66e56867
jinja2==3.1.4 \
--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
# via gcovr
lxml==4.9.3 \
--hash=sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3 \
--hash=sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d \
--hash=sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a \
--hash=sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120 \
--hash=sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305 \
--hash=sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287 \
--hash=sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23 \
--hash=sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52 \
--hash=sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f \
--hash=sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4 \
--hash=sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584 \
--hash=sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f \
--hash=sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693 \
--hash=sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef \
--hash=sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5 \
--hash=sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02 \
--hash=sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc \
--hash=sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7 \
--hash=sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da \
--hash=sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a \
--hash=sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40 \
--hash=sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8 \
--hash=sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd \
--hash=sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601 \
--hash=sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c \
--hash=sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be \
--hash=sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2 \
--hash=sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c \
--hash=sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129 \
--hash=sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc \
--hash=sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2 \
--hash=sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1 \
--hash=sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7 \
--hash=sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d \
--hash=sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477 \
--hash=sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d \
--hash=sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e \
--hash=sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7 \
--hash=sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2 \
--hash=sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574 \
--hash=sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf \
--hash=sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b \
--hash=sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98 \
--hash=sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12 \
--hash=sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42 \
--hash=sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35 \
--hash=sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d \
--hash=sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce \
--hash=sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d \
--hash=sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f \
--hash=sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db \
--hash=sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4 \
--hash=sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694 \
--hash=sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac \
--hash=sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2 \
--hash=sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7 \
--hash=sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96 \
--hash=sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d \
--hash=sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b \
--hash=sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a \
--hash=sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13 \
--hash=sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340 \
--hash=sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6 \
--hash=sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458 \
--hash=sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c \
--hash=sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c \
--hash=sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9 \
--hash=sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432 \
--hash=sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991 \
--hash=sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69 \
--hash=sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf \
--hash=sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb \
--hash=sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b \
--hash=sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833 \
--hash=sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76 \
--hash=sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85 \
--hash=sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e \
--hash=sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50 \
--hash=sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8 \
--hash=sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4 \
--hash=sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b \
--hash=sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5 \
--hash=sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190 \
--hash=sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7 \
--hash=sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa \
--hash=sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0 \
--hash=sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9 \
--hash=sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0 \
--hash=sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b \
--hash=sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5 \
--hash=sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7 \
--hash=sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4
# via gcovr
markupsafe==2.1.3 \
--hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
--hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
--hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
--hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
--hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
--hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
--hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
--hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
--hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
--hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
--hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
--hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
--hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
--hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
--hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
--hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
--hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
--hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
--hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
--hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
--hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
--hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
--hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
--hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
--hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
--hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
--hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
--hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
--hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
--hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
--hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
--hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
--hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
--hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
--hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
--hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
--hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
--hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
--hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
--hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
--hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
--hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
--hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
--hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
--hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
--hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
--hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
--hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
--hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
--hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
--hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
--hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
--hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
--hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
--hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
--hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
--hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
--hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
# via jinja2
meson==1.5.2 \
--hash=sha256:77706e2368a00d789c097632ccf4fc39251fba56d03e1e1b262559a3c7a08f5b \
--hash=sha256:f955e09ab0d71ef180ae85df65991d58ed8430323de7d77a37e11c9ea630910b
# via -r requirements.in
ninja==1.11.1.1 \
--hash=sha256:18302d96a5467ea98b68e1cae1ae4b4fb2b2a56a82b955193c637557c7273dbd \
--hash=sha256:185e0641bde601e53841525c4196278e9aaf4463758da6dd1e752c0a0f54136a \
--hash=sha256:376889c76d87b95b5719fdd61dd7db193aa7fd4432e5d52d2e44e4c497bdbbee \
--hash=sha256:3e0f9be5bb20d74d58c66cc1c414c3e6aeb45c35b0d0e41e8d739c2c0d57784f \
--hash=sha256:73b93c14046447c7c5cc892433d4fae65d6364bec6685411cb97a8bcf815f93a \
--hash=sha256:7563ce1d9fe6ed5af0b8dd9ab4a214bf4ff1f2f6fd6dc29f480981f0f8b8b249 \
--hash=sha256:76482ba746a2618eecf89d5253c0d1e4f1da1270d41e9f54dfbd91831b0f6885 \
--hash=sha256:84502ec98f02a037a169c4b0d5d86075eaf6afc55e1879003d6cab51ced2ea4b \
--hash=sha256:95da904130bfa02ea74ff9c0116b4ad266174fafb1c707aa50212bc7859aebf1 \
--hash=sha256:9d793b08dd857e38d0b6ffe9e6b7145d7c485a42dcfea04905ca0cdb6017cc3c \
--hash=sha256:9df724344202b83018abb45cb1efc22efd337a1496514e7e6b3b59655be85205 \
--hash=sha256:aad34a70ef15b12519946c5633344bc775a7656d789d9ed5fdb0d456383716ef \
--hash=sha256:d491fc8d89cdcb416107c349ad1e3a735d4c4af5e1cb8f5f727baca6350fdaea \
--hash=sha256:ecf80cf5afd09f14dcceff28cb3f11dc90fb97c999c89307aea435889cb66877 \
--hash=sha256:fa2ba9d74acfdfbfbcf06fad1b8282de8a7a8c481d9dee45c859a8c93fcc1082
# via -r requirements.in
pygments==2.16.1 \
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
# via gcovr
# The following packages are considered to be unsafe in a requirements file:
setuptools==78.1.0 \
--hash=sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54 \
--hash=sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8
setuptools==73.0.1 \
--hash=sha256:b208925fcb9f7af924ed2dc04708ea89791e24bde0d3020b27df0e116088b34e \
--hash=sha256:d59a3e788ab7e012ab2c4baed1b376da6366883ee20d7a5fc426816e3d7b1193
# via -r requirements.in

View file

@ -4,7 +4,7 @@ cpu_family = 'x86'
cpu = 'i686'
endian = 'little'
[built-in options]
[properties]
c_args = []
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
cpp_args = []
@ -18,5 +18,3 @@ ld = 'i686-w64-mingw32-ld'
objcopy = 'i686-w64-mingw32-objcopy'
strip = 'i686-w64-mingw32-strip'
windres = 'i686-w64-mingw32-windres'
pkg-config = 'i686-w64-mingw32-pkg-config'
exe_wrapper = 'wine'

View file

@ -4,7 +4,7 @@ cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[built-in options]
[properties]
c_args = []
c_link_args = ['-static-libgcc', '-Wl,-Bstatic', '-lpthread']
cpp_args = []
@ -18,5 +18,3 @@ ld = 'x86_64-w64-mingw32-ld'
objcopy = 'x86_64-w64-mingw32-objcopy'
strip = 'x86_64-w64-mingw32-strip'
windres = 'x86_64-w64-mingw32-windres'
pkg-config = 'x86_64-w64-mingw32-pkg-config'
exe_wrapper = 'wine'

View file

@ -3,10 +3,10 @@ version: 2.1
executors:
win32-executor:
docker:
- image: ubuntu:24.04
- image: cimg/base:2023.10
win64-executor:
docker:
- image: ubuntu:24.04
- image: cimg/base:2023.10
dist-executor:
docker:
- image: cimg/base:2023.10
@ -37,7 +37,7 @@ jobs:
- run: meson dist --no-tests -Cbuild
- persist_to_workspace:
root: .
paths: [build/meson-dist/harfbuzz-*.tar.xz]
paths: build/meson-dist/harfbuzz-*.tar.xz
publish-dist:
executor: dist-executor
@ -56,7 +56,22 @@ jobs:
- 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: RUN_VALGRIND=1 meson test -Cbuild -t 10 --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs --num-processes=$(($(nproc)/2 + 1))
# 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))
alpine:
docker:
- image: alpine
steps:
- checkout
- run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja
- run: |
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.56.0
meson setup build --buildtype=minsize
meson compile -Cbuild -j9
meson test -Cbuild --print-errorlogs
asan-ubsan:
docker:
@ -66,47 +81,43 @@ jobs:
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: |
export ASAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1
export UBSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1:print_stacktrace=1
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.60.0
pip3 install meson==0.56.0
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
meson compile -Cbuild -j9
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
tsan:
docker:
- image: ubuntu:24.04
- image: ubuntu:20.04
steps:
- checkout
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: |
export TSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.60.0
pip3 install meson==0.56.0
CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true
meson compile -Cbuild -j9
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
msan:
docker:
- image: ubuntu:24.04
- image: ubuntu:20.04
steps:
- checkout
- run: apt update || true
- run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip python3-venv ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev
- run: |
export MSAN_OPTIONS=log_path=stderr:halt_on_error=1:abort_on_error=1:print_stacktrace=1
python3 -m venv venv
source venv/bin/activate
pip3 install meson==0.60.0
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
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
meson compile -Cbuild -j9
meson test -Cbuild -t 10 --print-errorlogs | asan_symbolize | c++filt
meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt
clang-cxx2a:
docker:
@ -121,21 +132,17 @@ jobs:
executor: win32-executor
steps:
- checkout
- run: dpkg --add-architecture i386
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-i686 zip wine wine32
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-i686 zip
- run: |
export LANG=en_US.UTF-8
python3 -m venv venv
source venv/bin/activate
pip3 install meson==1.6.0
bash .ci/build-win.sh 32
meson devenv -Cbuild-win32 meson test -t 10 --print-errorlogs --suite=harfbuzz
pip3 install meson==0.60.0
bash .ci/build-win32.sh
- store_artifacts:
path: harfbuzz-win32.zip
- persist_to_workspace:
root: .
paths: [harfbuzz-win32.zip]
paths: harfbuzz-win32.zip
publish-win32:
executor: win32-executor
@ -143,8 +150,6 @@ jobs:
- checkout
- attach_workspace:
at: .
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y curl
- run: |
mv harfbuzz-win32{,-$CIRCLE_TAG}.zip
.ci/publish_release_artifact.sh harfbuzz-win32-$CIRCLE_TAG.zip
@ -153,21 +158,17 @@ jobs:
executor: win64-executor
steps:
- checkout
- run: dpkg --add-architecture i386
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-x86-64 zip wine wine64 wine32:i386
- run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip python3-venv git g++-mingw-w64-x86-64 zip
- run: |
export LANG=en_US.UTF-8
python3 -m venv venv
source venv/bin/activate
pip3 install meson==1.6.0
bash .ci/build-win.sh 64
meson devenv -Cbuild-win64 meson test -t 10 --print-errorlogs --suite=harfbuzz
pip3 install meson==0.60.0
bash .ci/build-win64.sh
- store_artifacts:
path: harfbuzz-win64.zip
- persist_to_workspace:
root: .
paths: [harfbuzz-win64.zip]
paths: harfbuzz-win64.zip
publish-win64:
executor: win64-executor
@ -175,8 +176,6 @@ jobs:
- checkout
- attach_workspace:
at: .
- run: apt update
- run: DEBIAN_FRONTEND=noninteractive apt install -y curl
- run: |
mv harfbuzz-win64{,-$CIRCLE_TAG}.zip
.ci/publish_release_artifact.sh harfbuzz-win64-$CIRCLE_TAG.zip
@ -201,6 +200,7 @@ workflows:
branches:
ignore: /.*/
- fedora-valgrind
- alpine
- asan-ubsan
- tsan
- msan

View file

@ -15,7 +15,7 @@ jobs:
container:
image: devkitpro/devkitarm:latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Configure CMake
run: |
cmake -S . -B build \

View file

@ -21,7 +21,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View file

@ -11,10 +11,10 @@ permissions:
jobs:
build:
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: install dependencies
run: sudo apt-get install gcc
- name: HB_DISABLE_DEPRECATED

View file

@ -11,7 +11,7 @@ jobs:
latest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- run: sudo apt-get install gcc clang wget git curl pkg-config libfreetype6-dev libglib2.0-dev libicu-dev libgraphite2-dev

View file

@ -1,63 +0,0 @@
name: fontations
on:
push:
branches: [ main ]
tags: ["*.*.*"]
pull_request:
branches: [ main ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- uses: dtolnay/rust-toolchain@nightly
- name: Install Dependencies
run: |
rustup component add \
rust-src \
rustfmt \
clippy \
--toolchain nightly-x86_64-unknown-linux-gnu
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 \
pkg-config \
bindgen
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with:
python-version: '3.12'
- name: Install Python Dependencies
run: pip3 install -r .ci/requirements.txt --require-hashes
- name: Setup Meson
run: |
ccache --version
meson setup build \
-Dauto_features=enabled \
-Dchafa=disabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Dfontations=enabled
- name: Build
run: meson compile -Cbuild
- name: Test
run: RUST_BACKTRACE=1 meson test --print-errorlogs -Cbuild

View file

@ -12,13 +12,13 @@ permissions:
jobs:
build:
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14
with:
key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }}
- name: Install Dependencies
@ -34,14 +34,16 @@ jobs:
libglib2.0-dev \
libgraphite2-dev \
libicu-dev \
ninja-build \
pkg-config \
help2man
python3 \
python3-setuptools
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: '3.12'
python-version: '3.x'
- name: Install Python Dependencies
run: pip3 install -r .ci/requirements.txt --require-hashes
run: sudo pip3 install -r .ci/requirements.txt --require-hashes
- name: Setup Meson
run: |
ccache --version
@ -50,6 +52,7 @@ jobs:
-Dchafa=disabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Db_coverage=true \
-Ddoc_tests=true \
-Dragel_subproject=true
- name: Build
@ -64,3 +67,9 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
REVISION: ${{ github.sha }}
- name: Generate Coverage
run: ninja -Cbuild coverage-xml
- name: Upload Coverage
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
with:
file: build/meson-logs/coverage.xml

View file

@ -15,16 +15,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14
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 rm -f pkg-config@0.29.2
brew install \
cairo \
freetype \
@ -34,11 +33,11 @@ jobs:
icu4c \
meson \
ninja \
pkgconf
pkg-config
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: '3.12'
python-version: '3.x'
- name: Install Python Dependencies
run: pip3 install -r .ci/requirements.txt --require-hashes
- name: Setup Meson
@ -54,7 +53,14 @@ jobs:
-Dcoretext=enabled \
-Dgraphite=enabled \
-Doptimization=2 \
-Db_coverage=true \
- name: Build
run: meson compile -Cbuild
- name: Test
run: meson test --print-errorlogs -Cbuild
- name: Generate Coverage
run: ninja -Cbuild coverage-xml
- name: Upload Coverage
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
with:
file: build/meson-logs/coverage.xml

View file

@ -28,16 +28,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup Ccache
uses: hendrikmuhs/ccache-action@a1209f81afb8c005c13b4296c32e363431bffea5 # v1.2.17
uses: hendrikmuhs/ccache-action@ed74d11c0b343532753ecead8a951bb09bb34bc9 # v1.2.14
with:
variant: sccache
key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }}
- name: Setup Python
uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5.2.0
with:
python-version: '3.12'
python-version: '3.x'
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
with:

View file

@ -21,16 +21,19 @@ jobs:
MSYS2_ARCH: i686
- MSYSTEM: MINGW64
MSYS2_ARCH: x86_64
- MSYSTEM: CLANG64
MSYS2_ARCH: clang-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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
- name: Setup MSYS2
uses: msys2/setup-msys2@cf96e00c0aab3788743aaf63b64146f0d383cee9 # v2
with:
@ -39,7 +42,8 @@ jobs:
install: >-
mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo
mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype
mingw-w64-${{ matrix.MSYS2_ARCH }}-cc
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
@ -47,9 +51,12 @@ jobs:
mingw-w64-${{ matrix.MSYS2_ARCH }}-icu
mingw-w64-${{ matrix.MSYS2_ARCH }}-meson
mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkgconf
mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config
mingw-w64-${{ matrix.MSYS2_ARCH }}-python
mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip
- name: Remove installed HarfBuzz DLLs
run: |
rm -f -v /ming*/bin/libharfbuzz-*.dll
- name: Install Python Dependencies
run: |
pip3 install -r .ci/requirements-fonttools.txt --require-hashes
@ -69,7 +76,7 @@ jobs:
run: meson test --print-errorlogs --suite=harfbuzz -Cbuild
- name: Upload DLLs
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
with:
name: libharfbuzz-${{ matrix.MSYS2_ARCH }}
path: ./build/src/libharfbuzz-*.dll

View file

@ -29,12 +29,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
@ -51,7 +51,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
with:
name: SARIF file
path: results.sarif
@ -59,6 +59,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@45775bd8235c68ba998cffa5171334d58593da47 # v3.28.15
uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8
with:
sarif_file: results.sarif

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.12)
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.")
@ -6,6 +6,20 @@ message(WARN "HarfBuzz has a Meson port and tries to migrate all the other build
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
## Limit framework build to Xcode generator
if (BUILD_FRAMEWORK)
# for a framework build on macOS, use:
# cmake -DBUILD_FRAMEWORK=ON -Bbuild -H. -GXcode && cmake --build build
if (NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode")
message(FATAL_ERROR
"You should use Xcode generator with BUILD_FRAMEWORK enabled")
endif ()
set (CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_64_BIT)")
set (CMAKE_MACOSX_RPATH ON)
set (BUILD_SHARED_LIBS ON)
endif ()
## Disallow in-source builds, as CMake generated make files can collide with autotools ones
if (NOT MSVC AND "${PROJECT_BINARY_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
message(FATAL_ERROR
@ -59,14 +73,6 @@ if (HB_HAVE_INTROSPECTION)
set (HB_HAVE_GLIB ON)
endif ()
if (APPLE)
option(BUILD_FRAMEWORK "Build as Apple Frameworks" OFF)
endif ()
if (BUILD_FRAMEWORK)
set (CMAKE_MACOSX_RPATH ON)
set (BUILD_SHARED_LIBS OFF)
endif ()
include_directories(AFTER
${PROJECT_SOURCE_DIR}/src
${PROJECT_BINARY_DIR}/src
@ -162,7 +168,7 @@ set (subset_project_sources
${PROJECT_SOURCE_DIR}/src/hb-subset-plan.cc
${PROJECT_SOURCE_DIR}/src/hb-subset-plan.hh
${PROJECT_SOURCE_DIR}/src/hb-subset-plan-member-list.hh
${PROJECT_SOURCE_DIR}/src/hb-subset-serialize.cc
${PROJECT_SOURCE_DIR}/src/hb-subset-repacker.cc
${PROJECT_SOURCE_DIR}/src/hb-subset.cc
${PROJECT_SOURCE_DIR}/src/hb-subset.hh
${PROJECT_SOURCE_DIR}/src/hb-repacker.hh
@ -204,7 +210,6 @@ set (project_headers
${PROJECT_SOURCE_DIR}/src/hb-ot.h
${PROJECT_SOURCE_DIR}/src/hb-paint.h
${PROJECT_SOURCE_DIR}/src/hb-set.h
${PROJECT_SOURCE_DIR}/src/hb-script-list.h
${PROJECT_SOURCE_DIR}/src/hb-shape-plan.h
${PROJECT_SOURCE_DIR}/src/hb-shape.h
${PROJECT_SOURCE_DIR}/src/hb-style.h
@ -214,7 +219,7 @@ set (project_headers
)
set (subset_project_headers
${PROJECT_SOURCE_DIR}/src/hb-subset.h
${PROJECT_SOURCE_DIR}/src/hb-subset-serialize.h
${PROJECT_SOURCE_DIR}/src/hb-subset-repacker.h
)
## Find and include needed header folders and libraries
@ -234,7 +239,7 @@ if (HB_HAVE_FREETYPE AND NOT TARGET freetype)
set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${FREETYPE_INCLUDE_DIRS})
set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${FREETYPE_LIBRARIES})
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var FT_Get_Transform)
check_funcs(FT_Get_Var_Blend_Coordinates FT_Set_Var_Blend_Coordinates FT_Done_MM_Var)
endif ()
if (HB_HAVE_FREETYPE)
@ -335,15 +340,15 @@ endif ()
if (WIN32 AND HB_HAVE_GDI)
add_definitions(-DHAVE_GDI)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-gdi.h)
list(APPEND THIRD_PARTY_LIBS gdi32 user32)
list(APPEND PC_LIBS_PRIV -lgdi32 -luser32)
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 user32)
list(APPEND PC_LIBS_PRIV -lusp10 -lgdi32 -lrpcrt4 -luser32)
list(APPEND THIRD_PARTY_LIBS usp10 gdi32 rpcrt4)
list(APPEND PC_LIBS_PRIV -lusp10 -lgdi32 -lrpcrt4)
endif ()
if (WIN32 AND HB_HAVE_DIRECTWRITE)
@ -501,21 +506,6 @@ if (HB_HAVE_ICU)
if (BUILD_SHARED_LIBS)
set_target_properties(harfbuzz harfbuzz-icu PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
if (BUILD_FRAMEWORK)
set_target_properties(harfbuzz harfbuzz-icu PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION "${HB_VERSION}"
PUBLIC_HEADER "${project_headers}"
PRODUCT_BUNDLE_IDENTIFIER "harfbuzz.harfbuzz-icu"
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
OUTPUT_NAME "harfbuzz-icu"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz-icu"
MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}"
MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}"
)
endif ()
endif ()
endif ()
@ -523,27 +513,12 @@ endif ()
## Define harfbuzz-subset library
if (HB_BUILD_SUBSET)
add_library(harfbuzz-subset ${subset_project_sources} ${subset_project_headers})
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-subset.h ${PROJECT_SOURCE_DIR}/src/hb-subset-serialize.h)
list(APPEND project_headers ${PROJECT_SOURCE_DIR}/src/hb-subset.h ${PROJECT_SOURCE_DIR}/src/hb-subset-repacker.h)
add_dependencies(harfbuzz-subset harfbuzz)
target_link_libraries(harfbuzz-subset harfbuzz ${THIRD_PARTY_LIBS})
if (BUILD_SHARED_LIBS)
set_target_properties(harfbuzz harfbuzz-subset PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
if (BUILD_FRAMEWORK)
set_target_properties(harfbuzz harfbuzz-subset PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION "${HB_VERSION}"
PUBLIC_HEADER "${project_headers}"
PRODUCT_BUNDLE_IDENTIFIER "harfbuzz.harfbuzz-subset"
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
OUTPUT_NAME "harfbuzz-subset"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz-subset"
MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}"
MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}"
)
endif ()
endif ()
endif ()
@ -593,22 +568,7 @@ if (HB_HAVE_GOBJECT)
target_link_libraries(harfbuzz-gobject harfbuzz ${GOBJECT_LIBRARIES} ${THIRD_PARTY_LIBS})
if (BUILD_SHARED_LIBS)
set_target_properties(harfbuzz harfbuzz-gobject PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
if (BUILD_FRAMEWORK)
set_target_properties(harfbuzz-gobject PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION "${HB_VERSION}"
PUBLIC_HEADER "${project_headers}"
PRODUCT_BUNDLE_IDENTIFIER "harfbuzz.harfbuzz-gobject"
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
OUTPUT_NAME "harfbuzz-gobject"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz-gobject"
MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}"
MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}"
)
endif ()
set_target_properties(harfbuzz-gobject PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
endif ()
endif ()
@ -621,21 +581,6 @@ if (HB_HAVE_CAIRO)
if (BUILD_SHARED_LIBS)
set_target_properties(harfbuzz-cairo PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE)
if (BUILD_FRAMEWORK)
set_target_properties(harfbuzz-cairo PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION "${HB_VERSION}"
PUBLIC_HEADER "${project_headers}"
PRODUCT_BUNDLE_IDENTIFIER "harfbuzz.harbuzz-cairo"
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
OUTPUT_NAME "harfbuzz-cairo"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz-cairo"
MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}"
MACOSX_FRAMEWORK_BUNDLE_VERSION "${HB_VERSION}"
)
endif ()
endif ()
endif()
@ -774,12 +719,8 @@ if (BUILD_FRAMEWORK)
set (CMAKE_MACOSX_RPATH ON)
set_target_properties(harfbuzz PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION "${HB_VERSION}"
PUBLIC_HEADER "${project_headers}"
PRODUCT_BUNDLE_IDENTIFIER "harfbuzz"
XCODE_ATTRIBUTE_INSTALL_PATH "@rpath"
OUTPUT_NAME "harfbuzz"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
)
set (MACOSX_FRAMEWORK_IDENTIFIER "harfbuzz")
set (MACOSX_FRAMEWORK_SHORT_VERSION_STRING "${HB_VERSION}")
@ -940,8 +881,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
COMPONENT runtime OPTIONAL
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz")
install(EXPORT harfbuzzConfig
@ -953,8 +893,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
COMPONENT runtime OPTIONAL
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz-icu")
endif ()
@ -963,19 +902,13 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
COMPONENT runtime OPTIONAL
FRAMEWORK DESTINATION Library/Frameworks
)
make_pkgconfig_pc_file("harfbuzz-cairo")
endif ()
if (HB_BUILD_SUBSET)
install(TARGETS harfbuzz-subset
EXPORT harfbuzz-subset
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION Library/Frameworks
COMPONENT runtime OPTIONAL
)
make_pkgconfig_pc_file("harfbuzz-subset")
endif ()
@ -1010,12 +943,9 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
endif ()
if (HB_HAVE_GOBJECT)
install(TARGETS harfbuzz-gobject
EXPORT harfbuzz-gobject
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT runtime OPTIONAL
)
make_pkgconfig_pc_file("harfbuzz-gobject")
if (HB_HAVE_INTROSPECTION)

228
NEWS
View file

@ -1,232 +1,12 @@
Overview of changes leading to 11.1.0
Wednesdat, April 16, 2025
====================================
- Include bidi mirroring variants of the requested codepoints when subsetting.
The new HB_SUBSET_FLAGS_NO_BIDI_CLOSURE can be used to disable this
behaviour.
- Various bug fixes.
- Various build fixes and improvements.
- Various test suite improvements.
New API:
+HB_SUBSET_FLAGS_NO_BIDI_CLOSURE
Overview of changes leading to 11.0.1
Friday, April 4, 2025
====================================
- The change in version 10.3.0 to apply “trak” table tracking values to glyph
advances directly has been reverted as it required every font functions
implementation to handle it, which breaks existing custom font functions.
Tracking is instead back to being applied during shaping.
- When `directwrite` integration is enabled, we now link to `dwrite.dll`
instead of dynamically loading it.
- A new experimental APIs for getting raw “CFF” and “CFF2” CharStrings.
- We now provide manpages for the various command line utilities. Building
manpages requires “help2man” and will be skipped if it is not present.
- The command line utilities now set different return value for different kinds
of failures. Details are provided in the manpages.
- Various fixes and improvements to `fontations` font functions.
- All shaping operations using the `ot` shaper have become memory
allocation-free.
- Glyph extents returned by `hb-ot` and `hb-ft` font functions are now rounded
in stead of flooring/ceiling them, which also matches what other font
libraries do.
- Fix “AAT” deleted glyph marks interfering with fallback mark positioning.
- Glyph outlines emboldening have been moved out of `hb-ot` and `hb-ft` font
functions to the HarfBuzz font layer, so that it works with any font
functions implementation.
- Fix our fallback C++11 atomics integration, which seems to not be widely
used.
- Various testing fixes and improvements.
- Various subsetting fixes and improvements.
- Various other fixes and improvements.
Overview of changes leading to 11.0.0
Monday, March 24, 2025
====================================
- There are three new font-functions implementations (integrations) in this
release:
* `hb-coretext` has gained one, calling into the CoreText library,
* `hb-directwrite` has gained one, calling into the DirectWrite library.
* `hb-fontations` has gained one, calling into the Skrifa Rust library.
All three are mostly useful for performance and correctness testing, but some
clients might find them useful.
An API is added to use them from a single API by providing a backend name
string:
* `hb_font_set_funcs_using()`
- Several new APIs are added, to load a font-face using different
"face-loaders", and a single entry point to them all using a loader name
string:
* `hb_ft_face_create_from_file_or_fail()` and
`hb_ft_face_create_from_blob_or_fail()`
* `hb_coretext_face_create_from_file_or_fail()` and
`hb_coretext_face_create_from_blob_or_fail()`
* `hb_directwrite_face_create_from_file_or_fail()` and
`hb_directwrite_face_create_from_blob_or_fail()`
* `hb_face_create_from_file_or_fail_using()`
- All drawing and painting operations using the default, `hb-ot` functions have
become memory allocation-free.
- Several performance optimizations have been implemented.
- Application of the `trak` table during shaping has been improved.
- The `directwrite` shaper now supports font variations, and correctly applies
user features.
- The `hb-directwrite` API and shaper has graduated from experimental.
- Various bug fixes and other improvements.
- New API:
+hb_malloc
+hb_calloc
+hb_realloc
+hb_free
+hb_face_list_loaders
+hb_face_create_or_fail_using
+hb_face_create_from_file_or_fail_using
+hb_font_list_funcs
+hb_font_set_funcs_using
+hb_coretext_face_create_from_blob_or_fail
+hb_directwrite_face_create_from_file_or_fail
+hb_directwrite_face_create_from_blob_or_fail
+hb_directwrite_font_create
+hb_directwrite_font_get_dw_font_face
+hb_directwrite_font_set_funcs
+hb_fontations_font_set_funcs
+hb_ft_face_create_from_blob_or_fail
+hb_paint_push_font_transform
+hb_paint_push_inverse_font_transform
+HB_BUFFER_CLUSTER_LEVEL_GRAPHEMES
+HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
+HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
+HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
- Deprecated API:
+hb_directwrite_font_get_dw_font
Overview of changes leading to 10.4.0
Saturday, March 1, 2025
====================================
- Drawing glyphs using hb-draw API now avoids any “malloc” calls, which
improves drawing performance by 10+%.
- Add support new “GVAR” table fonts with more than 65535 glyphs. Support is
currently behind a compilation flag and is disabled by default.
- Some hb-directwrite and hb-ft APIs got renamed with more clear names and the
old names are deprecated.
- Various build and fuzzing fixes.
- New API:
+hb_directwrite_face_get_dw_font_face()
+hb_ft_font_get_ft_face()
- Deprecated API:
+hb_directwrite_face_get_font_face()
+hb_ft_font_get_face()
Overview of changes leading to 10.3.0
Thursday, February 11, 2025
====================================
- Vastly improved “AAT” shaping performance. LucidaGrande benchmark-shape
before: 14.6ms after: 5.9ms.
- Improved OpenType shaping performance (kerning / ligature), at the expense of
~1kb per face allocated cache memory. Roboto-Regular benchmark-shape before:
10.3ms after: 9.4ms.
- Improved “COLRv1” benchmark-font paint performance. Before: 7.85ms after
4.85ms.
- Dont apply glyph substitutions in “morx” table of a font with known broken
“morx” table (AALMAGHRIBI.ttf font).
- Update IANA and OT language registries.
- Various documentation updates.
- Various build improvements, and test speed-ups.
- The “hb_face_reference_blob()” API now works for faces created with
“hb_face_create_for_tables()” if the face sets “get_table_tags” callback.
This constructs a new face blob from individual table blobs.
- Various fixes to how “trak” table is handled to bring it closer to Core Text
behaviour. Particularly, the tracking values for sizes not explicitly set in
the table are now properly interpolated, and the tracking is applied to glyph
advances when they are returned by ot-font functions, instead of applying
them during shaping. The “trak” pseudo OpenType feature that could be used to
disable “trak” table application have been dropped.
- Core Text font functions now support non-BMP code points.
- The drawing algorithm used by hb-draw for “glyf” table now match the
algorithm used by FreeType and Core Text.
- The “hb_coretext_font_create()” API now copy font variations from Core Text
font to the created HarfBuzz font.
- Add an API to get the feature tags enabled on a given shape-plan after
executing it, which can be used to applications to show in the UI what
features are applied by default (which can vary based on the font, the
script, the language, and the direction set on the buffer).
- Add APIs to created HarfBuzz font from DirectWrite font, and copy the font
variations.
- New API:
+hb_directwrite_font_create()
+hb_directwrite_font_get_dw_font()
+hb_ot_shape_plan_get_feature_tags()
Overview of changes leading to 10.2.0
Saturday, January 11, 2025
====================================
- Consider Unicode Variation Selectors when subsetting “cmap” table.
- Guard hb_cairo_glyphs_from_buffer() against malformed UTF-8 strings.
- Fix incorrect “COLR” v1 glyph scaling in hb-cairo.
- Use locale-independent parsing of double numbers is “hb-subset” command line
tool.
- Fix incorrect zeroing of advance width of base glyphs in various “Courier New”
font versions due to incorrect “GDEF” glyph classes.
- Fix handling of long language codes with “HB_LEAN” configuration.
- Update OpenType language system registry.
- Allow all Myanmar tone marks (including visarga) in any order
- Dont insert U+25CC DOTTED CIRCLE before superscript/subscript digits
- Handle Garay script as right to left script.
- New API for serializing font tables and potentially repacking them in optimal
way. This was a previously experimental-only API.
- New API for converting font variation setting from and to strings.
- Various build fixes
- Various subsetter and instancer fixes.
- New API:
+hb_subset_serialize_link_t
+hb_subset_serialize_object_t
+hb_subset_serialize_or_fail()
+hb_subset_axis_range_from_string()
+hb_subset_axis_range_to_string()
Overview of changes leading to 10.1.0
Tuesday, November 5, 2024
====================================
- Fix the sign of fallback vertical glyph advance (used when font has no
vertical advance data).
- Increase maximum “CFF” operands limit 20 times to support more complex fonts.
- Add “--face-loader” option to command line utilities.
- Support “COLR” v0 table in hb_font_get_glyph_extents().
- Add support for font functions that use Core Text APIs, similar to FreeType
font functions. This allows, for example, using drawing fonts that use the new
(and undocumented) “hvgl” table.
- Update IANA and OT language registries, as well ase USE data files.
- Fix build with ICU 76.
- Various compiler warnings and build fixes.
- Various subsetter fixes.
- New API:
+hb_face_create_or_fail()
+hb_face_create_from_file_or_fail()
+hb_coretext_face_create_from_file_or_fail()
+hb_coretext_font_set_funcs()
+hb_ft_face_create_from_file_or_fail()
Overview of changes leading to 10.0.1
Tuesday, September 24, 2024
Tuesday, Sep 24, 2024
====================================
- Relax sanitization checks for “morx” subtables to fix broken AAT shaping of
macOS 15.0 version of GeezaPro.
Overview of changes leading to 10.0.0
Monday, September 23, 2024
Monday, Sep 23, 2024
====================================
- Unicode 16.0.0 support.
- Various documentation fixes.
@ -351,10 +131,10 @@ Saturday, November 11, 2023
tools. Old option is kept as an alias.
- New API:
+HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
- Deprecated API:
+HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
Overview of changes leading to 8.2.2
Wednesday, October 18, 2023

View file

@ -1,9 +1,9 @@
[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/actions/workflows/linux-ci.yml/badge.svg)](https://github.com/harfbuzz/harfbuzz/actions/workflows/linux-ci.yml)
[![macoOS CI Status](https://github.com/harfbuzz/harfbuzz/actions/workflows/macos-ci.yml/badge.svg)](https://github.com/harfbuzz/harfbuzz/actions/workflows/macos-ci.yml)
[![Windows CI Status](https://github.com/harfbuzz/harfbuzz/actions/workflows/msvc-ci.yml/badge.svg)](https://github.com/harfbuzz/harfbuzz/actions/workflows/msvc-ci.yml)
[![Linux CI Status](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)](https://github.com/harfbuzz/harfbuzz/workflows/linux-ci/badge.svg)
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#harfbuzz)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
@ -35,20 +35,13 @@ will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
`hb-view.exe`, `hb-shape.exe`, and all dependencies.
The canonical source tree is available on [github][4].
Both development and user support discussion around HarfBuzz happens on
[github][4] as well.
The API that comes with `hb.h` will not change incompatibly. Other, peripheral,
headers are more likely to go through minor modifications, but again, we do our
best to never change API in an incompatible way. We will never break the ABI.
The API and ABI are stable even across major version number jumps. In fact,
current HarfBuzz is API/ABI compatible all the way back to the 0.9.x series.
If one day we need to break the API/ABI, that would be called a new a library.
As such, we bump the major version number only when we add major new features,
the minor version when there is new API, and the micro version when there
are bug fixes.
If you are not sure whether Pango or HarfBuzz is right for you, read [Pango vs
HarfBuzz][5].
## Development
@ -58,38 +51,24 @@ For custom configurations, see [CONFIG.md](CONFIG.md).
For testing and profiling, see [TESTING.md](TESTING.md).
For using with Python, see [README.python.md](README.python.md). There is also [uharfbuzz](https://github.com/harfbuzz/uharfbuzz).
For cross-compiling to Windows from Linux or macOS, see [README.mingw.md](README.mingw.md).
To report bugs or submit patches please use [github][4] issues and pull-requests.
### Developer documents
To get a better idea of where HarfBuzz stands in the text rendering stack you
may want to read [State of Text Rendering 2024][6].
Here are a few presentation slides about HarfBuzz at the
Internationalization and Unicode Conference over the years:
- 2014 [Unicode, OpenType, and HarfBuzz: Closing the Circle][7]
- 2012 [HarfBuzz, The Free and Open Text Shaping Engine][8]
- 2016 [Ten Years of HarfBuzz][20]
- 2009 [HarfBuzz: the Free and Open Shaping Engine][9]
* November 2014, [Unicode, OpenType, and HarfBuzz: Closing the Circle][7],
* October 2012, [HarfBuzz, The Free and Open Text Shaping Engine][8],
* October 2009, [HarfBuzz: the Free and Open Shaping Engine][9].
More presentations and papers are available on [behdad][11]'s website.
In particular, the following _studies_ are relevant to HarfBuzz development:
Both development and user support discussion around HarfBuzz happens on the
[github][4].
- 2025 [Subsetting][21]
- 2025 [Caching][12]
- 2025 [`hb-decycler`][13]
- 2022 [`hb-iter`][14]
- 2022 [A C library written in C++][15]
- 2022 [The case of the slow `hb-ft` `>h_advance` function][18]
- 2022 [PackTab: A static integer table packer][16]
- 2020 [HarfBuzz OT+AAT "Unishaper"][19]
- 2014 [Building the Indic Shaper][17]
- 2012 [Memory Consumption][10]
To report bugs or submit patches please use [github][4] issues and
pull-requests.
For a comparison of old vs new HarfBuzz memory consumption see [this][10].
<!--See past and upcoming [HarfBuzz Hackfests](https://freedesktop.org/wiki/Software/HarfBuzz/Hackfests/)!-->
## Name
@ -106,8 +85,6 @@ transliterated using the Latin script. It also means "talkative" or
> TrueType that adds support for complex script rendering, and HarfBuzz is an
> implementation of OpenType complex text shaping.
## Distribution
<details>
<summary>Packaging status of HarfBuzz</summary>
@ -119,19 +96,9 @@ transliterated using the Latin script. It also means "talkative" or
[2]: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6AATIntro.html
[3]: https://github.com/harfbuzz/harfbuzz/releases
[4]: https://github.com/harfbuzz/harfbuzz
[5]: http://mces.blogspot.com/2009/11/pango-vs-harfbuzz.html
[6]: http://behdad.org/text2024
[7]: https://docs.google.com/presentation/d/1x97pfbB1gbD53Yhz6-_yBUozQMVJ_5yMqqR_D-R7b7I/preview
[8]: https://docs.google.com/presentation/d/1ySTZaXP5XKFg0OpmHZM00v5b17GSr3ojnzJekl4U8qI/preview
[7]: https://goo.gl/FSIQuC
[8]: https://goo.gl/2wSRu
[9]: http://behdad.org/download/Presentations/slippy/harfbuzz_slides.pdf
[10]: https://docs.google.com/document/d/12jfNpQJzeVIAxoUSpk7KziyINAa1msbGliyXqguS86M/preview
[11]: https://behdad.org/
[12]: https://docs.google.com/document/d/1_VgObf6Je0J8byMLsi7HCQHnKo2emGnx_ib_sHo-bt4/preview
[13]: https://docs.google.com/document/d/1Y-u08l9YhObRVObETZt1k8f_5lQdOix9TRH3zEXaoAw/preview
[14]: https://docs.google.com/document/d/1o-xvxCbgMe9JYFHLVnPjk01ZY_8Cj0vB9-KTI1d0nyk/preview
[15]: https://docs.google.com/document/d/18hI56KJpvXtwWbc9QSaz9zzhJwIMnrJ-zkAaKS-W-8k/preview
[16]: https://docs.google.com/document/d/1Xq3owVt61HVkJqbLFHl73il6pcTy6PdPJJ7bSouQiQw/preview
[17]: https://docs.google.com/document/d/1wMPwVNBvsIriamcyBO5aNs7Cdr8lmbwLJ8GmZBAswF4/preview
[18]: https://docs.google.com/document/d/1wskYbA-czBt57oH9gEuGf3sWbTx7bfOiEIcDs36-heo/preview
[19]: https://prezi.com/view/THNPJGFVDUCWoM20syev/
[20]: https://behdad.org/doc/harfbuzz10years-slides.pdf
[21]: https://docs.google.com/document/d/1_vZrt97OorJ0jA1YzJ29LRcGr3YGrNJANdOABjVZGEs/preview
[10]: https://goo.gl/woyty

View file

@ -1,216 +0,0 @@
Most HarfBuzz developers do so on Linux or macOS. However, HarfBuzz is a
cross-platform library and it is important to ensure that it works on Windows
as well. In particular, we use this workflow to develop and test the HarfBuzz
Uniscribe shaper and DirectWrite shaper and font backend, all from Linux or
macOS.
This document provides instructions for cross-compiling HarfBuzz on Linux or
macOS, for Windows, using the MinGW toolchain, and running tests and utilties
under Wine.
We then discuss using native Windows Uniscribe or DirectWrite DLLs, which
allows you to test HarfBuzz's shaping against the Microsoft shaping engines
instead of those provided by Wine.
This document assumes that you are familiar with building HarfBuzz on Linux or
macOS.
You can build for 32bit or 64bit Windows. If your intention is to use a native
Uniscribe usp10.dll from Windows 7 or before, you would need to build for 32bit.
If you want to use a native DirectWrite DLL from Windows 10 or later, you would
need to build for 64bit.
We suggest you read to the end of this document before starting, as it provides
a few different ways to build and test HarfBuzz for Windows.
1. Install Wine.
- Fedora: `dnf install wine`.
- Ubuntu, 32bit: `apt install wine wine32`.
- Ubuntu, 64bit: `apt install wine wine64`.
- Mac: `brew install wine-stable`.
Note that to run Wine on Apple silicon systems, you need the Apple Rosetta translator.
Follow the instructions you got from brew. This should do it:
- `softwareupdate --install-rosetta --agree-to-license`
2. Install the `mingw-w64` cross-compiler.
- Fedora, 32bit: `dnf install mingw32-gcc-c++`
- Fedora, 64bit: `dnf install mingw64-gcc-c++`
- Ubuntu, 32bit: `apt install g++-mingw-w64-i686`
- Ubuntu, 64bit: `apt install g++-mingw-w64-x86-64`
- Mac: `brew install mingw-w64`
3. Install dependencies.
First, make sure you do not have the mingw32 harfbuzz package, as that will
override our own build with older `meson`:
- Fedora, 32bit: `dnf remove mingw32-harfbuzz`
- Fedora, 64bit: `dnf remove mingw64-harfbuzz`
Then install the actual dependencies:
- Fedora, 32bit: `dnf install mingw32-glib2 mingw32-cairo mingw32-freetype`
- Fedora, 64bit: `dnf install mingw64-glib2 mingw64-cairo mingw64-freetype`
If you cannot find these packages for your distribution, or you are on macOS,
you can skip to the next step, as meson will automatically download and build
the dependencies for you.
4. If you are familiar with `meson`, you can use the cross-compile files we
provide to find your way around. But we do not recommend this way. Read until
the end of this section before deciding which one to use.
- 32bit: `meson --cross-file=.ci/win32-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
- 64bit: `meson --cross-file=.ci/win64-cross-file.txt build-win -Dglib-enabled -Dcairo=enabled -Dgdi=enabled -Ddirectwrite=enabled`
In which case, you will proceed to run `ninja` as usual to build:
- `ninja -C build-win`
Or you can simply invoke the scripts we provide for our Continuous Integration
system, to configure and build HarfBuzz for you. This is the easiest way to
build HarfBuzz for Windows and how we build our Windows binaries:
- 32bit: `./.ci/build-win.sh 32 && ln -s build-win32 build-win`
- 64bit: `./.ci/build-win.sh 64 && ln -s build-win64 build-win`
This might take a while, since, if you do not have the dependencies installed,
meson will download and build them for you.
5. If everything succeeds, you should have the `hb-shape.exe`, `hb-view.exe`,
`hb-subset.exe`, and `hb-info.exe` executables in `build-win/util`.
6. Configure your wine to find system mingw libraries. While there, set it also
to find the built HarfBuzz DLLs:
- Fedora, 32bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/i686-w64-mingw32/sys-root/mingw/bin"`
- Fedora, 64bit: `export WINEPATH="$HOME/harfbuzz/build-win/src;/usr/x86_64-w64-mingw32/sys-root/mingw/bin"`
- Other systems: `export WINEPATH="$HOME/harfbuzz/build-win/src"`
Adjust for the path where you have built HarfBuzz. You might want to add this
to your `.bashrc` or `.zshrc` file.
Alternatively, can skip this step if commands are run through the `meson devenv`
command, which we will introduce in the next step. I personally find it more
convenient to set the `WINEPATH` variable, as it allows me to run the executables
directly from the shell.
7. Run the `hb-shape` executable under Wine:
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
Or using `meson devenv to do the same:
- `meson devenv -C build-win util/hb-shape.exe $PWD/perf/fonts/Roboto-Regular.ttf Test`
You probably will get lots of Wine warnings, but if all works fine, you
should see:
```
[gid57=0+1123|gid74=1+1086|gid88=2+1057|gid89=3+670]
```
You can make Wine less verbose, without hiding all errors, by setting:
- `export WINEDEBUG=fixme-all,warn-all,err-plugplay,err-seh,err-rpc,err-ntoskrnl,err-winediag,err-systray,err-hid`
Add this to your `.bashrc` or `.zshrc` file as well.
Next, let's try some non-Latin text. Unfortunately, the command-line parsing of
our cross-compiled glib is not quite Unicode-aware, at least when run under
Wine. So you will need to find some other way to feed Unicode text to the
shaper. There are three different ways you can try:
- `echo حرف | wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf`
- `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf -u 062D,0631,0641`
- `wine build-win/util/hb-shape.exe perf/fonts/Amiri-Regular.ttf --text-file harf.txt`
To get the Unicode codepoints for a string, you can use the `hb-unicode-decode`
utility:
```
$ test/shape/hb-unicode-decode حرف
U+062D,U+0631,U+0641
```
8. Next, let's try the `hb-view` utility. By default, `hb-view` outputs ANSI text,
which Wine will not display correctly. You can use the `-o` option to redirect the
output to a file, or just redirect the output using the shell, which will produce
a PNG file.
- `wine build-win/util/hb-view.exe perf/fonts/Roboto-Regular.ttf Test > test.png`
7. As noted, if your Linux has `binfmt_misc` enabled, you can run the executables
directly. If not, you can modify the cross-file to use the `exe_wrapper` option as
specified before.
- `build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test`
If that does not work, you can use the `wine` command as shown above.
10. You can try running the test suite. If on Linux with `binfmt_misc` enabled, you
can run the tests directly:
- `ninja -C build-win test`
For other situations, use `meson devenv`:
- `meson devenv -C build-win ninja test`
This might take a couple of minutes to run. Running under Wine is expensive, so
be patient.
If all goes well, tests should run. If all is well, you should probably see about
400 tests pass, some skipped, but none failing.
11. In the above testing situation, the `directwrite` test will be disabled
automatically upon detection of running under Wine. The reason the `directwrite`
test would otherwise fails is that we are running against the Wine-provided
DirectWrite DLL, which is an incomplete reimplementation of the DirectWrite API
by Wine, and not the real thing.
If you want to test the Uniscribe or DirectWrite shapers against the real
Uniscribe / DirectWrite, you can follow the instructions below.
11. Old Uniscribe: Assuming a 32bit build for now.
Bring a 32bit version of `usp10.dll` for yourself from
`C:\Windows\SysWOW64\usp10.dll` of your 64bit Windows installation,
or `C:\Windows\System32\usp10.dll` for 32bit Windows installation.
You want one from Windows 7 or earlier. One that is not just a proxy for
`TextShaping.dll`. Rule of thumb, your `usp10.dll` should have a size more
than 500kb.
Put the file in `~/.wine/drive_c/windows/syswow64/` so wine can find it.
You can now tell wine to use the native `usp10.dll`:
- `export WINEDLLOVERRIDES="usp10=n"`
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=uniscribe`
12. DirectWrite and new Uniscribe: You can use the same method to test the
DirectWrite shaper against the native DirectWrite DLL. Try with a 64bit build
this time.
Bring `TextShaping.dll`, `DWrite.dll`, and `usp10.dll` from your 64bit Windows
installation (`C:\Windows\System32`) to `~/.wine/drive_c/windows/system32/`.
You want the ones from Windows 10 or later. You might have some luck downloading
them from the internet, but be careful with the source. I had success with the
DLLs from [https://dllme.com](dllme.com), but I cannot vouch for the site.
You can now tell wine to use the native DirectWrite:
- `export WINEDLLOVERRIDES="textshaping,dwrite,usp10=n"`
- `wine build-win/util/hb-shape.exe perf/fonts/Roboto-Regular.ttf Test --shaper=directwrite`
If all works well, you should be able to rerun the tests and see all pass this time.
13. For some old instructions on how to test HarfBuzz's native Indic shaper against
Uniscribe, see: https://github.com/harfbuzz/harfbuzz/issues/3671
14. That's it! If you made it this far, you are now able to develop and test
HarfBuzz on Windows, from Linux or macOS. Enjoy!

View file

@ -3,21 +3,21 @@
- [ ] Open gitk and review changes since last release.
- [ ] Print all public API changes:
`git diff $(git describe | sed 's/-.*//').. src/*.h`
`git diff $(git describe | sed 's/-.*//').. src/*.h`
- [ ] Document them in NEWS.
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
All API and API semantic changes should be clearly marked as API additions, API changes, or API deletions.
- [ ] Document deprecations.
Ensure all new API / deprecations are listed correctly in docs/harfbuzz-sections.txt.
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
Ensure all new API / deprecations are in listed correctly in docs/harfbuzz-sections.txt.
If release added new API, add entry for new API index at the end of docs/harfbuzz-docs.xml.
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
Do NOT release.
If there's a backward-incompatible API change (including deletions for API used anywhere), that's a release blocker.
Do NOT release.
- [ ] Based on severity of changes, decide whether it's a minor or micro release number bump.
- [ ] Search for 'REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'.
- [ ] Make sure you have correct date and new version at the top of NEWS file.
@ -26,16 +26,12 @@
- [ ] Do a `meson test -Cbuild` so it both checks the tests and updates hb-version.h (use `git diff` to see if is really updated).
- [ ] Commit NEWS, meson.build, and src/hb-version.h, as well as any REPLACEME changes you made.
The commit message is simply the release number, e. g. "1.4.7"
The commit message is simply the release number, e. g. "1.4.7"
- [ ] Do a `meson dist -Cbuild` that runs the tests against the latest committed changes.
If it does not pass, something fishy is going on, reset the repo and start over.
If doesn't pass, something fishy is going on, reset the repo and start over.
- [ ] Tag the release and sign it: e.g. `git tag -s 1.4.7 -m 1.4.7`.
Enter your GPG password.
- [ ] Push the commit and tag out: `git push --follow-tags`.
- [ ] There should be a GitHub release automatically created.
When it does, go to that release page and add description.
The description should be the NEWS file additions.

View file

@ -90,16 +90,15 @@
<chapter id="integration-api">
<title>Integration API</title>
<xi:include href="xml/hb-cairo.xml"/>
<xi:include href="xml/hb-coretext.xml"/>
<xi:include href="xml/hb-directwrite.xml"/>
<xi:include href="xml/hb-ft.xml"/>
<xi:include href="xml/hb-fontations.xml"/>
<xi:include href="xml/hb-gdi.xml"/>
<xi:include href="xml/hb-glib.xml"/>
<xi:include href="xml/hb-graphite2.xml"/>
<xi:include href="xml/hb-icu.xml"/>
<xi:include href="xml/hb-uniscribe.xml"/>
<xi:include href="xml/hb-gdi.xml"/>
<xi:include href="xml/hb-directwrite.xml"/>
<xi:include href="xml/hb-cairo.xml"/>
</chapter>
<chapter id="style-api">
@ -121,11 +120,6 @@
<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="api-index-11-0-0"><title>Index of new symbols in 11.0.0</title><xi:include href="xml/api-index-11.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-4-0"><title>Index of new symbols in 10.4.0</title><xi:include href="xml/api-index-10.4.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-3-0"><title>Index of new symbols in 10.3.0</title><xi:include href="xml/api-index-10.3.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-2-0"><title>Index of new symbols in 10.2.0</title><xi:include href="xml/api-index-10.2.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-1-0"><title>Index of new symbols in 10.1.0</title><xi:include href="xml/api-index-10.1.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-10-0-0"><title>Index of new symbols in 10.0.0</title><xi:include href="xml/api-index-10.0.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-8-5-0"><title>Index of new symbols in 8.5.0</title><xi:include href="xml/api-index-8.5.0.xml"><xi:fallback /></xi:include></index>
<index id="api-index-8-4-0"><title>Index of new symbols in 8.4.0</title><xi:include href="xml/api-index-8.4.0.xml"><xi:fallback /></xi:include></index>

View file

@ -114,9 +114,6 @@ hb_glyph_position_t
hb_buffer_content_type_t
hb_buffer_flags_t
hb_buffer_cluster_level_t
HB_BUFFER_CLUSTER_LEVEL_IS_CHARACTERS
HB_BUFFER_CLUSTER_LEVEL_IS_GRAPHEMES
HB_BUFFER_CLUSTER_LEVEL_IS_MONOTONE
hb_segment_properties_t
hb_buffer_serialize_format_t
hb_buffer_serialize_flags_t
@ -184,10 +181,6 @@ uint8_t
HB_EXTERN
HB_DEPRECATED
HB_DEPRECATED_FOR
hb_malloc
hb_calloc
hb_realloc
hb_free
<SUBSECTION Private>
HB_H_IN
HB_OT_H_IN
@ -292,8 +285,6 @@ hb_paint_custom_palette_color_func_t
hb_paint_funcs_set_custom_palette_color_func
hb_paint_push_transform
hb_paint_push_font_transform
hb_paint_push_inverse_font_transform
hb_paint_pop_transform
hb_paint_color_glyph
hb_paint_push_clip_glyph
@ -341,10 +332,6 @@ hb_font_funcs_set_glyph_shape_func
hb_font_get_glyph_v_kerning
hb_font_get_glyph_v_kerning_func_t
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION
hb_directwrite_face_get_font_face
hb_directwrite_font_get_dw_font
hb_ft_font_get_face
hb_graphite2_font_get_gr_font
</SECTION>
<SECTION>
@ -353,23 +340,15 @@ HB_CORETEXT_TAG_KERX
HB_CORETEXT_TAG_MORT
HB_CORETEXT_TAG_MORX
hb_coretext_face_create
hb_coretext_face_create_from_file_or_fail
hb_coretext_face_create_from_blob_or_fail
hb_coretext_font_create
hb_coretext_face_get_cg_font
hb_coretext_font_get_ct_font
hb_coretext_font_set_funcs
</SECTION>
<SECTION>
<FILE>hb-directwrite</FILE>
hb_directwrite_face_create
hb_directwrite_face_create_from_file_or_fail
hb_directwrite_face_create_from_blob_or_fail
hb_directwrite_face_get_dw_font_face
hb_directwrite_font_create
hb_directwrite_font_get_dw_font_face
hb_directwrite_font_set_funcs
hb_directwrite_face_get_font_face
</SECTION>
<SECTION>
@ -377,11 +356,6 @@ hb_directwrite_font_set_funcs
hb_face_count
hb_face_t
hb_face_create
hb_face_create_or_fail
hb_face_create_or_fail_using
hb_face_create_from_file_or_fail
hb_face_create_from_file_or_fail_using
hb_face_list_loaders
hb_reference_table_func_t
hb_face_create_for_tables
hb_face_get_empty
@ -475,8 +449,6 @@ hb_font_get_serial
hb_font_changed
hb_font_set_funcs
hb_font_set_funcs_data
hb_font_set_funcs_using
hb_font_list_funcs
hb_font_subtract_glyph_origin_for_direction
hb_font_funcs_create
hb_font_funcs_get_empty
@ -536,23 +508,15 @@ hb_font_extents_t
hb_glyph_extents_t
</SECTION>
<SECTION>
<FILE>hb-fontations</FILE>
hb_fontations_font_set_funcs
</SECTION>
<SECTION>
<FILE>hb-ft</FILE>
hb_ft_face_create
hb_ft_face_create_cached
hb_ft_face_create_referenced
hb_ft_face_create_from_file_or_fail
hb_ft_face_create_from_blob_or_fail
hb_ft_font_create
hb_ft_font_create_referenced
hb_ft_font_changed
hb_ft_font_get_ft_face
hb_ft_font_get_face
hb_ft_font_lock_face
hb_ft_font_unlock_face
hb_ft_font_set_load_flags
@ -578,6 +542,7 @@ hb_glib_blob_create
<FILE>hb-graphite2</FILE>
HB_GRAPHITE2_TAG_SILF
hb_graphite2_face_get_gr_face
hb_graphite2_font_get_gr_font
</SECTION>
<SECTION>
@ -704,7 +669,6 @@ hb_ot_layout_table_get_script_tags
hb_ot_layout_table_get_lookup_count
hb_ot_layout_table_select_script
hb_ot_shape_plan_collect_lookups
hb_ot_shape_plan_get_feature_tags
hb_ot_layout_language_get_required_feature_index
HB_OT_MAX_TAGS_PER_LANGUAGE
HB_OT_MAX_TAGS_PER_SCRIPT
@ -832,10 +796,8 @@ hb_set_t
<FILE>hb-shape</FILE>
hb_shape
hb_shape_full
hb_shape_list_shapers
<SUBSECTION Private>
hb_shape_justify
</SUBSECTION>
hb_shape_list_shapers
</SECTION>
<SECTION>
@ -933,8 +895,6 @@ hb_subset_input_pin_axis_location
hb_subset_input_pin_axis_to_default
hb_subset_input_get_axis_range
hb_subset_input_set_axis_range
hb_subset_axis_range_from_string
hb_subset_axis_range_to_string
hb_subset_or_fail
hb_subset_plan_create_or_fail
hb_subset_plan_reference
@ -950,15 +910,11 @@ hb_subset_flags_t
hb_subset_input_t
hb_subset_sets_t
hb_subset_plan_t
hb_subset_serialize_link_t
hb_subset_serialize_object_t
hb_subset_serialize_or_fail
<SUBSECTION Private>
hb_link_t
hb_object_t
hb_subset_repack_or_fail
hb_subset_input_override_name_table
hb_subset_cff_get_charstring_data
hb_subset_cff_get_charstrings_index
hb_subset_cff2_get_charstring_data
hb_subset_cff2_get_charstrings_index
</SECTION>
<SECTION>

View file

@ -518,6 +518,18 @@
<type>hb_font_t</type> font object. Core Text uses this value to
implement optical scaling.
</para>
<para>
When integrating your client code with Core Text, it is
important to recognize that Core Text <literal>points</literal>
are not typographic points (standardized at 72 per inch) as the
term is used elsewhere in OpenType. Instead, Core Text points
are CSS points, which are standardized at 96 per inch.
</para>
<para>
HarfBuzz's font functions take this distinction into account,
but it can be an easy detail to miss in cross-platform
code.
</para>
<para>
As a final note, you may notice a reference to an optional
<literal>coretext</literal> shaper back-end in the <xref

View file

@ -1,12 +1,11 @@
project('harfbuzz', ['c', 'cpp'],
meson_version: '>= 0.60.0',
version: '11.1.0',
project('harfbuzz', 'c', 'cpp',
meson_version: '>= 0.55.0',
version: '10.0.1',
default_options: [
'cpp_eh=none', # Just to support msvc, we are passing -fno-exceptions also anyway
# 'cpp_rtti=false', # Do NOT enable, wraps inherit it and ICU needs RTTI
'cpp_std=c++11',
'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548
'buildtype=debugoptimized',
],
)
@ -32,16 +31,11 @@ pkgmod = import('pkgconfig')
cpp = meson.get_compiler('cpp')
null_dep = dependency('', required: false)
# Includes Microsoft Clang compiler with GNU arguments, see
# https://github.com/harfbuzz/harfbuzz/pull/4394
cpp_is_microsoft_compiler = host_machine.system() == 'windows' and cpp.get_define('_MSC_FULL_VER') != ''
# Only perform these checks if cpp_std is c++11 as setting -std directly
# produces a warning from meson.
if get_option('cpp_std') == 'c++11'
# Enforce C++14 requirement for MSVC STL
if cpp.get_id() == 'clang' and cpp_is_microsoft_compiler
if cpp.get_id() == 'clang' and cpp.get_define('_MSC_FULL_VER') != ''
add_project_arguments('-std=c++14', language: 'cpp')
elif cpp.get_id() == 'clang-cl'
# Clang-cl produces a warning when using -std=c++14, but not when using /std:c++14
@ -108,36 +102,44 @@ check_funcs = [
m_dep = cpp.find_library('m', required: false)
# Painful hack to handle multiple dependencies but also respect options
if get_option('freetype').disabled()
freetype_dep = dependency('', required: false)
else
if meson.version().version_compare('>=0.60.0')
# Sadly, FreeType's versioning schemes are different between pkg-config and CMake
# Try pkg-config name
# pkg-config: freetype2, cmake: Freetype
freetype_dep = dependency('freetype2',
version: freetype_min_version,
method: 'pkg-config',
required: false,
allow_fallback: false)
if not freetype_dep.found()
# Try cmake name
freetype_dep = dependency('Freetype',
freetype_dep = dependency('FreeType',
version: freetype_min_version_actual,
method: 'cmake',
required: false,
allow_fallback: false)
# Subproject fallback
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
endif
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', version: freetype_min_version, 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', version: freetype_min_version_actual, 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_proj = subproject('freetype2',
version: freetype_min_version_actual,
freetype_dep = dependency('freetype2',
version: freetype_min_version,
method: 'pkg-config',
required: get_option('freetype'),
default_options: ['harfbuzz=disabled'])
if freetype_proj.found()
freetype_dep = freetype_proj.get_variable('freetype_dep')
else
freetype_dep = dependency('', required: false)
endif
default_options: ['harfbuzz=disabled'],
allow_fallback: true)
endif
endif
endif
@ -150,12 +152,38 @@ wasm_dep = cpp.find_library('iwasm', required: get_option('wasm'))
# How to check whether iwasm was built, and hence requires, LLVM?
#llvm_dep = cpp.find_library('LLVM-15', required: get_option('wasm'))
# pkg-config: icu-uc, cmake: ICU but with components
icu_dep = dependency('icu-uc', 'ICU',
version: icu_min_version,
components: 'uc',
required: get_option('icu'),
allow_fallback: true)
if meson.version().version_compare('>=0.60.0')
# pkg-config: icu-uc, cmake: ICU but with components
icu_dep = dependency('icu-uc', 'ICU',
version: icu_min_version,
components: 'uc',
required: get_option('icu'),
allow_fallback: true)
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', version: icu_min_version, 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', version: icu_min_version, 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',
version: icu_min_version,
method: 'pkg-config',
required: get_option('icu'))
endif
endif
endif
if icu_dep.found() and icu_dep.version().version_compare('>=75.1') and (get_option('cpp_std') == 'c++11' or get_option('cpp_std') == 'c++14')
cpp17_arg = cpp.get_argument_syntax() == 'msvc' ? '/std:c++17' : '-std=c++17'
@ -199,18 +227,16 @@ endif
chafa_dep = dependency('chafa', version: chafa_min_version, required: get_option('chafa'))
fontations_dep_found = false
if get_option('fontations').enabled()
add_languages(['rust'], native: false, required : true)
fontations_dep_found = true
endif
conf = configuration_data()
incconfig = include_directories('.')
add_project_arguments('-DHAVE_CONFIG_H', language: ['c', 'cpp'])
cpp_args = []
warn_cflags = [
'-Wno-non-virtual-dtor',
]
cpp_args = cpp.get_supported_arguments(warn_cflags)
if glib_dep.found()
conf.set('HAVE_GLIB', 1)
@ -246,10 +272,6 @@ if chafa_dep.found()
conf.set('HAVE_CHAFA', 1)
endif
if fontations_dep_found
conf.set('HAVE_FONTATIONS', 1)
endif
if wasm_dep.found()
conf.set('HAVE_WASM', 1)
conf.set('HB_WASM_MODULE_DIR', '"'+get_option('prefix')+'/'+get_option('libdir')+'/harfbuzz/wasm"')
@ -293,13 +315,13 @@ endif
gdi_uniscribe_deps = []
# GDI (Uniscribe) (Windows)
if host_machine.system() == 'windows' and not get_option('gdi').disabled()
if (get_option('gdi').enabled() and
if (get_option('directwrite').enabled() and
not (cpp.has_header('usp10.h') and cpp.has_header('windows.h')))
error('GDI/Uniscribe was enabled explicitly, but required headers are missing.')
endif
gdi_deps_found = true
foreach usplib : ['usp10', 'gdi32', 'rpcrt4', 'user32']
foreach usplib : ['usp10', 'gdi32', 'rpcrt4']
dep = cpp.find_library(usplib, required: get_option('gdi'))
gdi_deps_found = gdi_deps_found and dep.found()
gdi_uniscribe_deps += dep
@ -311,16 +333,13 @@ if host_machine.system() == 'windows' and not get_option('gdi').disabled()
endif
endif
directwrite_dep = []
# DirectWrite (Windows)
if host_machine.system() == 'windows' and not get_option('directwrite').disabled()
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_3.h')
if get_option('directwrite').enabled() and not cpp.has_header('dwrite_1.h')
error('DirectWrite was enabled explicitly, but required header is missing.')
endif
directwrite_dep = cpp.find_library('dwrite', required: get_option('directwrite'))
if directwrite_dep.found()
conf.set('HAVE_DIRECTWRITE', 1)
endif
conf.set('HAVE_DIRECTWRITE', 1)
endif
# CoreText (macOS)
@ -445,11 +464,6 @@ configure_file(output: 'config.h', configuration: conf)
alias_target('lib', libharfbuzz)
alias_target('libs', libharfbuzz, libharfbuzz_subset)
# Re glib, see https://github.com/harfbuzz/harfbuzz/issues/4153#issuecomment-2646347531
add_test_setup('default',
exclude_suites: ['google-benchmark'],
is_default: glib_dep.type_name() != 'internal' and not meson.is_subproject())
build_summary = {
'Directories':
{'prefix': get_option('prefix'),
@ -467,7 +481,6 @@ build_summary = {
'Font callbacks (the more the merrier)':
{'Builtin' : true,
'FreeType': conf.get('HAVE_FREETYPE', 0) == 1,
'Fontations': conf.get('HAVE_FONTATIONS', 0) == 1,
},
'Dependencies used for command-line utilities':
{'Cairo': conf.get('HAVE_CAIRO', 0) == 1,

View file

@ -15,12 +15,10 @@ option('graphite2', type: 'feature', value: 'disabled',
description: 'Enable Graphite2 complementary shaper')
option('freetype', type: 'feature', value: 'auto',
description: 'Enable freetype interop helpers')
option('fontations', type: 'feature', value: 'disabled',
description: 'Enabled fontations font functions')
option('gdi', type: 'feature', value: 'disabled',
description: 'Enable GDI helpers and Uniscribe shaper backend (Windows only)')
option('directwrite', type: 'feature', value: 'disabled',
description: 'Enable DirectWrite shaper backend on Windows')
description: 'Enable DirectWrite shaper backend on Windows (experimental)')
option('coretext', type: 'feature', value: 'disabled',
description: 'Enable CoreText shaper backend on macOS')
option('wasm', type: 'feature', value: 'disabled',

View file

@ -4,21 +4,17 @@ Benchmarks are implemented using [Google Benchmark](https://github.com/google/be
To build the benchmarks in this directory you need to set the benchmark
option while configuring the build with meson:
```
meson build -Dbenchmark=enabled --buildtype=release
```
or:
```
meson build -Dbenchmark=enabled --buildtype=debugoptimized
```
The default build type is `debugoptimized`, which is good enough for
benchmarking, but you can also get the fastest mode with `release`
build type:
```
meson build -Dbenchmark=enabled --buildtype=release
```
You should, of course, enable features you want to benchmark, like
`-Dfreetype`, `-Dfontations`, `-Dcoretext`, etc.
Then build a specific benchmark binaries with ninja, eg.:
Then build a specific benchmark binaries with ninja:
```
ninja -Cbuild perf/benchmark-set
```
@ -37,47 +33,22 @@ It's possible to filter the benchmarks being run and customize the output
via flags to the benchmark binary. See the
[Google Benchmark User Guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md#user-guide) for more details.
The most useful benchmark is `benchmark-font`. You can provide custom fonts to it too.
For example, to run only the "paint" benchmarks, against a given font, you can do:
```
./build/perf/benchmark-font NotoColorEmoji-Regular.ttf --benchmark_filter="paint"
```
Some useful options are: `--benchmark_repetitions=5` to run the benchmark 5 times,
`--benchmark_min_time=.1s` to run the benchmark for at least .1 seconds (defaults
to .5s), and `--benchmark_filter=...` to filter the benchmarks by regular expression.
To compare before/after benchmarks, you need to save the benchmark results in files
for both runs. Use `--benchmark_out=results.json` to output the results in JSON format.
Then you can use:
```
./subprojects/benchmark-1.8.4/tools/compare.py benchmarks before.json after.json
```
Substitute your version of benchmark instead of 1.8.4.
# Profiling
If you like to disable optimizations and enable frame pointers for better profiling output,
you can do so with the following meson command:
Configure the build to include debug information for profiling:
```
CXXFLAGS="-fno-omit-frame-pointer" meson --reconfigure build -Dbenchmark=enabled --buildtype=debug
ninja -Cbuild
```
However, this will slow down the benchmarks significantly and might give you inaccurate
information as to where to optimize. It's better to profile the `debugoptimized` build (the default).
Then run the benchmark with perf:
```
perf record -g build/perf/benchmark-subset --benchmark_filter="BM_subset_codepoints/subset_notocjk/100000" --benchmark_repetitions=5
```
You probably want to filter to a specific benchmark of interest and set the number of
repititions high enough to get a good sampling of profile data.
You probably want to filter to a specific benchmark of interest and set the number of repititions high enough to get a good sampling of profile data.
Finally view the profile with:
```
perf report
```
Another useful `perf` tool is the `perf stat` command, which can give you a quick overview
of the performance of a benchmark, as well as stalled cycles, cache misses, and mispredicted branches.

View file

@ -1,4 +1,17 @@
#include "hb-benchmark.hh"
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
@ -21,6 +34,8 @@ struct test_input_t
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
enum backend_t { HARFBUZZ, FREETYPE };
enum operation_t
{
nominal_glyphs,
@ -79,15 +94,16 @@ _draw_funcs_create (void)
}
static void BM_Font (benchmark::State &state,
bool is_var, const char * backend,
operation_t operation,
bool is_var, backend_t backend, operation_t operation,
const test_input_t &test_input)
{
hb_font_t *font;
unsigned num_glyphs;
{
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
num_glyphs = hb_face_get_glyph_count (face);
font = hb_font_create (face);
hb_face_destroy (face);
@ -99,12 +115,17 @@ static void BM_Font (benchmark::State &state,
hb_font_set_variations (font, &wght, 1);
}
bool ret = hb_font_set_funcs_using (font, backend);
if (!ret)
switch (backend)
{
state.SkipWithError("Backend failed to initialize for font.");
hb_font_destroy (font);
return;
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
}
switch (operation)
@ -187,17 +208,24 @@ static void BM_Font (benchmark::State &state,
{
for (auto _ : state)
{
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
bool ret = hb_font_set_funcs_using (font, backend);
if (!ret)
switch (backend)
{
state.SkipWithError("Backend failed to initialize for font.");
hb_font_destroy (font);
return;
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
}
hb_buffer_t *buffer = hb_buffer_create ();
@ -217,7 +245,8 @@ static void BM_Font (benchmark::State &state,
hb_font_destroy (font);
}
static void test_backend (const char *backend,
static void test_backend (backend_t backend,
const char *backend_name,
bool variable,
operation_t op,
const char *op_name,
@ -231,7 +260,7 @@ static void test_backend (const char *backend,
strcat (name, p ? p + 1 : test_input.font_path);
strcat (name, variable ? "/var" : "");
strcat (name, "/");
strcat (name, backend);
strcat (name, backend_name);
benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
->Unit(time_unit);
@ -241,7 +270,6 @@ static void test_operation (operation_t op,
const char *op_name,
benchmark::TimeUnit time_unit)
{
const char **supported_backends = hb_font_list_funcs ();
for (unsigned i = 0; i < num_tests; i++)
{
auto& test_input = tests[i];
@ -249,8 +277,10 @@ static void test_operation (operation_t op,
{
bool is_var = (bool) variable;
for (const char **backend = supported_backends; *backend; backend++)
test_backend (*backend, is_var, op, op_name, time_unit, test_input);
test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
#endif
}
}
}
@ -275,7 +305,7 @@ int main(int argc, char** argv)
TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond);
TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
TEST_OPERATION (draw_glyph, benchmark::kMillisecond);
TEST_OPERATION (draw_glyph, benchmark::kMicrosecond);
TEST_OPERATION (paint_glyph, benchmark::kMillisecond);
TEST_OPERATION (load_face_and_shape, benchmark::kMicrosecond);

View file

@ -1,4 +1,11 @@
#include "hb-benchmark.hh"
/*
* Benchmarks for hb_map_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
void RandomMap(unsigned size, hb_map_t* out, hb_set_t* key_sample) {
hb_map_clear(out);

View file

@ -1,4 +1,9 @@
#include "hb-benchmark.hh"
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include "hb-ot.h"
static void BM_hb_ot_tags_from_script_and_language (benchmark::State& state,
hb_script_t script,

View file

@ -1,4 +1,11 @@
#include "hb-benchmark.hh"
/*
* Benchmarks for hb_set_t operations.
*/
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstdlib>
#include "hb.h"
void RandomSet(unsigned size, unsigned max_value, hb_set_t* out) {
hb_set_clear(out);

View file

@ -1,4 +1,17 @@
#include "hb-benchmark.hh"
#include "benchmark/benchmark.h"
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <cassert>
#include "hb.h"
#include "hb-ot.h"
#ifdef HAVE_FREETYPE
#include "hb-ft.h"
#endif
#define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
@ -6,52 +19,76 @@ struct test_input_t
{
const char *font_path;
const char *text_path;
bool is_variable;
} default_tests[] =
{
{"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
"perf/texts/fa-thelittleprince.txt"},
"perf/texts/fa-thelittleprince.txt",
false},
{"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
"perf/texts/fa-words.txt"},
"perf/texts/fa-words.txt",
false},
{"perf/fonts/Amiri-Regular.ttf",
"perf/texts/fa-thelittleprince.txt"},
"perf/texts/fa-thelittleprince.txt",
false},
{SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
"perf/texts/hi-words.txt"},
"perf/texts/hi-words.txt",
false},
{"perf/fonts/Roboto-Regular.ttf",
"perf/texts/en-thelittleprince.txt"},
"perf/texts/en-thelittleprince.txt",
false},
{"perf/fonts/Roboto-Regular.ttf",
"perf/texts/en-words.txt"},
"perf/texts/en-words.txt",
false},
{SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
"perf/texts/react-dom.txt"},
"perf/texts/en-thelittleprince.txt",
true},
};
static test_input_t *tests = default_tests;
static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
const char *variation = nullptr;
enum backend_t { HARFBUZZ, FREETYPE };
static void BM_Shape (benchmark::State &state,
const char *shaper,
bool is_var,
backend_t backend,
const test_input_t &input)
{
hb_font_t *font;
{
hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (input.font_path, 0);
assert (face);
hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
font = hb_font_create (face);
hb_face_destroy (face);
}
if (variation)
if (is_var)
{
hb_variation_t var;
hb_variation_from_string (variation, -1, &var);
hb_font_set_variations (font, &var, 1);
hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
hb_font_set_variations (font, &wght, 1);
}
switch (backend)
{
case HARFBUZZ:
hb_ot_font_set_funcs (font);
break;
case FREETYPE:
#ifdef HAVE_FREETYPE
hb_ft_font_set_funcs (font);
#endif
break;
}
hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
@ -71,8 +108,7 @@ static void BM_Shape (benchmark::State &state,
hb_buffer_clear_contents (buf);
hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
hb_buffer_guess_segment_properties (buf);
const char *shaper_list[] = {shaper, nullptr};
hb_shape_full (font, buf, nullptr, 0, shaper_list);
hb_shape (font, buf, nullptr, 0);
unsigned skip = end - text + 1;
text_length -= skip;
@ -85,8 +121,10 @@ static void BM_Shape (benchmark::State &state,
hb_font_destroy (font);
}
static void test_shaper (const char *shaper,
const test_input_t &test_input)
static void test_backend (backend_t backend,
const char *backend_name,
bool variable,
const test_input_t &test_input)
{
char name[1024] = "BM_Shape";
const char *p;
@ -96,10 +134,11 @@ static void test_shaper (const char *shaper,
strcat (name, "/");
p = strrchr (test_input.text_path, '/');
strcat (name, p ? p + 1 : test_input.text_path);
strcat (name, variable ? "/var" : "");
strcat (name, "/");
strcat (name, shaper);
strcat (name, backend_name);
benchmark::RegisterBenchmark (name, BM_Shape, shaper, test_input)
benchmark::RegisterBenchmark (name, BM_Shape, variable, backend, test_input)
->Unit(benchmark::kMillisecond);
}
@ -107,25 +146,35 @@ int main(int argc, char** argv)
{
benchmark::Initialize(&argc, argv);
test_input_t static_test = {};
if (argc > 2)
{
static_test.font_path = argv[1];
static_test.text_path = argv[2];
tests = &static_test;
num_tests = 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].is_variable = true;
tests[i].font_path = argv[1 + i * 2];
tests[i].text_path = argv[2 + i * 2];
}
}
if (argc > 3)
variation = argv[3];
for (unsigned i = 0; i < num_tests; i++)
{
auto& test_input = tests[i];
const char **shapers = hb_shape_list_shapers ();
for (const char **shaper = shapers; *shaper; shaper++)
test_shaper (*shaper, test_input);
for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
{
bool is_var = (bool) variable;
test_backend (HARFBUZZ, "hb", is_var, test_input);
#ifdef HAVE_FREETYPE
test_backend (FREETYPE, "ft", is_var, test_input);
#endif
}
}
benchmark::RunSpecifiedBenchmarks();
benchmark::Shutdown();
if (tests != default_tests)
free (tests);
}

View file

@ -1,4 +1,13 @@
#include "hb-benchmark.hh"
#include "benchmark/benchmark.h"
#include <cassert>
#include <cstring>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "hb-subset.h"
enum operation_t
{
@ -139,8 +148,10 @@ static void BM_subset (benchmark::State &state,
if (!cached_font_path || strcmp (cached_font_path, test_input.font_path))
{
face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
assert (face);
hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
assert (blob);
face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
face = preprocess_face (face);

View file

@ -1,64 +0,0 @@
/*
* Copyright © 2024 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.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_BENCHMARK_HH
#define HB_BENCHMARK_HH
#include <hb-config.hh>
#include <hb.h>
#include <hb-subset.h>
#include <hb-ot.h>
#ifdef HAVE_FREETYPE
#include <hb-ft.h>
#endif
#ifdef HAVE_FONTATIONS
#include <hb-fontations.h>
#endif
#ifdef HAVE_CORETEXT
#include <hb-coretext.h>
#endif
#include <benchmark/benchmark.h>
#include <cassert>
#include <cstdlib>
#include <cstring>
HB_BEGIN_DECLS
static inline hb_face_t *
hb_benchmark_face_create_from_file_or_fail (const char *font_path,
unsigned face_index)
{
return hb_face_create_from_file_or_fail_using (font_path, face_index, nullptr);
}
HB_END_DECLS
#endif /* HB_BENCHMARK_HH */

View file

@ -1,45 +0,0 @@
#include <hb.h>
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "Usage: %s font-file [font-funcs] [wght]\n", argv[0]);
return 1;
}
hb_face_t *face = hb_face_create_from_file_or_fail (argv[1], 0);
if (!face)
{
fprintf (stderr, "Failed to create face\n");
return 1;
}
hb_font_t *font = hb_font_create (face);
if (argc > 2)
hb_font_set_funcs_using (font, argv[2]);
if (argc > 3)
{
hb_variation_t variations[] = {
{ HB_TAG ('w', 'g', 'h', 't'), atoi (argv[3]) },
};
hb_font_set_variations (font, variations, 1);
}
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
unsigned glyph_count = hb_face_get_glyph_count (face);
for (unsigned gid = 0; gid < glyph_count; gid++)
hb_font_draw_glyph (font, gid, funcs, NULL);
hb_draw_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
return 0;
}

View file

@ -1,45 +0,0 @@
#include <hb.h>
#include <stdlib.h>
#include <stdio.h>
int main (int argc, char **argv)
{
if (argc < 2)
{
fprintf (stderr, "Usage: %s font-file [font-funcs] [wght]\n", argv[0]);
return 1;
}
hb_face_t *face = hb_face_create_from_file_or_fail (argv[1], 0);
if (!face)
{
fprintf (stderr, "Failed to create face\n");
return 1;
}
hb_font_t *font = hb_font_create (face);
if (argc > 2)
hb_font_set_funcs_using (font, argv[2]);
if (argc > 3)
{
hb_variation_t variations[] = {
{ HB_TAG ('w', 'g', 'h', 't'), atoi (argv[3]) },
};
hb_font_set_variations (font, variations, 1);
}
hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
unsigned glyph_count = hb_face_get_glyph_count (face);
for (unsigned gid = 0; gid < glyph_count; gid++)
hb_font_paint_glyph (font, gid, funcs, NULL, 0, 0);
hb_paint_funcs_destroy (funcs);
hb_font_destroy (font);
hb_face_destroy (face);
return 0;
}

View file

@ -1,54 +1,62 @@
google_benchmark = subproject('google-benchmark')
google_benchmark_dep = google_benchmark.get_variable('google_benchmark_dep')
benchmarks = [
'benchmark-font.cc',
'benchmark-map.cc',
'benchmark-ot.cc',
'benchmark-set.cc',
'benchmark-shape.cc',
]
foreach source : benchmarks
benchmark_name = source.split('.')[0]
benchmark(benchmark_name, executable(benchmark_name, source,
dependencies: [
google_benchmark_dep, freetype_dep, coretext_deps,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
endforeach
benchmarks_subset = [
'benchmark-subset.cc',
]
foreach source : benchmarks_subset
benchmark_name = source.split('.')[0]
benchmark(benchmark_name, executable(benchmark_name, source,
dependencies: [
google_benchmark_dep, freetype_dep, coretext_deps,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz, libharfbuzz_subset],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
endforeach
hb_draw_all = executable('hb-draw-all', ['hb-draw-all.c'],
cpp_args: cpp_args,
benchmark('benchmark-font', executable('benchmark-font', 'benchmark-font.cc',
dependencies: [
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
)
meson.override_find_program('hb-draw-all', hb_draw_all)
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
hb_paint_all = executable('hb-paint-all', ['hb-paint-all.c'],
cpp_args: cpp_args,
benchmark('benchmark-map', executable('benchmark-map', 'benchmark-map.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
)
meson.override_find_program('hb-paint-all', hb_paint_all)
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-ot', executable('benchmark-ot', 'benchmark-ot.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-set', executable('benchmark-set', 'benchmark-set.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-shape', executable('benchmark-shape', 'benchmark-shape.cc',
dependencies: [
google_benchmark_dep, freetype_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)
benchmark('benchmark-subset', executable('benchmark-subset', 'benchmark-subset.cc',
dependencies: [
google_benchmark_dep,
],
cpp_args: [],
include_directories: [incconfig, incsrc],
link_with: [libharfbuzz, libharfbuzz_subset],
install: false,
), workdir: meson.current_source_dir() / '..', timeout: 100)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -941,12 +941,10 @@ struct CBDT
}
}
bool has_data () const { return cbdt->version.major; }
bool has_data () const { return cbdt.get_length (); }
bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
{
if (!has_data ()) return false;
hb_glyph_extents_t extents;
hb_glyph_extents_t pixel_extents;
hb_blob_t *blob = reference_png (font, glyph);

View file

@ -29,15 +29,11 @@
#define OT_COLOR_COLR_COLR_HH
#include "../../../hb.hh"
#include "../../../hb-decycler.hh"
#include "../../../hb-open-type.hh"
#include "../../../hb-ot-var-common.hh"
#include "../../../hb-paint.hh"
#include "../../../hb-paint-bounded.hh"
#include "../../../hb-paint-extents.hh"
#include "../CPAL/CPAL.hh"
/*
* COLR -- Color
* https://docs.microsoft.com/en-us/typography/opentype/spec/colr
@ -48,12 +44,6 @@ namespace OT {
struct hb_paint_context_t;
}
struct hb_colr_scratch_t
{
hb_paint_bounded_context_t paint_bounded;
hb_paint_extents_context_t paint_extents;
};
namespace OT {
struct COLR;
@ -76,11 +66,11 @@ public:
hb_paint_funcs_t *funcs;
void *data;
hb_font_t *font;
hb_array_t<const BGRAColor> palette;
unsigned int palette_index;
hb_color_t foreground;
ItemVarStoreInstancer &instancer;
hb_decycler_t glyphs_decycler;
hb_decycler_t layers_decycler;
hb_map_t current_glyphs;
hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
@ -95,12 +85,7 @@ public:
funcs (funcs_),
data (data_),
font (font_),
palette (
#ifndef HB_NO_COLOR
// https://github.com/harfbuzz/harfbuzz/issues/5116
font->face->table.CPAL->get_palette_colors (palette_ < font->face->table.CPAL->get_palette_count () ? palette_ : 0)
#endif
),
palette_index (palette_),
foreground (foreground_),
instancer (instancer_)
{ }
@ -114,7 +99,12 @@ public:
if (color_index != 0xffff)
{
if (!funcs->custom_palette_color (data, color_index, &color))
color = palette[color_index];
{
unsigned int clen = 1;
hb_face_t *face = hb_font_get_face (font);
hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
}
*is_foreground = false;
}
@ -940,9 +930,9 @@ struct PaintGlyph
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
c->funcs->push_inverse_font_transform (c->data, c->font);
c->funcs->push_inverse_root_transform (c->data, c->font);
c->funcs->push_clip_glyph (c->data, gid, c->font);
c->funcs->push_font_transform (c->data, c->font);
c->funcs->push_root_transform (c->data, c->font);
c->recurse (this+paint);
c->funcs->pop_transform (c->data);
c->funcs->pop_clip (c->data);
@ -1013,7 +1003,7 @@ struct PaintTransform
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
(this+transform).paint_glyph (c); // This does a push_transform()
(this+transform).paint_glyph (c);
c->recurse (this+src);
c->funcs->pop_transform (c->data);
}
@ -1519,12 +1509,10 @@ struct PaintComposite
void paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
c->funcs->push_group (c->data);
c->recurse (this+backdrop);
c->funcs->push_group (c->data);
c->recurse (this+src);
c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
}
HBUINT8 format; /* format = 32 */
@ -1622,7 +1610,7 @@ struct ClipBox
void closurev1 (hb_colrv1_closure_context_t* c) const
{
switch (u.format) {
case 2: u.format2.closurev1 (c); return;
case 2: u.format2.closurev1 (c);
default:return;
}
}
@ -2070,7 +2058,7 @@ struct delta_set_index_map_subset_plan_t
unsigned outer = (*var_idx) >> 16;
unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
outer_bit_count = hb_max (bit_count, outer_bit_count);
unsigned inner = (*var_idx) & 0xFFFF;
bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
inner_bit_count = hb_max (bit_count, inner_bit_count);
@ -2089,12 +2077,10 @@ struct COLR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
bool has_data () const { return has_v0_data () || version; }
bool has_v0_data () const { return numBaseGlyphs; }
bool has_v1_data () const
{
if (version < 1)
if (version != 1)
return false;
hb_barrier ();
@ -2124,53 +2110,7 @@ struct COLR
{
accelerator_t (hb_face_t *face)
{ colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
~accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_colr_scratch_t ();
hb_free (scratch);
}
colr.destroy ();
}
bool has_data () const { return colr->has_data (); }
#ifndef HB_NO_PAINT
bool
get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const
{
if (unlikely (!has_data ())) return false;
hb_colr_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = colr->get_extents (font, glyph, extents, *scratch);
release_scratch (scratch);
return ret;
}
bool paint_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_paint_funcs_t *funcs, void *data,
unsigned int palette_index,
hb_color_t foreground,
bool clip = true) const
{
if (unlikely (!has_data ())) return false;
hb_colr_scratch_t *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = colr->paint_glyph (font, glyph, funcs, data, palette_index, foreground, clip, *scratch);
release_scratch (scratch);
return ret;
}
#endif
~accelerator_t () { this->colr.destroy (); }
bool is_valid () { return colr.get_blob ()->length; }
@ -2194,45 +2134,15 @@ struct COLR
const ItemVariationStore &get_var_store () const
{ return colr->get_var_store (); }
const ItemVariationStore *get_var_store_ptr () const
{ return colr->get_var_store_ptr (); }
bool has_delta_set_index_map () const
{ return colr->has_delta_set_index_map (); }
const DeltaSetIndexMap &get_delta_set_index_map () const
{ return colr->get_delta_set_index_map (); }
const DeltaSetIndexMap *get_delta_set_index_map_ptr () const
{ return colr->get_delta_set_index_map_ptr (); }
private:
hb_colr_scratch_t *acquire_scratch () const
{
hb_colr_scratch_t *scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_colr_scratch_t *) hb_calloc (1, sizeof (hb_colr_scratch_t));
if (unlikely (!scratch))
return nullptr;
}
return scratch;
}
void release_scratch (hb_colr_scratch_t *scratch) const
{
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_colr_scratch_t ();
hb_free (scratch);
}
}
public:
hb_blob_ptr_t<COLR> colr;
private:
mutable hb_atomic_t<hb_colr_scratch_t *> cached_scratch;
};
void closure_glyphs (hb_codepoint_t glyph,
@ -2270,7 +2180,7 @@ struct COLR
hb_set_t *variation_indices,
hb_set_t *delta_set_indices) const
{
if (version < 1) return;
if (version != 1) return;
hb_barrier ();
hb_set_t visited_glyphs;
@ -2312,26 +2222,16 @@ struct COLR
{ return (this+baseGlyphList); }
bool has_var_store () const
{ return version >= 1 && hb_barrier () && varStore != 0; }
{ return version >= 1 && varStore != 0; }
bool has_delta_set_index_map () const
{ return version >= 1 && hb_barrier () && varIdxMap != 0; }
bool has_clip_list () const
{ return version >= 1 && hb_barrier () && clipList != 0; }
{ return version >= 1 && varIdxMap != 0; }
const DeltaSetIndexMap &get_delta_set_index_map () const
{ return has_delta_set_index_map () && hb_barrier () ? this+varIdxMap : Null (DeltaSetIndexMap); }
const DeltaSetIndexMap *get_delta_set_index_map_ptr () const
{ return has_delta_set_index_map () && hb_barrier () ? &(this+varIdxMap) : nullptr; }
{ return (version == 0 || varIdxMap == 0) ? Null (DeltaSetIndexMap) : this+varIdxMap; }
const ItemVariationStore &get_var_store () const
{ return has_var_store () && hb_barrier () ? this+varStore : Null (ItemVariationStore); }
const ItemVariationStore *get_var_store_ptr () const
{ return has_var_store () && hb_barrier () ? &(this+varStore) : nullptr; }
const ClipList &get_clip_list () const
{ return has_clip_list () && hb_barrier () ? this+clipList : Null (ClipList); }
{ return (version == 0 || varStore == 0) ? Null (ItemVariationStore) : this+varStore; }
bool sanitize (hb_sanitize_context_t *c) const
{
@ -2342,6 +2242,7 @@ struct COLR
(this+layersZ).sanitize (c, numLayers) &&
(version == 0 ||
(hb_barrier () &&
version == 1 &&
baseGlyphList.sanitize (c, this) &&
layerList.sanitize (c, this) &&
clipList.sanitize (c, this) &&
@ -2564,9 +2465,7 @@ struct COLR
if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
if (version == 0 || downgrade_to_V0 (glyphset))
return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
hb_barrier ();
return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
//start version 1
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
@ -2576,9 +2475,9 @@ struct COLR
* after instancing */
if (!subset_varstore (c, colr_prime)) return_trace (false);
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
c->plan->normalized_coords.as_array ());
ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
varIdxMap ? &(this+varIdxMap) : nullptr,
c->plan->normalized_coords.as_array ());
if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
return_trace (false);
@ -2604,15 +2503,14 @@ struct COLR
#ifndef HB_NO_PAINT
bool
get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
hb_colr_scratch_t &scratch) const
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
if (version != 1)
return false;
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
hb_array (font->coords, font->num_coords));
ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
if (get_clip (glyph, extents, instancer))
{
@ -2621,10 +2519,10 @@ struct COLR
}
auto *extents_funcs = hb_paint_extents_get_funcs ();
scratch.paint_extents.clear ();
bool ret = paint_glyph (font, glyph, extents_funcs, &scratch.paint_extents, 0, HB_COLOR(0,0,0,0), true, scratch);
hb_paint_extents_context_t extents_data;
bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
auto e = scratch.paint_extents.get_extents ();
hb_extents_t e = extents_data.get_extents ();
if (e.is_void ())
{
extents->x_bearing = 0;
@ -2634,7 +2532,6 @@ struct COLR
}
else
{
// Ugh. We need to undo the synthetic slant here. Leave it for now. :-(.
extents->x_bearing = e.xmin;
extents->y_bearing = e.ymax;
extents->width = e.xmax - e.xmin;
@ -2648,7 +2545,7 @@ struct COLR
bool
has_paint_for_glyph (hb_codepoint_t glyph) const
{
if (version >= 1)
if (version == 1)
{
hb_barrier ();
@ -2664,29 +2561,22 @@ struct COLR
hb_glyph_extents_t *extents,
const ItemVarStoreInstancer instancer) const
{
return get_clip_list ().get_extents (glyph,
return (this+clipList).get_extents (glyph,
extents,
instancer);
}
#ifndef HB_NO_PAINT
bool
paint_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_paint_funcs_t *funcs, void *data,
unsigned int palette_index, hb_color_t foreground,
bool clip,
hb_colr_scratch_t &scratch) const
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{
ItemVarStoreInstancer instancer (get_var_store_ptr (),
get_delta_set_index_map_ptr (),
hb_array (font->coords, font->num_coords));
ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
c.current_glyphs.add (glyph);
hb_decycler_node_t node (c.glyphs_decycler);
node.visit (glyph);
if (version >= 1)
if (version == 1)
{
hb_barrier ();
@ -2702,7 +2592,6 @@ struct COLR
if (get_clip (glyph, &extents, instancer))
{
font->scale_glyph_extents (&extents);
font->synthetic_glyph_extents (&extents);
c.funcs->push_clip_rectangle (c.data,
extents.x_bearing,
extents.y_bearing + extents.height,
@ -2711,26 +2600,26 @@ struct COLR
}
else
{
clip = false;
is_bounded = false;
}
if (!is_bounded)
{
auto *bounded_funcs = hb_paint_bounded_get_funcs ();
scratch.paint_bounded.clear ();
auto *extents_funcs = hb_paint_extents_get_funcs ();
hb_paint_extents_context_t extents_data;
paint_glyph (font, glyph,
bounded_funcs, &scratch.paint_bounded,
extents_funcs, &extents_data,
palette_index, foreground,
false,
scratch);
false);
is_bounded = scratch.paint_bounded.is_bounded ();
hb_extents_t extents = extents_data.get_extents ();
is_bounded = extents_data.is_bounded ();
c.funcs->push_clip_rectangle (c.data,
extents.xmin,
extents.ymin,
extents.xmax,
extents.ymax);
}
}
c.funcs->push_font_transform (c.data, font);
c.funcs->push_root_transform (c.data, font);
if (is_bounded)
c.recurse (*paint);
@ -2801,14 +2690,19 @@ void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
hb_decycler_node_t node (c->layers_decycler);
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
if (unlikely (!node.visit (i)))
return;
if (unlikely (c->current_layers.has (i)))
continue;
c->current_layers.add (i);
const Paint &paint = paint_offset_lists.get_paint (i);
c->funcs->push_group (c->data);
c->recurse (paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
c->current_layers.del (i);
}
}
@ -2816,14 +2710,16 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
{
TRACE_PAINT (this);
hb_decycler_node_t node (c->glyphs_decycler);
if (unlikely (!node.visit (gid)))
if (unlikely (c->current_glyphs.has (gid)))
return;
c->funcs->push_inverse_font_transform (c->data, c->font);
c->current_glyphs.add (gid);
c->funcs->push_inverse_root_transform (c->data, c->font);
if (c->funcs->color_glyph (c->data, gid, c->font))
{
c->funcs->pop_transform (c->data);
c->current_glyphs.del (gid);
return;
}
c->funcs->pop_transform (c->data);
@ -2846,6 +2742,8 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
if (has_clip_box)
c->funcs->pop_clip (c->data);
c->current_glyphs.del (gid);
}
} /* namespace OT */

View file

@ -187,14 +187,6 @@ struct CPAL
hb_ot_name_id_t get_color_name_id (unsigned int color_index) const
{ return v1 ().get_color_name_id (this, color_index, numColors); }
hb_array_t<const BGRAColor> get_palette_colors (unsigned int palette_index) const
{
if (unlikely (palette_index >= numPalettes))
return hb_array_t<const BGRAColor> ();
unsigned int start_index = colorRecordIndicesZ[palette_index];
hb_array_t<const BGRAColor> all_colors ((this+colorRecordsZ).arrayZ, numColorRecords);
return all_colors.sub_array (start_index, numColors);
}
unsigned int get_palette_colors (unsigned int palette_index,
unsigned int start_offset,
unsigned int *color_count, /* IN/OUT. May be NULL. */

View file

@ -96,15 +96,6 @@ struct Coverage
default:return NOT_COVERED;
}
}
unsigned int get_coverage (hb_codepoint_t glyph_id,
hb_ot_lookup_cache_t *cache) const
{
unsigned coverage;
if (cache && cache->get (glyph_id, &coverage)) return coverage;
coverage = get_coverage (glyph_id);
if (cache) cache->set (glyph_id, coverage);
return coverage;
}
unsigned get_population () const
{
@ -210,19 +201,6 @@ struct Coverage
}
}
unsigned cost () const
{
switch (u.format) {
case 1: hb_barrier (); return u.format1.cost ();
case 2: hb_barrier (); return u.format2.cost ();
#ifndef HB_NO_BEYOND_64K
case 3: hb_barrier (); return u.format3.cost ();
case 4: hb_barrier (); return u.format4.cost ();
#endif
default:return 0u;
}
}
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename set_t>

View file

@ -77,7 +77,7 @@ struct CoverageFormat1_3
bool intersects (const hb_set_t *glyphs) const
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len))
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
{
for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
@ -103,8 +103,6 @@ struct CoverageFormat1_3
intersect_glyphs << glyphArray[i];
}
unsigned cost () const { return hb_bit_storage ((unsigned) glyphArray.len); /* bsearch cost */ }
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{ return glyphs->add_sorted_array (glyphArray.as_array ()); }

View file

@ -120,7 +120,7 @@ struct CoverageFormat2_4
bool intersects (const hb_set_t *glyphs) const
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len))
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
@ -157,8 +157,6 @@ struct CoverageFormat2_4
}
}
unsigned cost () const { return hb_bit_storage ((unsigned) rangeRecord.len); /* bsearch cost */ }
template <typename set_t>
bool collect_coverage (set_t *glyphs) const
{

View file

@ -205,19 +205,20 @@ struct CaretValueFormat3
unsigned varidx = (this+deviceTable).get_variation_index ();
hb_pair_t<unsigned, int> *new_varidx_delta;
if (c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta)) {
uint32_t new_varidx = hb_first (*new_varidx_delta);
int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
return_trace (false);
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
uint32_t new_varidx = hb_first (*new_varidx_delta);
int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
return_trace (false);
@ -1014,8 +1015,7 @@ struct GDEF
hb_blob_ptr_t<GDEF> table;
#ifndef HB_NO_GDEF_CACHE
hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
mutable hb_cache_t<21, 3> glyph_props_cache;
static_assert (sizeof (glyph_props_cache) == 512, "");
mutable hb_cache_t<21, 3, 8> glyph_props_cache;
#endif
};

View file

@ -54,7 +54,7 @@ struct PairPosFormat1_3
{
auto &cov = this+coverage;
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len))
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
{
for (hb_codepoint_t g : glyphs->iter())
{
@ -103,50 +103,12 @@ struct PairPosFormat1_3
const Coverage &get_coverage () const { return this+coverage; }
unsigned cache_cost () const
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset_fast (buffer->idx);
@ -194,7 +156,7 @@ struct PairPosFormat1_3
strip = true;
newFormats = compute_effective_value_formats (glyphset, strip, true);
}
out->valueFormat[0] = newFormats.first;
out->valueFormat[1] = newFormats.second;

View file

@ -123,61 +123,12 @@ struct PairPosFormat2_4 : ValueBase
const Coverage &get_coverage () const { return this+coverage; }
struct pair_pos_cache_t
{
hb_ot_lookup_cache_t coverage;
hb_ot_lookup_cache_t first;
hb_ot_lookup_cache_t second;
};
unsigned cache_cost () const
{
return (this+coverage).cost () + (this+classDef1).cost () + (this+classDef2).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) hb_malloc (sizeof (pair_pos_cache_t));
if (likely (cache))
{
cache->coverage.clear ();
cache->first.clear ();
cache->second.clear ();
}
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
pair_pos_cache_t *cache = (pair_pos_cache_t *) p;
hb_free (cache);
return nullptr;
}
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
pair_pos_cache_t *cache = cached ? (pair_pos_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache ? &cache->coverage : nullptr);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
skippy_iter.reset_fast (buffer->idx);
@ -188,13 +139,8 @@ struct PairPosFormat2_4 : ValueBase
return_trace (false);
}
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint, cache ? &cache->first : nullptr);
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint, cache ? &cache->second : nullptr);
#else
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
#endif
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);

View file

@ -67,7 +67,7 @@ struct SinglePosFormat1 : ValueBase
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{

View file

@ -66,7 +66,7 @@ struct SinglePosFormat2 : ValueBase
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= valueCount)) return_trace (false);

View file

@ -74,7 +74,7 @@ struct AlternateSubstFormat1_2
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
return_trace ((this+alternateSet[index]).apply (c));
}

View file

@ -78,49 +78,12 @@ struct LigatureSubstFormat1_2
return lig_set.would_apply (c);
}
unsigned cache_cost () const
{
return (this+coverage).cost ();
}
static void * cache_func (void *p, hb_ot_lookup_cache_op_t op)
{
switch (op)
{
case hb_ot_lookup_cache_op_t::CREATE:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) hb_malloc (sizeof (hb_ot_lookup_cache_t));
if (likely (cache))
cache->clear ();
return cache;
}
case hb_ot_lookup_cache_op_t::ENTER:
return (void *) true;
case hb_ot_lookup_cache_op_t::LEAVE:
return nullptr;
case hb_ot_lookup_cache_op_t::DESTROY:
{
hb_ot_lookup_cache_t *cache = (hb_ot_lookup_cache_t *) p;
hb_free (cache);
return nullptr;
}
}
return nullptr;
}
bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
bool _apply (hb_ot_apply_context_t *c, bool cached) const
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
hb_ot_lookup_cache_t *cache = cached ? (hb_ot_lookup_cache_t *) c->lookup_accel->cache : nullptr;
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint, cache);
#else
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
#endif
if (index == NOT_COVERED) return_trace (false);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
const auto &lig_set = this+ligatureSet[index];
return_trace (lig_set.apply (c));

View file

@ -66,7 +66,7 @@ struct MultipleSubstFormat1_2
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
return_trace ((this+sequence[index]).apply (c));
}

View file

@ -112,7 +112,7 @@ struct ReverseChainSingleSubstFormat1
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
return_trace (false); /* No chaining to this type */

View file

@ -128,7 +128,7 @@ struct SingleSubstFormat1_3
TRACE_APPLY (this);
hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
unsigned int index = (this+coverage).get_coverage (glyph_id);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
hb_codepoint_t d = deltaGlyphID;
hb_codepoint_t mask = get_mask ();

View file

@ -104,7 +104,7 @@ struct SingleSubstFormat2_4
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
if (index == NOT_COVERED) return_trace (false);
if (likely (index == NOT_COVERED)) return_trace (false);
if (unlikely (index >= substitute.len)) return_trace (false);

View file

@ -29,9 +29,6 @@
#ifndef OT_LAYOUT_TYPES_HH
#define OT_LAYOUT_TYPES_HH
using hb_ot_lookup_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_ot_lookup_cache_t) == 256, "");
namespace OT {
namespace Layout {

View file

@ -3,6 +3,7 @@
#ifndef HB_NO_VAR_COMPOSITES
#include "../../../hb-draw.hh"
#include "../../../hb-geometry.hh"
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-layout-gdef-table.hh"
@ -126,19 +127,24 @@ hb_transforming_pen_get_funcs ()
return static_transforming_pen_funcs.get_unconst ();
}
hb_ubytes_t
VarComponent::get_path_at (const hb_varc_context_t &c,
VarComponent::get_path_at (hb_font_t *font,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t total_transform,
hb_ubytes_t total_record,
hb_set_t *visited,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache) const
{
const unsigned char *end = total_record.arrayZ + total_record.length;
const unsigned char *record = total_record.arrayZ;
auto &VARC = *c.font->face->table.VARC->table;
auto &VARC = *font->face->table.VARC;
auto &varStore = &VARC+VARC.varStore;
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
#define READ_UINT32VAR(name) \
HB_STMT_START { \
@ -181,25 +187,22 @@ VarComponent::get_path_at (const hb_varc_context_t &c,
unsigned conditionIndex;
READ_UINT32VAR (conditionIndex);
const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
}
// Axis values
auto &axisIndices = c.scratch.axisIndices;
axisIndices.clear ();
auto &axisValues = c.scratch.axisValues;
axisValues.clear ();
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
if (flags & (unsigned) flags_t::HAVE_AXES)
{
unsigned axisIndicesIndex;
READ_UINT32VAR (axisIndicesIndex);
axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]);
axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
axisValues.resize (axisIndices.length);
const HBUINT8 *p = (const HBUINT8 *) record;
TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
record = (const unsigned char *) p;
record += (const unsigned char *) p - record;
}
// Apply variations if any
@ -216,7 +219,7 @@ VarComponent::get_path_at (const hb_varc_context_t &c,
* limit on the max number of coords for now. */
if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
coords.length > HB_VAR_COMPOSITE_MAX_AXES)
component_coords = hb_array<int> (c.font->coords, c.font->num_coords);
component_coords = hb_array<int> (font->coords, font->num_coords);
// Transform
@ -309,19 +312,26 @@ VarComponent::get_path_at (const hb_varc_context_t &c,
if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
transform.scaleY = transform.scaleX;
total_transform.transform (transform.to_transform ());
total_transform.scale (c.font->x_mult ? 1.f / c.font->x_multf : 0.f,
c.font->y_mult ? 1.f / c.font->y_multf : 0.f);
// Scale the transform by the font's scale
float x_scale = font->x_multf;
float y_scale = font->y_multf;
transform.translateX *= x_scale;
transform.translateY *= y_scale;
transform.tCenterX *= x_scale;
transform.tCenterY *= y_scale;
bool same_coords = component_coords.length == coords.length &&
component_coords.arrayZ == coords.arrayZ;
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform.to_transform (),
draw_session.funcs,
draw_session.draw_data,
&draw_session.st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
c.depth_left--;
VARC.get_path_at (c, gid,
component_coords, total_transform,
VARC.get_path_at (font, gid,
transformer_session, component_coords,
parent_gid,
same_coords ? cache : nullptr);
c.depth_left++;
visited, edges_left, depth_left - 1);
}
#undef PROCESS_TRANSFORM_COMPONENTS
@ -330,87 +340,6 @@ VarComponent::get_path_at (const hb_varc_context_t &c,
return hb_ubytes_t (record, end - record);
}
bool
VARC::get_path_at (const hb_varc_context_t &c,
hb_codepoint_t glyph,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_codepoint_t parent_glyph,
VarRegionList::cache_t *parent_cache) const
{
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
NOT_COVERED :
(this+coverage).get_coverage (glyph);
if (idx == NOT_COVERED)
{
if (c.draw_session)
{
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform,
c.draw_session->funcs,
c.draw_session->draw_data,
&c.draw_session->st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
hb_draw_session_t &shape_draw_session = transform.is_identity () ? *c.draw_session : transformer_session;
if (!c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch))
#ifndef HB_NO_CFF
if (!c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords))
if (!c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) // Doesn't have variations
#endif
return false;
}
else if (c.extents)
{
hb_glyph_extents_t glyph_extents;
if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords))
#ifndef HB_NO_CFF
if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords))
if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations
#endif
return false;
hb_extents_t comp_extents (glyph_extents);
transform.transform_extents (comp_extents);
c.extents->union_ (comp_extents);
}
return true;
}
if (c.depth_left <= 0)
return true;
if (c.edges_left <= 0)
return true;
(c.edges_left)--;
hb_decycler_node_t node (c.decycler);
if (unlikely (!node.visit (glyph)))
return true;
hb_ubytes_t record = (this+glyphRecords)[idx];
VarRegionList::cache_t static_cache[sizeof (void *) * 16];
VarRegionList::cache_t *cache = parent_cache ?
parent_cache :
(this+varStore).create_cache (hb_array (static_cache));
transform.scale (c.font->x_multf, c.font->y_multf);
VarCompositeGlyph::get_path_at (c,
glyph,
coords, transform,
record,
cache);
if (cache != parent_cache)
(this+varStore).destroy_cache (cache, hb_array (static_cache));
return true;
}
//} // namespace Var
} // namespace OT

View file

@ -1,8 +1,6 @@
#ifndef OT_VAR_VARC_VARC_HH
#define OT_VAR_VARC_VARC_HH
#include "../../../hb-decycler.hh"
#include "../../../hb-geometry.hh"
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-glyf-table.hh"
#include "../../../hb-ot-cff2-table.hh"
@ -21,24 +19,6 @@ namespace OT {
#ifndef HB_NO_VAR_COMPOSITES
struct hb_varc_scratch_t
{
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
hb_glyf_scratch_t glyf_scratch;
};
struct hb_varc_context_t
{
hb_font_t *font;
hb_draw_session_t *draw_session;
hb_extents_t *extents;
mutable hb_decycler_t decycler;
mutable signed edges_left;
mutable signed depth_left;
hb_varc_scratch_t &scratch;
};
struct VarComponent
{
enum class flags_t : uint32_t
@ -62,32 +42,37 @@ struct VarComponent
};
HB_INTERNAL hb_ubytes_t
get_path_at (const hb_varc_context_t &c,
get_path_at (hb_font_t *font,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_ubytes_t record,
hb_set_t *visited,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache = nullptr) const;
};
struct VarCompositeGlyph
{
static void
get_path_at (const hb_varc_context_t &c,
hb_codepoint_t gid,
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_transform_t transform,
hb_ubytes_t record,
VarRegionList::cache_t *cache)
hb_set_t *visited,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache = nullptr)
{
while (record)
{
const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
record = comp.get_path_at (c,
gid,
coords, transform,
record = comp.get_path_at (font, glyph,
draw_session, coords,
record,
cache);
visited, edges_left, depth_left, cache);
}
}
};
@ -100,48 +85,79 @@ struct VARC
static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
HB_INTERNAL bool
get_path_at (const hb_varc_context_t &c,
hb_codepoint_t gid,
hb_array_t<const int> coords,
hb_transform_t transform = HB_TRANSFORM_IDENTITY,
hb_codepoint_t parent_gid = HB_CODEPOINT_INVALID,
VarRegionList::cache_t *parent_cache = nullptr) const;
bool
get_path (hb_font_t *font,
hb_codepoint_t gid,
hb_draw_session_t &draw_session,
hb_varc_scratch_t &scratch) const
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID,
hb_set_t *visited = nullptr,
signed *edges_left = nullptr,
signed depth_left = HB_MAX_NESTING_LEVEL) const
{
hb_varc_context_t c {font,
&draw_session,
nullptr,
hb_decycler_t {},
HB_MAX_GRAPH_EDGE_COUNT,
HB_MAX_NESTING_LEVEL,
scratch};
hb_set_t stack_set;
if (visited == nullptr)
visited = &stack_set;
signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT;
if (edges_left == nullptr)
edges_left = &stack_edges;
return get_path_at (c, gid,
hb_array (font->coords, font->num_coords));
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
NOT_COVERED :
(this+coverage).get_coverage (glyph);
if (idx == NOT_COVERED)
{
if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords))
#ifndef HB_NO_CFF
if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords))
if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations
#endif
return false;
return true;
}
if (depth_left <= 0)
return true;
if (*edges_left <= 0)
return true;
(*edges_left)--;
if (visited->has (glyph) || visited->in_error ())
return true;
visited->add (glyph);
hb_ubytes_t record = (this+glyphRecords)[idx];
VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
(this+varStore).create_cache ()
: nullptr;
VarCompositeGlyph::get_path_at (font, glyph,
draw_session, coords,
record,
visited, edges_left, depth_left,
cache);
(this+varStore).destroy_cache (cache);
visited->del (glyph);
return true;
}
bool
get_extents (hb_font_t *font,
hb_codepoint_t gid,
hb_extents_t *extents,
hb_varc_scratch_t &scratch) const
{
hb_varc_context_t c {font,
nullptr,
extents,
hb_decycler_t {},
HB_MAX_GRAPH_EDGE_COUNT,
HB_MAX_NESTING_LEVEL,
scratch};
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); }
return get_path_at (c, gid,
hb_array (font->coords, font->num_coords));
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;
}
bool sanitize (hb_sanitize_context_t *c) const
@ -157,89 +173,6 @@ struct VARC
glyphRecords.sanitize (c, this));
}
struct accelerator_t
{
friend struct VarComponent;
accelerator_t (hb_face_t *face)
{
table = hb_sanitize_context_t ().reference_table<VARC> (face);
}
~accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_varc_scratch_t ();
hb_free (scratch);
}
table.destroy ();
}
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{
if (!table->has_data ()) return false;
auto *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = table->get_path (font, gid, draw_session, *scratch);
release_scratch (scratch);
return ret;
}
bool
get_extents (hb_font_t *font,
hb_codepoint_t gid,
hb_glyph_extents_t *extents) const
{
if (!table->has_data ()) return false;
hb_extents_t f_extents;
auto *scratch = acquire_scratch ();
if (unlikely (!scratch)) return true;
bool ret = table->get_extents (font, gid, &f_extents, *scratch);
release_scratch (scratch);
if (ret)
*extents = f_extents.to_glyph_extents (font->x_scale < 0, font->y_scale < 0);
return ret;
}
private:
hb_varc_scratch_t *acquire_scratch () const
{
hb_varc_scratch_t *scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_varc_scratch_t *) hb_calloc (1, sizeof (hb_varc_scratch_t));
if (unlikely (!scratch))
return nullptr;
}
return scratch;
}
void release_scratch (hb_varc_scratch_t *scratch) const
{
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_varc_scratch_t ();
hb_free (scratch);
}
}
private:
hb_blob_ptr_t<VARC> table;
mutable hb_atomic_t<hb_varc_scratch_t *> cached_scratch;
};
bool has_data () const { return version.major != 0; }
protected:
FixedVersion<> version; /* Version identifier */
Offset32To<Coverage> coverage;
@ -251,10 +184,6 @@ struct VARC
DEFINE_SIZE_STATIC (24);
};
struct VARC_accelerator_t : VARC::accelerator_t {
VARC_accelerator_t (hb_face_t *face) : VARC::accelerator_t (face) {}
};
#endif
//}

View file

@ -11,48 +11,22 @@ namespace OT {
struct coord_setter_t
{
coord_setter_t (hb_array_t<const int> coords_)
{
length = coords_.length;
if (length <= ARRAY_LENGTH (static_coords))
hb_memcpy (static_coords, coords_.arrayZ, length * sizeof (int));
else
dynamic_coords.extend (coords_);
}
coord_setter_t (hb_array_t<const int> coords) :
coords (coords) {}
int& operator [] (unsigned idx)
{
if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES))
return Crap(int);
if (length <= ARRAY_LENGTH (static_coords))
{
if (idx < ARRAY_LENGTH (static_coords))
{
while (length <= idx)
static_coords[length++] = 0;
return static_coords[idx];
}
else
dynamic_coords.extend (hb_array (static_coords, length));
}
if (dynamic_coords.length <= idx)
{
if (unlikely (!dynamic_coords.resize (idx + 1)))
return Crap(int);
length = idx + 1;
}
return dynamic_coords.arrayZ[idx];
if (coords.length < idx + 1)
coords.resize (idx + 1);
return coords[idx];
}
hb_array_t<int> get_coords ()
{ return length <= ARRAY_LENGTH (static_coords) ? hb_array (static_coords, length) : dynamic_coords.as_array (); }
{ return coords.as_array (); }
private:
hb_vector_t<int> dynamic_coords;
unsigned length;
int static_coords[sizeof (void *) * 8];
hb_vector_t<int> coords;
};

View file

@ -143,7 +143,7 @@ struct CompositeGlyphRecord
float matrix[4];
contour_point_t trans;
get_transformation (matrix, trans);
if (unlikely (!points.alloc (points.length + 1 + 4))) return false; // For phantom points
if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
points.push (trans);
return true;
}

View file

@ -251,8 +251,7 @@ struct Glyph
composite_contours_p = nullptr;
}
hb_glyf_scratch_t scratch;
if (!get_points (font, glyf, all_points, scratch, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
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
@ -306,7 +305,6 @@ struct Glyph
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
hb_glyf_scratch_t &scratch,
contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
@ -314,6 +312,7 @@ struct Glyph
bool use_my_metrics = true,
bool phantom_only = false,
hb_array_t<const int> coords = hb_array_t<const int> (),
hb_map_t *current_glyphs = nullptr,
unsigned int depth = 0,
unsigned *edge_count = nullptr) const
{
@ -323,6 +322,10 @@ struct Glyph
if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
(*edge_count)++;
hb_map_t current_glyphs_stack;
if (current_glyphs == nullptr)
current_glyphs = &current_glyphs_stack;
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@ -331,7 +334,8 @@ struct Glyph
if (!coords)
coords = hb_array (font->coords, font->num_coords);
contour_point_vector_t &points = type == SIMPLE ? all_points : scratch.comp_points;
contour_point_vector_t stack_points;
contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
unsigned old_length = points.length;
switch (type) {
@ -384,53 +388,36 @@ struct Glyph
#ifndef HB_NO_VAR
if (coords)
{
#ifndef HB_NO_BEYOND_64K
if (glyf_accelerator.GVAR->has_data ())
glyf_accelerator.GVAR->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
scratch,
phantom_only && type == SIMPLE);
else
#endif
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
scratch,
phantom_only && type == SIMPLE);
}
glyf_accelerator.gvar->apply_deltas_to_points (gid,
coords,
points.as_array ().sub_array (old_length),
phantom_only && type == SIMPLE);
#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)
{
assert (old_length == 0);
if (unlikely (!points_with_deltas->resize (points.length))) return false;
*points_with_deltas = points;
}
float shift = 0;
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
shift = phantoms[PHANTOM_LEFT].x;
break;
case COMPOSITE:
{
hb_decycler_node_t decycler_node (scratch.decycler);
unsigned int comp_index = 0;
for (auto &item : get_composite_iterator ())
{
hb_codepoint_t item_gid = item.get_gid ();
if (unlikely (!decycler_node.visit (item_gid)))
{
comp_index++;
if (unlikely (current_glyphs->has (item_gid)))
continue;
}
current_glyphs->add (item_gid);
unsigned old_count = all_points.length;
@ -439,7 +426,6 @@ struct Glyph
.get_points (font,
glyf_accelerator,
all_points,
scratch,
points_with_deltas,
head_maxp_info,
composite_contours,
@ -447,16 +433,14 @@ struct Glyph
use_my_metrics,
phantom_only,
coords,
current_glyphs,
depth + 1,
edge_count)))
{
points.resize (old_length);
current_glyphs->del (item_gid);
return false;
}
// points might have been reallocated. Relocate phantoms.
phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
auto comp_points = all_points.as_array ().sub_array (old_count);
/* Copy phantom points from component if USE_MY_METRICS flag set */
@ -471,7 +455,7 @@ struct Glyph
item.get_transformation (matrix, default_trans);
/* Apply component transformation & translation (with deltas applied) */
item.transform_points (comp_points, matrix, points[old_length + comp_index]);
item.transform_points (comp_points, matrix, points[comp_index]);
}
if (item.is_anchored () && !phantom_only)
@ -492,11 +476,12 @@ struct Glyph
if (all_points.length > HB_GLYF_MAX_POINTS)
{
points.resize (old_length);
current_glyphs->del (item_gid);
return false;
}
comp_index++;
current_glyphs->del (item_gid);
}
if (head_maxp_info && depth == 0)
@ -507,13 +492,9 @@ struct Glyph
head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
}
all_points.extend (phantoms);
shift = phantoms[PHANTOM_LEFT].x;
points.resize (old_length);
} break;
case EMPTY:
all_points.extend (phantoms);
shift = phantoms[PHANTOM_LEFT].x;
points.resize (old_length);
break;
}
@ -522,9 +503,10 @@ struct Glyph
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
if (shift)
float v = -phantoms[PHANTOM_LEFT].x;
if (v)
for (auto &point : all_points)
point.x -= shift;
point.x += v;
}
return !all_points.in_error ();

View file

@ -127,20 +127,19 @@ struct SimpleGlyph
hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end)
{
auto *points = points_.arrayZ;
unsigned count = points_.length;
for (unsigned int i = 0; i < count;)
{
if (unlikely (p + 1 > end)) return false;
uint8_t flag = *p++;
points[i++].flag = flag;
points_.arrayZ[i++].flag = flag;
if (flag & FLAG_REPEAT)
{
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[i].flag = flag;
points_.arrayZ[i].flag = flag;
}
}
return true;
@ -161,7 +160,10 @@ struct SimpleGlyph
if (flag & short_flag)
{
if (unlikely (p + 1 > end)) return false;
v += (bool(flag & same_flag) * 2 - 1) * *p++;
if (flag & same_flag)
v += *p++;
else
v -= *p++;
}
else
{
@ -188,7 +190,7 @@ struct SimpleGlyph
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
unsigned old_length = points.length;
points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy
points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
if (unlikely (!points.resize (points.length + num_points, false))) return false;
auto points_ = points.as_array ().sub_array (old_length);
if (!phantom_only)
@ -279,9 +281,9 @@ struct SimpleGlyph
unsigned num_points = all_points.length - 4;
hb_vector_t<uint8_t> flags, x_coords, y_coords;
if (unlikely (!flags.alloc_exact (num_points))) return false;
if (unlikely (!x_coords.alloc_exact (2*num_points))) return false;
if (unlikely (!y_coords.alloc_exact (2*num_points))) return false;
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;
unsigned lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0;

View file

@ -94,7 +94,7 @@ struct glyf
}
hb_vector_t<unsigned> padded_offsets;
if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length)))
if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true)))
return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
@ -172,9 +172,6 @@ struct glyf_accelerator_t
glyf_table = nullptr;
#ifndef HB_NO_VAR
gvar = nullptr;
#ifndef HB_NO_BEYOND_64K
GVAR = nullptr;
#endif
#endif
hmtx = nullptr;
#ifndef HB_NO_VERTICAL
@ -190,9 +187,6 @@ struct glyf_accelerator_t
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
#ifndef HB_NO_VAR
gvar = face->table.gvar;
#ifndef HB_NO_BEYOND_64K
GVAR = face->table.GVAR;
#endif
#endif
hmtx = face->table.hmtx;
#ifndef HB_NO_VERTICAL
@ -204,13 +198,6 @@ struct glyf_accelerator_t
}
~glyf_accelerator_t ()
{
auto *scratch = cached_scratch.get_relaxed ();
if (scratch)
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
glyf_table.destroy ();
}
@ -219,16 +206,21 @@ struct glyf_accelerator_t
protected:
template<typename T>
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
hb_array_t<const int> coords,
hb_glyf_scratch_t &scratch) const
hb_array_t<const int> coords = hb_array_t<const int> ()) const
{
if (!coords)
coords = hb_array (font->coords, font->num_coords);
if (gid >= num_glyphs) return false;
auto &all_points = scratch.all_points;
all_points.resize (0);
/* Making this allocfree is not that easy
https://github.com/harfbuzz/harfbuzz/issues/2095
mostly because of gvar handling in VF fonts,
perhaps a separate path for non-VF fonts can be considered */
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, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
return false;
unsigned count = all_points.length;
@ -237,61 +229,8 @@ struct glyf_accelerator_t
if (consumer.is_consuming_contour_points ())
{
auto *points = all_points.arrayZ;
if (false)
{
/* Our path-builder was designed to work with this simple loop.
* But FreeType and CoreText do it differently, so we match those
* with the other, more complicated, code branch below. */
for (unsigned i = 0; i < count; i++)
{
consumer.consume_point (points[i]);
if (points[i].is_end_point)
consumer.contour_end ();
}
}
else
{
for (unsigned i = 0; i < count; i++)
{
// Start of a contour.
if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE)
{
// First point is on-curve. Draw the contour.
for (; i < count; i++)
{
consumer.consume_point (points[i]);
if (points[i].is_end_point)
{
consumer.contour_end ();
break;
}
}
}
else
{
unsigned start = i;
// Find end of the contour.
for (; i < count; i++)
if (points[i].is_end_point)
break;
unsigned end = i;
// Enough to start from the end. Our path-builder takes care of the rest.
if (likely (end < count)) // Can only fail in case of alloc failure *maybe*.
consumer.consume_point (points[end]);
for (i = start; i < end; i++)
consumer.consume_point (points[i]);
consumer.contour_end ();
}
}
}
for (auto &point : all_points.as_array ().sub_array (0, count))
consumer.consume_point (point);
consumer.points_end ();
}
@ -364,7 +303,6 @@ struct glyf_accelerator_t
HB_ALWAYS_INLINE
void consume_point (const contour_point_t &point) { bounds.add (point); }
void contour_end () {}
void points_end () { bounds.get_extents (font, extents, scaled); }
bool is_consuming_contour_points () { return extents; }
@ -380,12 +318,7 @@ struct glyf_accelerator_t
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
if (font->num_coords)
{
hb_glyf_scratch_t scratch;
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false),
hb_array (font->coords, font->num_coords),
scratch);
}
success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false));
if (unlikely (!success))
return
@ -405,11 +338,9 @@ struct glyf_accelerator_t
if (unlikely (gid >= num_glyphs)) return false;
hb_glyph_extents_t extents;
hb_glyf_scratch_t scratch;
contour_point_t phantoms[glyf_impl::PHANTOM_COUNT];
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false),
hb_array (font->coords, font->num_coords),
scratch)))
if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false))))
return false;
*lsb = is_vertical
@ -429,33 +360,26 @@ struct glyf_accelerator_t
}
public:
bool get_extents (hb_font_t *font,
hb_codepoint_t gid,
hb_glyph_extents_t *extents) const
{ return get_extents_at (font, gid, extents, hb_array (font->coords, font->num_coords)); }
bool get_extents_at (hb_font_t *font,
hb_codepoint_t gid,
hb_glyph_extents_t *extents,
hb_array_t<const int> coords) const
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
{
if (unlikely (gid >= num_glyphs)) return false;
#ifndef HB_NO_VAR
if (coords)
{
hb_glyf_scratch_t scratch;
return get_points (font,
gid,
points_aggregator_t (font, extents, nullptr, true),
coords,
scratch);
}
if (font->num_coords)
return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true));
#endif
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
{
@ -486,52 +410,15 @@ struct glyf_accelerator_t
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{
if (!has_data ()) return false;
hb_glyf_scratch_t *scratch;
// Borrow the cached strach buffer.
{
scratch = cached_scratch.get_acquire ();
if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr)))
{
scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t));
if (unlikely (!scratch))
return true;
}
}
bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
hb_array (font->coords, font->num_coords),
*scratch);
// Put it back.
if (!cached_scratch.cmpexch (nullptr, scratch))
{
scratch->~hb_glyf_scratch_t ();
hb_free (scratch);
}
return ret;
}
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
bool
get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_glyf_scratch_t &scratch) const
{
if (!has_data ()) return false;
return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session),
coords,
scratch);
}
hb_array_t<const int> coords) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords); }
#ifndef HB_NO_VAR
const gvar_accelerator_t *gvar;
#ifndef HB_NO_BEYOND_64K
const GVAR_accelerator_t *GVAR;
#endif
#endif
const hmtx_accelerator_t *hmtx;
#ifndef HB_NO_VERTICAL
@ -543,7 +430,6 @@ struct glyf_accelerator_t
unsigned int num_glyphs;
hb_blob_ptr_t<loca> loca_table;
hb_blob_ptr_t<glyf> glyf_table;
mutable hb_atomic_t<hb_glyf_scratch_t *> cached_scratch;
};
@ -553,7 +439,7 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false;
if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false;
for (const auto &pair : plan->new_to_old_gid_list)
{

View file

@ -42,7 +42,7 @@ struct path_builder_t
{
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
#ifdef HB_NO_CUBIC_GLYF
constexpr bool is_cubic = false;
bool is_cubic = false;
#else
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif
@ -124,60 +124,58 @@ struct path_builder_t
}
}
if (unlikely (point.is_end_point))
{
if (first_offcurve && last_offcurve)
{
optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
first_offcurve2 :
first_offcurve);
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);
last_offcurve = optional_point_t ();
}
/* 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);
}
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);
}
else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve)
{
float x = first_offcurve.x, y = first_offcurve.y;
draw_session->move_to (x, y);
draw_session->quadratic_to (x, y, x, y);
}
/* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
draw_session->close_path ();
}
}
void contour_end ()
{
if (first_offcurve && last_offcurve)
{
optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
first_offcurve2 :
first_offcurve);
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);
last_offcurve = optional_point_t ();
}
/* 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);
}
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);
}
else if (first_oncurve)
draw_session->line_to (first_oncurve.x, first_oncurve.y);
else if (first_offcurve)
{
float x = first_offcurve.x, y = first_offcurve.y;
draw_session->move_to (x, y);
draw_session->quadratic_to (x, y, x, y);
}
/* Getting ready for the next contour */
first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
draw_session->close_path ();
}
void points_end () {}
bool is_consuming_contour_points () { return true; }

View file

@ -163,7 +163,7 @@ struct NameRecord
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);
@ -174,14 +174,14 @@ struct NameRecord
}
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
@ -392,7 +392,7 @@ struct name
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)
@ -485,7 +485,7 @@ struct name
const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
this->table->count);
this->names.alloc_exact (all_names.length);
this->names.alloc (all_names.length, true);
for (unsigned int i = 0; i < all_names.length; i++)
{

2
src/addTable.py Executable file → Normal file
View file

@ -1,5 +1,3 @@
#!/usr/bin/env python3
import sys
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables.DefaultTable import DefaultTable

View file

@ -22,30 +22,30 @@ if not OBJS:
stat = 0
tested = 0
result = subprocess.run(objdump.split () + ['-t'] + OBJS, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
for obj in OBJS:
result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if result.returncode:
if result.stderr.find (b'not recognized') != -1:
# https://github.com/harfbuzz/harfbuzz/issues/3019
print ('objdump %s returned "not recognized", skipping')
else:
print ('objdump returned error:\n%s' % (result.stderr.decode ('utf-8')))
stat = 2
else:
tested = 1
if result.returncode:
if result.stderr.find (b'not recognized') != -1:
# https://github.com/harfbuzz/harfbuzz/issues/3019
print ('objdump %s returned "not recognized", skipping' % obj)
continue
print ('objdump %s returned error:\n%s' % (obj, result.stderr.decode ('utf-8')))
stat = 2
result = result.stdout.decode ('utf-8')
result = result.stdout.decode ('utf-8')
# Checking that no object file has static initializers
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
if not re.match (r'.*\b0+\b', l):
print ('Ouch, library has static initializers/finalizers')
stat = 1
# Checking that no object file has static initializers
for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
if not re.match (r'.*\b0+\b', l):
print ('Ouch, %s has static initializers/finalizers' % obj)
stat = 1
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
print ('Ouch, library has lazy static C++ constructors/destructors or other such stuff')
stat = 1
# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
if ('__cxa_' in result) and ('__ubsan_handle' not in result):
print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
stat = 1
tested += 1
sys.exit (stat if tested else 77)

View file

@ -7,27 +7,18 @@ os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
builddir = os.getenv ('builddir', os.path.dirname (__file__))
libs = os.getenv ('libs', '.libs')
IGNORED_SYMBOLS = ['_fini', '_init', '_fdata', '_ftext', '_fbss',
IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
'lprofDirMode', 'reset_fn_list']
# Rust
IGNORED_SYMBOLS += [
'rust_eh_personality',
'_ZN3std9panicking11EMPTY_PANIC.*', # 'std::panicking::EMPTY_PANIC::.*'
'_ZN3std3sys3pal4unix4args3imp15ARGV_INIT_ARRAY.*', # 'std::sys::pal::unix::args::imp::ARGV_INIT_ARRAY::.*'
'_ZN3std3sys4args4unix3imp15ARGV_INIT_ARRAY.*', # std::sys::args::unix::imp::ARGV_INIT_ARRAY::.*
'_ZN17compiler_builtins4math4libm7generic4sqrt9RSQRT_TAB.*', # 'compiler_builtins::math::libm::generic::sqrt::RSQRT_TAB::.*'
]
IGNORED_SYMBOLS = '|'.join (IGNORED_SYMBOLS)
'lprofDirMode', 'reset_fn_list'])
nm = os.getenv ('NM', shutil.which ('nm'))
if not nm:
print ('check-symbols.py: \'nm\' not found; skipping test')
sys.exit (77)
cxxfilt = shutil.which ('c++filt')
tested = False
stat = 0
@ -43,6 +34,12 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
for s in re.findall (r'^.+ [BCDGIRSTu] .+$', 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
if cxxfilt:
EXPORTED_SYMBOLS = subprocess.check_output (
[cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
).decode ('utf-8').splitlines ()
prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
print ('Checking that %s does not expose internal symbols' % so)

View file

@ -1,95 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bytemuck"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "font-types"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d868ec188a98bb014c606072edd47e52e7ab7297db943b0b28503121e1d037bd"
dependencies = [
"bytemuck",
]
[[package]]
name = "harfbuzz_fontations"
version = "0.0.0"
dependencies = [
"read-fonts",
"skrifa",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
[[package]]
name = "read-fonts"
version = "0.27.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14974c88fb4fd0a7203719f98020209248c9dbebaf9d10d860337797a905097"
dependencies = [
"bytemuck",
"font-types",
]
[[package]]
name = "skrifa"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c0ca53de9bb9bee1720c727606275148463cd938eb6bde249dcedeec4967747"
dependencies = [
"bytemuck",
"read-fonts",
]
[[package]]
name = "syn"
version = "2.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"

View file

@ -1,28 +0,0 @@
[package]
name = "harfbuzz_fontations"
edition = "2021"
[dependencies]
read-fonts = "0.27"
skrifa = "0.29.2"
[lib]
name = "harfbuzz_fontations"
path = "lib.rs"
crate-type = ["staticlib"]
[profile.release]
strip = true
lto = "fat"
panic = "abort"
overflow-checks = false
codegen-units = 1
[profile.debugoptimized]
inherits = "release"
debug = true
codegen-units = 16
strip = false
[profile.dev]
lto = "fat"

File diff suppressed because it is too large Load diff

View file

@ -1,105 +0,0 @@
rust = import('unstable-rust')
hb_rs = rust.bindgen(
input : '../hb.h',
output : 'hb.rs',
include_directories: incsrc,
args : ['--allowlist-function=hb_.*',
'--allowlist-type=hb_.*',
'--no-copy=hb_.*',
],
)
cargo = find_program('cargo')
rustfmt = find_program('rustfmt')
rust_flags = ''
cargo_args = [
'--package', 'harfbuzz_fontations',
'--lib',
'--target-dir', meson.current_build_dir(),
'--manifest-path', meson.current_source_dir() / 'Cargo.toml',
'-Z', 'build-std=std,panic_abort',
'-Z', 'build-std-features=panic_immediate_abort',
]
buildtype = get_option('buildtype')
if buildtype == 'release' or buildtype == 'debugoptimized'
cargo_args += ['--profile', buildtype]
endif
opt_level = get_option('optimization')
rust_flags += ' -C opt-level=' + opt_level
harfbuzz_fontations = custom_target(
'harfbuzz_fontations',
input: ['lib.rs', 'Cargo.toml', 'Cargo.lock'],
output: ['libharfbuzz_fontations.a'],
depends: [hb_rs],
env: ['OUT_DIR=' + meson.current_build_dir(),
'RUSTFLAGS=' + rust_flags,
],
command: [
cargo, 'build',
] + cargo_args + [
'-Z', 'unstable-options',
'--artifact-dir', meson.current_build_dir(),
],
install: true,
install_dir: join_paths(get_option('prefix'), 'lib'),
)
harfbuzz_fontations_dep = declare_dependency(
link_with: harfbuzz_fontations,
)
clippy_fix = run_target(
'clippy-fix',
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs, harfbuzz_fontations],
command: [
cargo, 'clippy',
] + cargo_args + [
'--allow-dirty', '--fix',
],
)
if get_option('tests').enabled() and cargo.found()
test(
'clippy',
cargo,
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs, harfbuzz_fontations],
args: [
'clippy',
] + cargo_args + [
'--', '-D', 'warnings',
],
timeout: 120,
)
endif
rustfmt_fix = run_target(
'rustfmt-fix',
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs],
command: [
rustfmt,
'--edition', '2021',
'--',
meson.current_source_dir() / 'lib.rs',
],
)
if get_option('tests').enabled() and rustfmt.found()
test(
'rustfmt',
rustfmt,
env: ['OUT_DIR=' + meson.current_build_dir()],
depends: [hb_rs],
args: [
'--check',
'--edition', '2021',
'--',
meson.current_source_dir() / 'lib.rs',
],
)
endif

View file

@ -20,11 +20,8 @@ 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
hb_subset_cff_get_charstring_data
hb_subset_cff_get_charstrings_index
hb_subset_cff2_get_charstring_data
hb_subset_cff2_get_charstrings_index
""".splitlines ()
symbols = [x for x in symbols if x not in experimental_symbols]
symbols = "\n".join (symbols)

View file

@ -102,7 +102,6 @@ categories = {
'CM',
'Symbol',
'CS',
'SMPst',
],
'khmer' : [
'VAbv',
@ -436,8 +435,6 @@ defaults = (category_map[defaults[0]], position_map[defaults[1]], defaults[2])
indic_data = {}
for k, (cat, pos, block) in combined.items():
cat = category_map[cat]
if cat == 'SM' and pos == 'Not_Applicable':
cat = 'SMPst'
pos = position_map[pos]
indic_data[k] = (cat, pos, block)
@ -457,7 +454,7 @@ for k, (cat, pos, block) in indic_data.items():
# Keep in sync with CONSONANT_FLAGS in the shaper
consonant_categories = ('C', 'CS', 'Ra','CM', 'V', 'PLACEHOLDER', 'DOTTEDCIRCLE')
matra_categories = ('M', 'MPst')
smvd_categories = ('SM', 'SMPst', 'VD', 'A', 'Symbol')
smvd_categories = ('SM', 'VD', 'A', 'Symbol')
for k, (cat, pos, block) in indic_data.items():
if cat in consonant_categories:
pos = 'BASE_C'
@ -533,7 +530,6 @@ short = [{
"Repha": 'Rf',
"PLACEHOLDER": 'GB',
"DOTTEDCIRCLE": 'DC',
"SMPst": 'SP',
"VPst": 'VR',
"VPre": 'VL',
"Robatic": 'Rt',

View file

@ -19,9 +19,7 @@ outdir = os.path.dirname (OUTPUT)
shutil.copy (INPUT, outdir)
rl = os.path.basename (INPUT)
hh = rl.replace ('.rl', '.hh')
ret = subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
if ret:
sys.exit (ret)
subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
# copy it also to src/
shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))

View file

@ -345,18 +345,14 @@ class OpenTypeRegistryParser (HTMLParser):
self.from_bcp_47_uninherited = None
# Whether the parser is in a <td> element
self._td = False
# Whether the parser ignores the rest of the current <td> element
self._disengaged = False
# Whether the parser is after a <br> element within the current <tr> element
self._br = False
# The text of the <td> elements of the current <tr> element.
self._current_tr = []
def handle_starttag (self, tag, attrs):
if tag == 'a':
if self._current_tr and not self._disengaged:
self._current_tr[-1] = ''
self._disengaged = True
elif tag == 'br':
self._disengaged = True
if tag == 'br':
self._br = True
elif tag == 'meta':
for attr, value in attrs:
if attr == 'name' and value == 'updated_at':
@ -366,13 +362,12 @@ class OpenTypeRegistryParser (HTMLParser):
self._td = True
self._current_tr.append ('')
elif tag == 'tr':
self._disengaged = False
self._br = False
self._current_tr = []
def handle_endtag (self, tag):
if tag == 'td':
self._td = False
self._disengaged = False
elif tag == 'tr' and self._current_tr:
expect (2 <= len (self._current_tr) <= 3)
name = self._current_tr[0].strip ()
@ -392,7 +387,7 @@ class OpenTypeRegistryParser (HTMLParser):
self.ranks[tag] = rank
def handle_data (self, data):
if self._td and not self._disengaged:
if self._td and not self._br:
self._current_tr[-1] += data
def handle_charref (self, name):

View file

@ -109,7 +109,6 @@ property_names = [
'Nukta',
'Virama',
'Pure_Killer',
'Reordering_Killer',
'Invisible_Stacker',
'Vowel_Independent',
'Vowel_Dependent',
@ -264,8 +263,6 @@ def is_OTHER(U, UISC, UDI, UGC, AJT):
and not is_SYM_MOD(U, UISC, UDI, UGC, AJT)
and not is_Word_Joiner(U, UISC, UDI, UGC, AJT)
)
def is_REORDERING_KILLER(U, UISC, UDI, UGC, AJT):
return UISC == Reordering_Killer
def is_REPHA(U, UISC, UDI, UGC, AJT):
return UISC in [Consonant_Preceding_Repha, Consonant_Prefixed]
def is_SAKOT(U, UISC, UDI, UGC, AJT):
@ -309,7 +306,6 @@ use_mapping = {
'SE': is_HIEROGLYPH_SEGMENT_END,
'ZWNJ': is_ZWNJ,
'O': is_OTHER,
'RK': is_REORDERING_KILLER,
'R': is_REPHA,
'Sk': is_SAKOT,
'SM': is_SYM_MOD,
@ -362,7 +358,6 @@ use_positions = {
'Pst': [Not_Applicable],
},
'R': None,
'RK': None,
'SUB': None,
}

View file

@ -172,7 +172,7 @@ print ('static void')
print ('_output_dotted_circle (hb_buffer_t *buffer)')
print ('{')
print (' (void) buffer->output_glyph (0x25CCu);')
print (' _hb_glyph_info_clear_continuation (&buffer->prev());')
print (' _hb_glyph_info_reset_continuation (&buffer->prev());')
print ('}')
print ()
print ('static void')

View file

@ -2,8 +2,6 @@
set_and_check(HARFBUZZ_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set(HARFBUZZ_VERSION "@HARFBUZZ_VERSION@")
# Add the libraries.
add_library(harfbuzz::harfbuzz @HB_LIBRARY_TYPE@ IMPORTED)
set_target_properties(harfbuzz::harfbuzz PROPERTIES

View file

@ -43,7 +43,6 @@
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
#include "hb-outline.cc"
#include "hb-paint-bounded.cc"
#include "hb-paint-extents.cc"
#include "hb-paint.cc"
#include "hb-set.cc"
@ -58,10 +57,8 @@
#include "hb-subset-input.cc"
#include "hb-subset-instancer-iup.cc"
#include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan-layout.cc"
#include "hb-subset-plan-var.cc"
#include "hb-subset-plan.cc"
#include "hb-subset-serialize.cc"
#include "hb-subset-repacker.cc"
#include "hb-subset.cc"
#include "hb-ucd.cc"
#include "hb-unicode.cc"

View file

@ -6,11 +6,7 @@
#include "hb-buffer-verify.cc"
#include "hb-buffer.cc"
#include "hb-common.cc"
#include "hb-coretext-font.cc"
#include "hb-coretext-shape.cc"
#include "hb-coretext.cc"
#include "hb-directwrite-font.cc"
#include "hb-directwrite-shape.cc"
#include "hb-directwrite.cc"
#include "hb-draw.cc"
#include "hb-face-builder.cc"
@ -52,7 +48,6 @@
#include "hb-ot-tag.cc"
#include "hb-ot-var.cc"
#include "hb-outline.cc"
#include "hb-paint-bounded.cc"
#include "hb-paint-extents.cc"
#include "hb-paint.cc"
#include "hb-set.cc"

View file

@ -29,13 +29,7 @@
#include "hb-aat-layout.hh"
#include "hb-aat-map.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-open-type.hh"
#include "hb-cache.hh"
#include "hb-bit-set.hh"
#include "hb-bit-page.hh"
namespace OT {
struct GDEF;
@ -45,66 +39,10 @@ namespace AAT {
using namespace OT;
#define HB_AAT_BUFFER_DIGEST_THRESHOLD 32
struct ankr;
using hb_aat_class_cache_t = hb_cache_t<15, 8, 7>;
static_assert (sizeof (hb_aat_class_cache_t) == 256, "");
struct hb_aat_scratch_t
{
hb_aat_scratch_t () = default;
hb_aat_scratch_t (const hb_aat_scratch_t &) = delete;
hb_aat_scratch_t (hb_aat_scratch_t &&o)
{
buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
o.buffer_glyph_set.set_relaxed (nullptr);
}
hb_aat_scratch_t & operator = (hb_aat_scratch_t &&o)
{
buffer_glyph_set.set_relaxed (o.buffer_glyph_set.get_relaxed ());
o.buffer_glyph_set.set_relaxed (nullptr);
return *this;
}
~hb_aat_scratch_t ()
{
auto *s = buffer_glyph_set.get_relaxed ();
if (unlikely (!s))
return;
s->fini ();
hb_free (s);
}
hb_bit_set_t *create_buffer_glyph_set () const
{
hb_bit_set_t *s = buffer_glyph_set.get_acquire ();
if (s && buffer_glyph_set.cmpexch (s, nullptr))
return s;
s = (hb_bit_set_t *) hb_calloc (1, sizeof (hb_bit_set_t));
if (unlikely (!s))
return nullptr;
s->init ();
return s;
}
void destroy_buffer_glyph_set (hb_bit_set_t *s) const
{
if (unlikely (!s))
return;
if (buffer_glyph_set.cmpexch (nullptr, s))
return;
s->fini ();
hb_free (s);
}
mutable hb_atomic_t<hb_bit_set_t *> buffer_glyph_set;
};
enum { DELETED_GLYPH = 0xFFFF };
#define HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED HB_BUFFER_SCRATCH_FLAG_SHAPER0
struct hb_aat_apply_context_t :
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
@ -121,15 +59,12 @@ struct hb_aat_apply_context_t :
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
const OT::GDEF &gdef;
bool has_glyph_classes;
const OT::GDEF *gdef_table;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
bool using_buffer_glyph_set = false;
hb_bit_set_t *buffer_glyph_set = nullptr;
const hb_bit_set_t *left_set = nullptr;
const hb_bit_set_t *right_set = nullptr;
const hb_bit_set_t *machine_glyph_set = nullptr;
hb_aat_class_cache_t *machine_class_cache = nullptr;
hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
hb_set_digest_t left_set = hb_set_digest_t::full ();
hb_set_digest_t right_set = hb_set_digest_t::full ();
hb_mask_t subtable_flags = 0;
/* Unused. For debug tracing only. */
@ -145,88 +80,6 @@ struct hb_aat_apply_context_t :
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
void set_lookup_index (unsigned int i) { lookup_index = i; }
void setup_buffer_glyph_set ()
{
using_buffer_glyph_set = buffer->len >= 4 && buffer_glyph_set;
if (likely (using_buffer_glyph_set))
buffer->collect_codepoints (*buffer_glyph_set);
}
bool buffer_intersects_machine () const
{
if (likely (using_buffer_glyph_set))
return buffer_glyph_set->intersects (*machine_glyph_set);
// Faster for shorter buffers.
for (unsigned i = 0; i < buffer->len; i++)
if (machine_glyph_set->has (buffer->info[i].codepoint))
return true;
return false;
}
template <typename T>
HB_NODISCARD bool output_glyphs (unsigned int count,
const T *glyphs)
{
if (likely (using_buffer_glyph_set))
buffer_glyph_set->add_array (glyphs, count);
for (unsigned int i = 0; i < count; i++)
{
if (glyphs[i] == DELETED_GLYPH)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
_hb_glyph_info_set_aat_deleted (&buffer->cur());
}
else
{
#ifndef HB_NO_OT_LAYOUT
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->cur(),
gdef.get_glyph_props (glyphs[i]));
#endif
}
if (unlikely (!buffer->output_glyph (glyphs[i]))) return false;
}
return true;
}
HB_NODISCARD bool replace_glyph (hb_codepoint_t glyph)
{
if (glyph == DELETED_GLYPH)
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
_hb_glyph_info_set_aat_deleted (&buffer->cur());
}
if (likely (using_buffer_glyph_set))
buffer_glyph_set->add (glyph);
#ifndef HB_NO_OT_LAYOUT
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->cur(),
gdef.get_glyph_props (glyph));
#endif
return buffer->replace_glyph (glyph);
}
HB_NODISCARD bool delete_glyph ()
{
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED;
_hb_glyph_info_set_aat_deleted (&buffer->cur());
return buffer->replace_glyph (DELETED_GLYPH);
}
void replace_glyph_inplace (unsigned i, hb_codepoint_t glyph)
{
buffer->info[i].codepoint = glyph;
if (likely (using_buffer_glyph_set))
buffer_glyph_set->add (glyph);
#ifndef HB_NO_OT_LAYOUT
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[i],
gdef.get_glyph_props (glyph));
#endif
}
};
@ -234,6 +87,8 @@ struct hb_aat_apply_context_t :
* Lookup Table
*/
enum { DELETED_GLYPH = 0xFFFF };
template <typename T> struct Lookup;
template <typename T>
@ -253,13 +108,6 @@ struct LookupFormat0
{
glyphs.add_range (0, num_glyphs - 1);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
{
for (unsigned i = 0; i < num_glyphs; i++)
if (filter (arrayZ[i]))
glyphs.add (i);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -292,14 +140,8 @@ struct LookupSegmentSingle
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (first == DELETED_GLYPH) return;
glyphs.add_range (first, last);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (first == DELETED_GLYPH) return;
if (!filter (value)) return;
if (first == DELETED_GLYPH)
return;
glyphs.add_range (first, last);
}
@ -340,13 +182,6 @@ struct LookupFormat2
for (unsigned int i = 0; i < count; i++)
segments[i].collect_glyphs (glyphs);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
unsigned count = segments.get_length ();
for (unsigned int i = 0; i < count; i++)
segments[i].collect_glyphs_filtered (glyphs, filter);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -382,18 +217,10 @@ struct LookupSegmentArray
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (first == DELETED_GLYPH) return;
if (first == DELETED_GLYPH)
return;
glyphs.add_range (first, last);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const void *base, const filter_t &filter) const
{
if (first == DELETED_GLYPH) return;
const auto &values = base+valuesZ;
for (hb_codepoint_t i = first; i <= last; i++)
if (filter (values[i - first]))
glyphs.add (i);
}
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
@ -444,13 +271,6 @@ struct LookupFormat4
for (unsigned i = 0; i < count; i++)
segments[i].collect_glyphs (glyphs);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
unsigned count = segments.get_length ();
for (unsigned i = 0; i < count; i++)
segments[i].collect_glyphs_filtered (glyphs, this, filter);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -483,14 +303,8 @@ struct LookupSingle
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (glyph == DELETED_GLYPH) return;
glyphs.add (glyph);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (glyph == DELETED_GLYPH) return;
if (!filter (value)) return;
if (glyph == DELETED_GLYPH)
return;
glyphs.add (glyph);
}
@ -530,13 +344,6 @@ struct LookupFormat6
for (unsigned i = 0; i < count; i++)
entries[i].collect_glyphs (glyphs);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
unsigned count = entries.get_length ();
for (unsigned i = 0; i < count; i++)
entries[i].collect_glyphs_filtered (glyphs, filter);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -572,20 +379,12 @@ struct LookupFormat8
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
if (unlikely (!glyphCount))
return;
if (firstGlyph == DELETED_GLYPH)
return;
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, const filter_t &filter) const
{
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
const T *p = valueArrayZ.arrayZ;
for (unsigned i = 0; i < glyphCount; i++)
if (filter (p[i]))
glyphs.add (firstGlyph + i);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -634,8 +433,10 @@ struct LookupFormat10
template <typename set_t>
void collect_glyphs (set_t &glyphs) const
{
if (unlikely (!glyphCount)) return;
if (firstGlyph == DELETED_GLYPH) return;
if (unlikely (!glyphCount))
return;
if (firstGlyph == DELETED_GLYPH)
return;
glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1);
}
@ -700,18 +501,6 @@ struct Lookup
default:return;
}
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
{
switch (u.format) {
case 0: hb_barrier (); u.format0.collect_glyphs_filtered (glyphs, num_glyphs, filter); return;
case 2: hb_barrier (); u.format2.collect_glyphs_filtered (glyphs, filter); return;
case 4: hb_barrier (); u.format4.collect_glyphs_filtered (glyphs, filter); return;
case 6: hb_barrier (); u.format6.collect_glyphs_filtered (glyphs, filter); return;
case 8: hb_barrier (); u.format8.collect_glyphs_filtered (glyphs, filter); return;
default:return;
}
}
typename T::type get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
@ -774,7 +563,7 @@ DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2);
template <typename T>
struct Entry
{
// This doesn't seem like it's ever called.
// This does seem like it's ever called.
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -843,51 +632,18 @@ struct StateTable
{
(this+classTable).collect_glyphs (glyphs, num_glyphs);
}
template <typename set_t, typename table_t>
void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs, const table_t &table) const
{
unsigned num_classes = nClasses;
if (unlikely (num_classes > hb_bit_page_t::BITS))
{
(this+classTable).collect_glyphs (glyphs, num_glyphs);
return;
}
// Collect all classes going out from the start state.
hb_bit_page_t filter;
for (unsigned i = 0; i < num_classes; i++)
{
const auto &entry = get_entry (STATE_START_OF_TEXT, i);
if (new_state (entry.newState) == STATE_START_OF_TEXT &&
!table.is_action_initiable (entry) && !table.is_actionable (entry))
continue;
filter.add (i);
}
// And glyphs in those classes.
if (filter (CLASS_DELETED_GLYPH))
glyphs.add (DELETED_GLYPH);
(this+classTable).collect_glyphs_filtered (glyphs, num_glyphs, filter);
}
int new_state (unsigned int newState) const
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
template <typename set_t>
unsigned int get_class (hb_codepoint_t glyph_id,
unsigned int num_glyphs,
hb_aat_class_cache_t *cache = nullptr) const
const set_t &glyphs) const
{
unsigned klass;
if (cache && cache->get (glyph_id, &klass)) return klass;
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
klass = (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
if (cache) cache->set (glyph_id, klass);
return klass;
if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS;
return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS);
}
const Entry<Extra> *get_entries () const
@ -895,14 +651,13 @@ struct StateTable
const Entry<Extra> &get_entry (int state, unsigned int klass) const
{
unsigned n_classes = nClasses;
if (unlikely (klass >= n_classes))
if (unlikely (klass >= nClasses))
klass = CLASS_OUT_OF_BOUNDS;
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
const Entry<Extra> *entries = (this+entryTable).arrayZ;
unsigned int entry = states[state * n_classes + klass];
unsigned int entry = states[state * nClasses + klass];
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
return entries[entry];
@ -1048,13 +803,6 @@ struct ClassTable
if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS)
glyphs.add (firstGlyph + i);
}
template <typename set_t, typename filter_t>
void collect_glyphs_filtered (set_t &glyphs, unsigned num_glyphs, const filter_t &filter) const
{
for (unsigned i = 0; i < classArray.len; i++)
if (filter (classArray.arrayZ[i]))
glyphs.add (firstGlyph + i);
}
bool sanitize (hb_sanitize_context_t *c) const
{
@ -1170,7 +918,7 @@ struct ExtendedTypes
}
};
template <typename Types, typename EntryData, typename Flags>
template <typename Types, typename EntryData>
struct StateTableDriver
{
using StateTableT = StateTable<Types, EntryData>;
@ -1181,6 +929,14 @@ struct StateTableDriver
machine (machine_),
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t>
bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac)
{
const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
return !c->is_actionable (ac->buffer, this, entry) &&
machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
}
template <typename context_t>
void drive (context_t *c, hb_aat_apply_context_t *ac)
{
@ -1221,7 +977,7 @@ struct StateTableDriver
}
unsigned int klass = likely (buffer->idx < buffer->len) ?
machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_class_cache) :
machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) :
(unsigned) CLASS_END_OF_TEXT;
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
const EntryT &entry = machine.get_entry (state, klass);
@ -1255,36 +1011,41 @@ struct StateTableDriver
*
* https://github.com/harfbuzz/harfbuzz/issues/2860
*/
const EntryT *wouldbe_entry;
bool is_safe_to_break =
(
const auto is_safe_to_break_extra = [&]()
{
/* 2c. */
const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
/* 2c'. */
if (c->is_actionable (buffer, this, wouldbe_entry))
return false;
/* 2c". */
return next_state == machine.new_state(wouldbe_entry.newState)
&& (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
};
const auto is_safe_to_break = [&]()
{
/* 1. */
!c->table->is_actionable (entry) &&
if (c->is_actionable (buffer, this, entry))
return false;
/* 2. */
// This one is meh, I know...
(
const auto ok =
state == StateTableT::STATE_START_OF_TEXT
|| ((entry.flags & Flags::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
|| (
/* 2c. */
wouldbe_entry = &machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass)
,
/* 2c'. */
!c->table->is_actionable (*wouldbe_entry) &&
/* 2c". */
(
next_state == machine.new_state(wouldbe_entry->newState) &&
(entry.flags & Flags::DontAdvance) == (wouldbe_entry->flags & Flags::DontAdvance)
)
)
) &&
|| ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
|| is_safe_to_break_extra();
if (!ok)
return false;
/* 3. */
!c->table->is_actionable (machine.get_entry (state, CLASS_END_OF_TEXT))
);
return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT));
};
if (!is_safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
c->transition (buffer, this, entry);
@ -1295,7 +1056,7 @@ struct StateTableDriver
if (buffer->idx == buffer->len || unlikely (!buffer->successful))
break;
if (!(entry.flags & Flags::DontAdvance) || buffer->max_ops-- <= 0)
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
(void) buffer->next_glyph ();
}

View file

@ -112,6 +112,10 @@ struct KerxSubTableFormat0
if (header.coverage & header.Backwards)
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
@ -140,7 +144,7 @@ struct KerxSubTableFormat0
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!c->left_set[left] || !c->right_set[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -185,9 +189,6 @@ struct Format1Entry<true>
DEFINE_SIZE_STATIC (2);
};
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & Push; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.data.kernActionIndex != 0xFFFF; }
@ -210,9 +211,6 @@ struct Format1Entry<false>
typedef void EntryData;
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & Push; }
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
@ -229,23 +227,13 @@ struct KerxSubTableFormat1
typedef Format1Entry<Types::extended> Format1EntryT;
typedef typename Format1EntryT::EntryData EntryData;
enum Flags
{
DontAdvance = Format1EntryT::DontAdvance,
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return Format1EntryT::initiateAction (entry);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return Format1EntryT::performAction (entry);
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum
{
DontAdvance = Format1EntryT::DontAdvance,
};
driver_context_t (const KerxSubTableFormat1 *table_,
hb_aat_apply_context_t *c_) :
@ -258,8 +246,12 @@ struct KerxSubTableFormat1
depth (0),
crossStream (table->header.coverage & table->header.CrossStream) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return Format1EntryT::performAction (entry); }
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData, Flags> *driver,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
unsigned int flags = entry.flags;
@ -328,9 +320,8 @@ struct KerxSubTableFormat1
}
else if (buffer->info[idx].mask & kern_mask)
{
auto scaled = c->font->em_scale_x (v);
o.x_advance += scaled;
o.x_offset += scaled;
o.x_advance += c->font->em_scale_x (v);
o.x_offset += c->font->em_scale_x (v);
}
}
else
@ -360,10 +351,9 @@ struct KerxSubTableFormat1
}
}
public:
private:
hb_aat_apply_context_t *c;
const KerxSubTableFormat1 *table;
private:
const UnsizedArrayOf<FWORD> &kernAction;
unsigned int stack[8];
unsigned int depth;
@ -380,7 +370,12 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
StateTableDriver<Types, EntryData> driver (machine, c->font->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
driver.drive (&dc, c);
@ -398,8 +393,10 @@ struct KerxSubTableFormat1
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
set_t set;
machine.collect_glyphs (set, num_glyphs);
left_set.union_ (set);
right_set.union_ (set);
}
protected:
@ -443,6 +440,10 @@ struct KerxSubTableFormat2
if (header.coverage & header.Backwards)
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
@ -468,7 +469,7 @@ struct KerxSubTableFormat2
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!c->left_set[left] || !c->right_set[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -512,26 +513,17 @@ struct KerxSubTableFormat4
DEFINE_SIZE_STATIC (2);
};
enum Flags
{
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* Not used; set to 0. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & Mark);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return entry.data.ankrActionIndex != 0xFFFF;
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags
{
Mark = 0x8000, /* If set, remember this glyph as the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* Not used; set to 0. */
};
enum SubTableFlags
{
ActionType = 0xC0000000, /* A two-bit field containing the action type. */
@ -541,17 +533,20 @@ struct KerxSubTableFormat4
* point table. */
};
driver_context_t (const KerxSubTableFormat4 *table_,
driver_context_t (const KerxSubTableFormat4 *table,
hb_aat_apply_context_t *c_) :
c (c_),
table (table_),
action_type ((table->flags & ActionType) >> 30),
ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
mark_set (false),
mark (0) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry)
{ return entry.data.ankrActionIndex != 0xFFFF; }
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData, Flags> *driver,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
if (mark_set && entry.data.ankrActionIndex != 0xFFFF && buffer->idx < buffer->len)
@ -639,10 +634,8 @@ struct KerxSubTableFormat4
}
}
public:
hb_aat_apply_context_t *c;
const KerxSubTableFormat4 *table;
private:
hb_aat_apply_context_t *c;
unsigned int action_type;
const HBUINT16 *ankrData;
bool mark_set;
@ -655,7 +648,12 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->font->face);
StateTableDriver<Types, EntryData> driver (machine, c->font->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
driver.drive (&dc, c);
@ -673,8 +671,10 @@ struct KerxSubTableFormat4
template <typename set_t>
void collect_glyphs (set_t &left_set, set_t &right_set, unsigned num_glyphs) const
{
machine.collect_initial_glyphs (left_set, num_glyphs, *this);
//machine.collect_glyphs (right_set, num_glyphs); // right_set is unused for machine kerning
set_t set;
machine.collect_glyphs (set, num_glyphs);
left_set.union_ (set);
right_set.union_ (set);
}
protected:
@ -735,6 +735,10 @@ struct KerxSubTableFormat6
if (header.coverage & header.Backwards)
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
machine.kern (c->font, c->buffer, c->plan->kern_mask);
@ -789,7 +793,7 @@ struct KerxSubTableFormat6
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
{
if (!(*c->left_set)[left] || !(*c->right_set)[right]) return 0;
if (!c->left_set[left] || !c->right_set[right]) return 0;
return table.get_kerning (left, right, c);
}
};
@ -921,18 +925,7 @@ struct KerxSubTable
* The 'kerx' Table
*/
struct kern_subtable_accelerator_data_t
{
hb_bit_set_t left_set;
hb_bit_set_t right_set;
mutable hb_aat_class_cache_t class_cache;
};
struct kern_accelerator_data_t
{
hb_vector_t<kern_subtable_accelerator_data_t> subtable_accels;
hb_aat_scratch_t scratch;
};
using kern_accelerator_data_t = hb_vector_t<hb_pair_t<hb_set_digest_t, hb_set_digest_t>>;
template <typename T>
struct KerxTable
@ -992,11 +985,14 @@ struct KerxTable
}
bool apply (AAT::hb_aat_apply_context_t *c,
const kern_accelerator_data_t &accel_data) const
const kern_accelerator_data_t *accel_data = nullptr) const
{
c->buffer->unsafe_to_concat ();
c->setup_buffer_glyph_set ();
if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
c->buffer_digest = c->buffer->digest ();
else
c->buffer_digest = hb_set_digest_t::full ();
typedef typename T::SubTable SubTable;
@ -1009,25 +1005,12 @@ struct KerxTable
{
bool reverse;
auto &subtable_accel = accel_data.subtable_accels[i];
if (!T::Types::extended && (st->u.header.coverage & st->u.header.Variation))
goto skip;
if (HB_DIRECTION_IS_HORIZONTAL (c->buffer->props.direction) != st->u.header.is_horizontal ())
goto skip;
c->left_set = &subtable_accel.left_set;
c->right_set = &subtable_accel.right_set;
c->machine_glyph_set = &subtable_accel.left_set;
c->machine_class_cache = &subtable_accel.class_cache;
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped subtable %u because no glyph matches", c->lookup_index);
goto skip;
}
reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
@ -1054,6 +1037,16 @@ struct KerxTable
if (reverse)
c->buffer->reverse ();
if (accel_data)
{
c->left_set = (*accel_data)[i].first;
c->right_set = (*accel_data)[i].second;
}
else
{
c->left_set = c->right_set = hb_set_digest_t::full ();
}
{
/* See comment in sanitize() for conditional here. */
hb_sanitize_with_object_t with (&c->sanitizer, i < count - 1 ? st : (const SubTable *) nullptr);
@ -1129,13 +1122,9 @@ struct KerxTable
unsigned int count = thiz()->tableCount;
for (unsigned int i = 0; i < count; i++)
{
auto &subtable_accel = *accel_data.subtable_accels.push ();
if (unlikely (accel_data.subtable_accels.in_error ()))
return accel_data;
st->collect_glyphs (subtable_accel.left_set, subtable_accel.right_set, num_glyphs);
subtable_accel.class_cache.clear ();
hb_set_digest_t left_set, right_set;
st->collect_glyphs (left_set, right_set, num_glyphs);
accel_data.push (hb_pair (left_set, right_set));
st = &StructAfter<SubTable> (*st);
}
@ -1159,12 +1148,11 @@ struct KerxTable
bool apply (AAT::hb_aat_apply_context_t *c) const
{
return table->apply (c, accel_data);
return table->apply (c, &accel_data);
}
hb_blob_ptr_t<T> table;
kern_accelerator_data_t accel_data;
hb_aat_scratch_t scratch;
};
};

View file

@ -29,7 +29,8 @@
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-aat-map.hh"
/*
@ -52,40 +53,35 @@ struct RearrangementSubtable
typedef void EntryData;
enum Flags
{
MarkFirst = 0x8000, /* If set, make the current glyph the first
* glyph to be rearranged. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. This means
* that the glyph index doesn't change, even
* if the glyph at that index has changed. */
MarkLast = 0x2000, /* If set, make the current glyph the last
* glyph to be rearranged. */
Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */
Verb = 0x000F, /* The type of rearrangement specified. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & MarkFirst);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return (entry.flags & Verb);
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags
{
MarkFirst = 0x8000, /* If set, make the current glyph the first
* glyph to be rearranged. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph
* before going to the new state. This means
* that the glyph index doesn't change, even
* if the glyph at that index has changed. */
MarkLast = 0x2000, /* If set, make the current glyph the last
* glyph to be rearranged. */
Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */
Verb = 0x000F, /* The type of rearrangement specified. */
};
driver_context_t (const RearrangementSubtable *table_) :
driver_context_t (const RearrangementSubtable *table HB_UNUSED) :
ret (false),
table (table_),
start (0), end (0) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{
return (entry.flags & Verb) && start < end;
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData, Flags> *driver,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
unsigned int flags = entry.flags;
@ -162,7 +158,6 @@ struct RearrangementSubtable
public:
bool ret;
const RearrangementSubtable *table;
private:
unsigned int start;
unsigned int end;
@ -174,7 +169,11 @@ struct RearrangementSubtable
driver_context_t dc (this);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
@ -208,38 +207,39 @@ struct ContextualSubtable
DEFINE_SIZE_STATIC (4);
};
enum Flags
{
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & SetMark);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
}
struct driver_context_t
{
static constexpr bool in_place = true;
enum Flags
{
SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. */
Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */
};
driver_context_t (const ContextualSubtable *table_,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
table (table_),
gdef (*c->gdef_table),
mark_set (false),
has_glyph_classes (gdef.has_glyph_classes ()),
mark (0),
table (table_),
subs (table+table->substitutionTables) {}
bool is_actionable (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry) const
{
if (buffer->idx == buffer->len && !mark_set)
return false;
return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF;
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData, Flags> *driver,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
/* Looks like CoreText applies neither mark nor current substitution for
@ -271,7 +271,11 @@ struct ContextualSubtable
if (replacement)
{
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
c->replace_glyph_inplace (mark, *replacement);
buffer->info[mark].codepoint = *replacement;
c->buffer_digest.add (*replacement);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
gdef.get_glyph_props (*replacement));
ret = true;
}
@ -297,7 +301,11 @@ struct ContextualSubtable
}
if (replacement)
{
c->replace_glyph_inplace (idx, *replacement);
buffer->info[idx].codepoint = *replacement;
c->buffer_digest.add (*replacement);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
gdef.get_glyph_props (*replacement));
ret = true;
}
@ -310,11 +318,13 @@ struct ContextualSubtable
public:
bool ret;
hb_aat_apply_context_t *c;
const ContextualSubtable *table;
private:
hb_aat_apply_context_t *c;
const OT::GDEF &gdef;
bool mark_set;
bool has_glyph_classes;
unsigned int mark;
const ContextualSubtable *table;
const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
};
@ -324,7 +334,11 @@ struct ContextualSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
@ -375,16 +389,6 @@ struct LigatureEntry;
template <>
struct LigatureEntry<true>
{
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
* for processing this group, if indicated
* by the flags. */
public:
DEFINE_SIZE_STATIC (2);
};
enum Flags
{
SetComponent = 0x8000, /* Push this glyph onto the component stack for
@ -396,8 +400,14 @@ struct LigatureEntry<true>
Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */
};
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & SetComponent; }
struct EntryData
{
HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry
* for processing this group, if indicated
* by the flags. */
public:
DEFINE_SIZE_STATIC (2);
};
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & PerformAction; }
@ -408,8 +418,6 @@ struct LigatureEntry<true>
template <>
struct LigatureEntry<false>
{
typedef void EntryData;
enum Flags
{
SetComponent = 0x8000, /* Push this glyph onto the component stack for
@ -421,8 +429,7 @@ struct LigatureEntry<false>
* multiple of 4. */
};
static bool initiateAction (const Entry<EntryData> &entry)
{ return entry.flags & SetComponent; }
typedef void EntryData;
static bool performAction (const Entry<EntryData> &entry)
{ return entry.flags & Offset; }
@ -440,23 +447,13 @@ struct LigatureSubtable
typedef LigatureEntry<Types::extended> LigatureEntryT;
typedef typename LigatureEntryT::EntryData EntryData;
enum Flags
{
DontAdvance = LigatureEntryT::DontAdvance,
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return LigatureEntryT::initiateAction (entry);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return LigatureEntryT::performAction (entry);
}
struct driver_context_t
{
static constexpr bool in_place = false;
enum
{
DontAdvance = LigatureEntryT::DontAdvance,
};
enum LigActionFlags
{
LigActionLast = 0x80000000, /* This is the last action in the list. This also
@ -479,8 +476,14 @@ struct LigatureSubtable
ligature (table+table->ligature),
match_length (0) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{
return LigatureEntryT::performAction (entry);
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData, Flags> *driver,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx);
@ -553,7 +556,7 @@ struct LigatureSubtable
hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
if (unlikely (!c->replace_glyph (lig))) return;
if (unlikely (!buffer->replace_glyph (lig))) return;
unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u;
/* Now go and delete all subsequent components. */
@ -561,7 +564,8 @@ struct LigatureSubtable
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
if (!c->delete_glyph ()) return;
buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
if (unlikely (!buffer->move_to (lig_end))) return;
@ -577,9 +581,9 @@ struct LigatureSubtable
public:
bool ret;
private:
hb_aat_apply_context_t *c;
const LigatureSubtable *table;
private:
const UnsizedArrayOf<HBUINT32> &ligAction;
const UnsizedArrayOf<HBUINT16> &component;
const UnsizedArrayOf<HBGlyphID16> &ligature;
@ -593,7 +597,11 @@ struct LigatureSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
@ -630,6 +638,9 @@ struct NoncontextualSubtable
{
TRACE_APPLY (this);
const OT::GDEF &gdef (*c->gdef_table);
bool has_glyph_classes = gdef.has_glyph_classes ();
bool ret = false;
unsigned int num_glyphs = c->face->get_num_glyphs ();
@ -659,7 +670,11 @@ struct NoncontextualSubtable
const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
if (replacement)
{
c->replace_glyph_inplace (i, *replacement);
info[i].codepoint = *replacement;
c->buffer_digest.add (*replacement);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
ret = true;
}
}
@ -667,12 +682,6 @@ struct NoncontextualSubtable
return_trace (ret);
}
template <typename set_t>
void collect_initial_glyphs (set_t &glyphs, unsigned num_glyphs) const
{
substitute.collect_glyphs (glyphs, num_glyphs);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -706,78 +715,73 @@ struct InsertionSubtable
DEFINE_SIZE_STATIC (4);
};
enum Flags
{
SetMark = 0x8000, /* If set, mark the current glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. This does not mean
* that the glyph pointed to is the same one as
* before. If you've made insertions immediately
* downstream of the current glyph, the next glyph
* processed would in fact be the first one
* inserted. */
CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). If clear, and
* the currentInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). */
MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). If clear, and
* the markedInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). */
CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made
* to the left of the current glyph. If clear,
* they're made to the right of the current glyph. */
MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
* made to the left of the marked glyph. If clear,
* they're made to the right of the marked glyph. */
CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the current
* position. Since zero means no insertions, the
* largest number of insertions at any given
* current location is 31 glyphs. */
MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the marked
* position. Since zero means no insertions, the
* largest number of insertions at any given
* marked location is 31 glyphs. */
};
bool is_action_initiable (const Entry<EntryData> &entry) const
{
return (entry.flags & SetMark);
}
bool is_actionable (const Entry<EntryData> &entry) const
{
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
}
struct driver_context_t
{
static constexpr bool in_place = false;
enum Flags
{
SetMark = 0x8000, /* If set, mark the current glyph. */
DontAdvance = 0x4000, /* If set, don't advance to the next glyph before
* going to the new state. This does not mean
* that the glyph pointed to is the same one as
* before. If you've made insertions immediately
* downstream of the current glyph, the next glyph
* processed would in fact be the first one
* inserted. */
CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). If clear, and
* the currentInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the current glyph (depending on the state
* of the currentInsertBefore flag). */
MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero,
* then the specified glyph list will be inserted
* as a kashida-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). If clear, and
* the markedInsertList is nonzero, then the
* specified glyph list will be inserted as a
* split-vowel-like insertion, either before or
* after the marked glyph (depending on the state
* of the markedInsertBefore flag). */
CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made
* to the left of the current glyph. If clear,
* they're made to the right of the current glyph. */
MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be
* made to the left of the marked glyph. If clear,
* they're made to the right of the marked glyph. */
CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the current
* position. Since zero means no insertions, the
* largest number of insertions at any given
* current location is 31 glyphs. */
MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the
* number of glyphs to insert at the marked
* position. Since zero means no insertions, the
* largest number of insertions at any given
* marked location is 31 glyphs. */
};
driver_context_t (const InsertionSubtable *table_,
driver_context_t (const InsertionSubtable *table,
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
table (table_),
mark (0),
insertionAction (table+table->insertionAction) {}
bool is_actionable (hb_buffer_t *buffer HB_UNUSED,
StateTableDriver<Types, EntryData> *driver HB_UNUSED,
const Entry<EntryData> &entry) const
{
return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) &&
(entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF);
}
void transition (hb_buffer_t *buffer,
StateTableDriver<Types, EntryData, Flags> *driver,
StateTableDriver<Types, EntryData> *driver,
const Entry<EntryData> &entry)
{
unsigned int flags = entry.flags;
@ -801,7 +805,9 @@ struct InsertionSubtable
if (buffer->idx < buffer->len && !before)
if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
if (unlikely (!c->output_glyphs (count, glyphs))) return;
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
for (unsigned int i = 0; i < count; i++)
c->buffer_digest.add (glyphs[i]);
ret = true;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -830,8 +836,7 @@ struct InsertionSubtable
if (buffer->idx < buffer->len && !before)
if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
if (unlikely (!c->output_glyphs (count, glyphs))) return;
ret = true;
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -856,9 +861,8 @@ struct InsertionSubtable
public:
bool ret;
hb_aat_apply_context_t *c;
const InsertionSubtable *table;
private:
hb_aat_apply_context_t *c;
unsigned int mark;
const UnsizedArrayOf<HBGlyphID16> &insertionAction;
};
@ -869,7 +873,11 @@ struct InsertionSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData, Flags> driver (machine, c->face);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
@ -927,33 +935,24 @@ struct hb_accelerate_subtables_context_t :
friend struct hb_aat_layout_lookup_accelerator_t;
public:
hb_bit_set_t glyph_set;
mutable hb_aat_class_cache_t class_cache;
hb_set_digest_t digest;
template <typename T>
auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN
(
obj_.machine.collect_initial_glyphs (glyph_set, num_glyphs, obj_)
obj_.machine.collect_glyphs (this->digest, num_glyphs)
)
template <typename T>
void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>)
{
obj_.collect_initial_glyphs (glyph_set, num_glyphs);
digest = digest.full ();
}
template <typename T>
void init (const T &obj_, unsigned num_glyphs)
{
glyph_set.init ();
init_ (obj_, num_glyphs, hb_prioritize);
class_cache.clear ();
}
void
fini ()
{
glyph_set.fini ();
}
};
@ -1000,21 +999,12 @@ struct hb_aat_layout_chain_accelerator_t
if (unlikely (!thiz))
return nullptr;
thiz->count = count;
hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs);
chain.dispatch (&c_accelerate_subtables);
return thiz;
}
void destroy ()
{
for (unsigned i = 0; i < count; i++)
subtables[i].fini ();
}
unsigned count;
hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
};
@ -1162,28 +1152,17 @@ struct Chain
{
bool reverse;
auto coverage = subtable->get_coverage ();
hb_mask_t subtable_flags = subtable->subFeatureFlags;
if (hb_none (hb_iter (c->range_flags) |
hb_map ([subtable_flags] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable_flags & (_.flags); })))
hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
goto skip;
c->subtable_flags = subtable->subFeatureFlags;
c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full ();
c->subtable_flags = subtable_flags;
c->machine_glyph_set = accel ? &accel->subtables[i].glyph_set : &Null(hb_bit_set_t);
c->machine_class_cache = accel ? &accel->subtables[i].class_cache : nullptr;
if (!(coverage & ChainSubtable<Types>::AllDirections) &&
if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
bool (coverage & ChainSubtable<Types>::Vertical))
bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical))
goto skip;
if (!c->buffer_intersects_machine ())
{
(void) c->buffer->message (c->font, "skipped chainsubtable %u because no glyph matches", c->lookup_index);
goto skip;
}
/* Buffer contents is always in logical direction. Determine if
* we need to reverse before applying this subtable. We reverse
* back after if we did reverse indeed.
@ -1211,9 +1190,9 @@ struct Chain
(the order opposite that of the characters, which
may be right-to-left or left-to-right).
*/
reverse = coverage & ChainSubtable<Types>::Logical ?
bool (coverage & ChainSubtable<Types>::Backwards) :
bool (coverage & ChainSubtable<Types>::Backwards) !=
reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ?
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) :
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
@ -1319,15 +1298,9 @@ struct mortmorx
hb_sanitize_context_t sc;
this->table = sc.reference_table<T> (face);
if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
{
hb_blob_destroy (this->table.get_blob ());
this->table = hb_blob_get_empty ();
}
this->chain_count = table->get_chain_count ();
this->accels = (hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *) hb_calloc (this->chain_count, sizeof (*accels));
this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels));
if (unlikely (!this->accels))
{
this->chain_count = 0;
@ -1338,11 +1311,7 @@ struct mortmorx
~accelerator_t ()
{
for (unsigned int i = 0; i < this->chain_count; i++)
{
if (this->accels[i])
this->accels[i]->destroy ();
hb_free (this->accels[i]);
}
hb_free (this->accels);
this->table.destroy ();
}
@ -1374,8 +1343,7 @@ struct mortmorx
hb_blob_ptr_t<T> table;
unsigned int chain_count;
hb_atomic_t<hb_aat_layout_chain_accelerator_t *> *accels;
hb_aat_scratch_t scratch;
hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels;
};
@ -1397,8 +1365,9 @@ struct mortmorx
unsigned get_chain_count () const
{
return chainCount;
return chainCount;
}
void apply (hb_aat_apply_context_t *c,
const hb_aat_map_t &map,
const accelerator_t &accel) const
@ -1407,7 +1376,10 @@ struct mortmorx
c->buffer->unsafe_to_concat ();
c->setup_buffer_glyph_set ();
if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
c->buffer_digest = c->buffer->digest ();
else
c->buffer_digest = hb_set_digest_t::full ();
c->set_lookup_index (0);
const Chain<Types> *chain = &firstChain;
@ -1456,17 +1428,8 @@ struct mortmorx
DEFINE_SIZE_MIN (8);
};
struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx>
{
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
};
struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort>
{
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const;
};
struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {};
struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {};
struct morx_accelerator_t : morx::accelerator_t {
morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {}

View file

@ -31,7 +31,6 @@
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout.hh"
#include "hb-open-type.hh"
#include "hb-ot-stat-table.hh"
/*
* trak -- Tracking
@ -49,74 +48,22 @@ struct TrackTableEntry
float get_track_value () const { return track.to_float (); }
float interpolate_at (unsigned int idx,
float ptem,
const void *base,
hb_array_t<const F16DOT16> size_table) const
{
const FWORD *values = (base+valuesZ).arrayZ;
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
int v0 = values[idx];
int v1 = values[idx + 1];
// Deal with font bugs.
if (unlikely (s1 < s0))
{ hb_swap (s0, s1); hb_swap (v0, v1); }
if (unlikely (ptem < s0)) return v0;
if (unlikely (ptem > s1)) return v1;
if (unlikely (s0 == s1)) return (v0 + v1) * 0.5f;
float t = (ptem - s0) / (s1 - s0);
return v0 + t * (v1 - v0);
}
float get_value (float ptem,
const void *base,
hb_array_t<const F16DOT16> size_table) const
{
const FWORD *values = (base+valuesZ).arrayZ;
unsigned int n_sizes = size_table.length;
/*
* Choose size.
*/
if (!n_sizes) return 0.f;
if (n_sizes == 1) return values[0];
// At least two entries.
unsigned i;
for (i = 0; i < n_sizes; i++)
if (size_table[i].to_float () >= ptem)
break;
// Boundary conditions.
if (i == 0) return values[0];
if (i == n_sizes) return values[n_sizes - 1];
// Exact match.
if (size_table[i].to_float () == ptem) return values[i];
// Interpolate.
return interpolate_at (i - 1, ptem, base, size_table);
}
int get_value (const void *base, unsigned int index,
unsigned int table_size) const
{ return (base+valuesZ).as_array (table_size)[index]; }
public:
bool sanitize (hb_sanitize_context_t *c,
const void *base,
unsigned int n_sizes) const
bool sanitize (hb_sanitize_context_t *c, const void *base,
unsigned int table_size) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(valuesZ.sanitize (c, base, n_sizes))));
(valuesZ.sanitize (c, base, table_size))));
}
protected:
F16DOT16 track; /* Track value for this record. */
OT::NameID trackNameID; /* The 'name' table index for this track.
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
NNOffset16To<UnsizedArrayOf<FWORD>>
@ -129,38 +76,58 @@ struct TrackTableEntry
struct TrackData
{
float get_tracking (const void *base, float ptem, float track = 0.f) const
float interpolate_at (unsigned int idx,
float target_size,
const TrackTableEntry &trackTableEntry,
const void *base) const
{
unsigned count = nTracks;
hb_array_t<const F16DOT16> size_table = (base+sizeTable).as_array (nSizes);
unsigned int sizes = nSizes;
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
if (!count) return 0.f;
if (count == 1) return trackTable[0].get_value (ptem, base, size_table);
float s0 = size_table[idx].to_float ();
float s1 = size_table[idx + 1].to_float ();
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
return t * trackTableEntry.get_value (base, idx + 1, sizes) +
(1.f - t) * trackTableEntry.get_value (base, idx, sizes);
}
// At least two entries.
int get_tracking (const void *base, float ptem) const
{
/*
* Choose track.
*/
const TrackTableEntry *trackTableEntry = nullptr;
unsigned int count = nTracks;
for (unsigned int i = 0; i < count; i++)
{
/* Note: Seems like the track entries are sorted by values. But the
* spec doesn't explicitly say that. It just mentions it in the example. */
unsigned i = 0;
unsigned j = count - 1;
/* For now we only seek for track entries with zero tracking value */
// Find the two entries that track is between.
while (i + 1 < count && trackTable[i + 1].get_track_value () <= track)
i++;
while (j > 0 && trackTable[j - 1].get_track_value () >= track)
j--;
if (trackTable[i].get_track_value () == 0.f)
{
trackTableEntry = &trackTable[i];
break;
}
}
if (!trackTableEntry) return 0;
// Exact match.
if (i == j) return trackTable[i].get_value (ptem, base, size_table);
/*
* Choose size.
*/
unsigned int sizes = nSizes;
if (!sizes) return 0;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
// Interpolate.
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
unsigned int size_index;
for (size_index = 0; size_index < sizes - 1; size_index++)
if (size_table[size_index].to_float () >= ptem)
break;
float t0 = trackTable[i].get_track_value ();
float t1 = trackTable[j].get_track_value ();
float t = (track - t0) / (t1 - t0);
float a = trackTable[i].get_value (ptem, base, size_table);
float b = trackTable[j].get_value (ptem, base, size_table);
return a + t * (b - a);
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
*trackTableEntry, base));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
@ -191,52 +158,42 @@ struct trak
bool has_data () const { return version.to_int (); }
hb_position_t get_h_tracking (hb_font_t *font, float track = 0.f) const
{
float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
return font->em_scalef_x ((this+horizData).get_tracking (this, ptem, track));
}
hb_position_t get_v_tracking (hb_font_t *font, float track = 0.f) const
{
float ptem = font->ptem > 0.f ? font->ptem : HB_CORETEXT_DEFAULT_FONT_SIZE;
return font->em_scalef_y ((this+vertData).get_tracking (this, ptem, track));
}
hb_position_t get_tracking (hb_font_t *font, hb_direction_t dir, float track = 0.f) const
{
#ifndef HB_NO_STYLE
if (!font->face->table.STAT->has_data ())
return 0;
return HB_DIRECTION_IS_HORIZONTAL (dir) ?
get_h_tracking (font, track) :
get_v_tracking (font, track);
#else
return 0;
#endif
}
bool apply (hb_aat_apply_context_t *c, float track = 0.f) const
bool apply (hb_aat_apply_context_t *c) const
{
TRACE_APPLY (this);
float ptem = c->font->ptem;
hb_mask_t trak_mask = c->plan->trak_mask;
const float ptem = c->font->ptem;
if (unlikely (ptem <= 0.f))
{
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
ptem = HB_CORETEXT_DEFAULT_FONT_SIZE;
}
return_trace (false);
hb_buffer_t *buffer = c->buffer;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
hb_position_t advance_to_add = get_h_tracking (c->font, track);
const TrackData &trackData = this+horizData;
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
foreach_grapheme (buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].x_advance += advance_to_add;
buffer->pos[start].x_offset += offset_to_add;
}
}
else
{
hb_position_t advance_to_add = get_v_tracking (c->font, track);
const TrackData &trackData = this+vertData;
int tracking = trackData.get_tracking (this, ptem);
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
foreach_grapheme (buffer, start, end)
{
if (!(buffer->info[start].mask & trak_mask)) continue;
buffer->pos[start].y_advance += advance_to_add;
buffer->pos[start].y_offset += offset_to_add;
}
}
return_trace (true);

View file

@ -37,9 +37,6 @@
#include "hb-aat-layout-trak-table.hh"
#include "hb-aat-ltag-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gdef-table.hh"
/*
* hb_aat_apply_context_t
@ -58,14 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
buffer (buffer_),
sanitizer (),
ankr_table (&Null (AAT::ankr)),
gdef (
gdef_table (
#ifndef HB_NO_OT_LAYOUT
*face->table.GDEF->table
face->table.GDEF->table
#else
Null (GDEF)
&Null (GDEF)
#endif
),
has_glyph_classes (gdef.has_glyph_classes ()),
lookup_index (0)
{
sanitizer.init (blob);
@ -204,43 +200,13 @@ hb_aat_layout_find_feature_mapping (hb_tag_t tag)
#endif
#ifndef HB_NO_AAT_SHAPE
#ifndef HB_NO_AAT
/*
* mort/morx/kerx/trak
*/
bool
AAT::morx::is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const
{
#ifdef HB_NO_AAT_LAYOUT_BLOCKLIST
return false;
#endif
switch HB_CODEPOINT_ENCODE3 (blob->length,
face->table.GSUB->table.get_length (),
face->table.GDEF->table.get_length ())
{
/* https://github.com/harfbuzz/harfbuzz/issues/4108
sha1sum:a71ca6813b7e56a772cffff7c24a5166b087197c AALMAGHRIBI.ttf */
case HB_CODEPOINT_ENCODE3 (19892, 2794, 340):
return true;
}
return false;
}
bool
AAT::mort::is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const
{
#ifdef HB_NO_AAT_LAYOUT_BLOCKLIST
return false;
#endif
return false;
}
void
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
hb_aat_map_t *map)
@ -288,14 +254,11 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
const hb_feature_t *features,
unsigned num_features)
{
hb_aat_map_builder_t builder (font->face, plan->props);
for (unsigned i = 0; i < num_features; i++)
builder.add_feature (features[i]);
hb_aat_map_t map;
if (num_features)
{
hb_aat_map_builder_t builder (font->face, plan->props);
for (unsigned i = 0; i < num_features; i++)
builder.add_feature (features[i]);
builder.compile (map);
}
builder.compile (map);
{
auto &accel = *font->face->table.morx;
@ -304,10 +267,7 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table morx")) return;
c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
morx.apply (&c, num_features ? map : plan->aat_map, accel);
accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
c.buffer_glyph_set = nullptr;
morx.apply (&c, map, accel);
(void) buffer->message (font, "end table morx");
return;
}
@ -320,24 +280,34 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table mort")) return;
mort.apply (&c, num_features ? map : plan->aat_map, accel);
mort.apply (&c, map, accel);
(void) buffer->message (font, "end table mort");
return;
}
}
}
void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int i = 0; i < count; i++)
if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
}
static bool
is_deleted_glyph (const hb_glyph_info_t *info)
{
return _hb_glyph_info_is_aat_deleted (info);
return info->codepoint == AAT::DELETED_GLYPH;
}
void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
{
if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_AAT_HAS_DELETED)
buffer->delete_glyphs_inplace (is_deleted_glyph);
buffer->delete_glyphs_inplace (is_deleted_glyph);
}
/**
@ -368,11 +338,8 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
AAT::hb_aat_apply_context_t c (plan, font, buffer, accel.get_blob ());
if (!buffer->message (font, "start table kerx")) return;
c.buffer_glyph_set = accel.scratch.create_buffer_glyph_set ();
c.set_ankr_table (font->face->table.ankr.get ());
accel.apply (&c);
accel.scratch.destroy_buffer_glyph_set (c.buffer_glyph_set);
c.buffer_glyph_set = nullptr;
(void) buffer->message (font, "end table kerx");
}

View file

@ -32,9 +32,6 @@
#include "hb-ot-shape.hh"
#include "hb-aat-ltag-table.hh"
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
struct hb_aat_feature_mapping_t
{
hb_tag_t otFeatureTag;
@ -60,6 +57,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
const hb_feature_t *features,
unsigned num_features);
HB_INTERNAL void
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
HB_INTERNAL void
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);

View file

@ -85,31 +85,25 @@ void
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
{
/* Compute active features per range, and compile each. */
if (!features.length)
{
hb_aat_layout_compile_map (this, &m);
return;
}
/* Sort features by start/end events. */
hb_vector_t<feature_event_t> feature_events;
feature_events.alloc_exact (features.length * 2 + 1);
for (unsigned int i = 0; i < features.length; i++)
{
auto &feature = features.arrayZ[i];
auto &feature = features[i];
if (feature.start == feature.end)
if (features[i].start == features[i].end)
continue;
feature_event_t *event;
event = feature_events.push ();
event->index = feature.start;
event->index = features[i].start;
event->start = true;
event->feature = feature.info;
event = feature_events.push ();
event->index = feature.end;
event->index = features[i].end;
event->start = false;
event->feature = feature.info;
}
@ -145,12 +139,12 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
current_features.qsort ();
unsigned int j = 0;
for (unsigned int i = 1; i < current_features.length; i++)
if (current_features.arrayZ[i].type != current_features.arrayZ[j].type ||
if (current_features[i].type != current_features[j].type ||
/* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
* respectively, so we mask out the low-order bit when checking for "duplicates"
* (selectors referring to the same feature setting) here. */
(!current_features.arrayZ[i].is_exclusive && ((current_features.arrayZ[i].setting & ~1) != (current_features.arrayZ[j].setting & ~1))))
current_features.arrayZ[++j] = current_features.arrayZ[i];
(!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1))))
current_features[++j] = current_features[i];
current_features.shrink (j + 1);
}

View file

@ -286,7 +286,7 @@ HB_FUNCOBJ (hb_bool);
// Compression function for Merkle-Damgard construction.
// This function is generated using the framework provided.
#define fasthash_mix(h) ( \
#define mix(h) ( \
(void) ((h) ^= (h) >> 23), \
(void) ((h) *= 0x2127599bf4325c37ULL), \
(h) ^= (h) >> 47)
@ -310,7 +310,7 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
#pragma GCC diagnostic ignored "-Wcast-align"
v = * (const uint64_t *) (pos++);
#pragma GCC diagnostic pop
h ^= fasthash_mix(v);
h ^= mix(v);
h *= m;
}
}
@ -320,7 +320,7 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
while (pos != end)
{
v = pos++->v;
h ^= fasthash_mix(v);
h ^= mix(v);
h *= m;
}
}
@ -336,11 +336,11 @@ static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH;
case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH;
case 1: v ^= (uint64_t)pos2[0];
h ^= fasthash_mix(v);
h ^= mix(v);
h *= m;
}
return fasthash_mix(h);
return mix(h);
}
static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed)

View file

@ -251,8 +251,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
if (end < start + 2)
return;
unsigned stop = start + (end - start) / 2;
for (unsigned lhs = start, rhs = end - 1; lhs < stop; lhs++, rhs--)
for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--)
hb_swap (arrayZ[rhs], arrayZ[lhs]);
}

View file

@ -80,14 +80,15 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
#include <atomic>
#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<typename std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
@ -148,55 +149,69 @@ static inline void _hb_compiler_memory_r_barrier () {}
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
#endif
#ifndef hb_atomic_int_impl_set
template <typename T>
inline void hb_atomic_int_impl_set (T *AI, T v) { _hb_memory_w_barrier (); *AI = v; }
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; }
#endif
#ifndef hb_atomic_int_impl_get
template <typename T>
inline T hb_atomic_int_impl_get (const T *AI) { T v = *AI; _hb_memory_r_barrier (); return v; }
inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; }
#endif
#ifndef hb_atomic_ptr_impl_get
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
#endif
template <typename T>
struct hb_atomic_t
struct hb_atomic_short_t
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T v) : v (v) {}
hb_atomic_short_t () = default;
constexpr hb_atomic_short_t (short v) : v (v) {}
hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
operator T () const { return get_relaxed (); }
hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
operator short () const { return get_relaxed (); }
void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
T get_acquire () const { return hb_atomic_int_impl_get (&v); }
T inc () { return hb_atomic_int_impl_add (&v, 1); }
T dec () { return hb_atomic_int_impl_add (&v, -1); }
void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
short get_acquire () const { return hb_atomic_int_impl_get (&v); }
short inc () { return hb_atomic_int_impl_add (&v, 1); }
short dec () { return hb_atomic_int_impl_add (&v, -1); }
int operator ++ (int) { return inc (); }
int operator -- (int) { return dec (); }
long operator |= (long v_) { set_relaxed (get_relaxed () | v_); return *this; }
T v = 0;
short v = 0;
};
template <typename T>
struct hb_atomic_t<T*>
struct hb_atomic_int_t
{
hb_atomic_t () = default;
constexpr hb_atomic_t (T* v) : v (v) {}
hb_atomic_t (const hb_atomic_t &other) = delete;
hb_atomic_int_t () = default;
constexpr hb_atomic_int_t (int v) : v (v) {}
hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
operator int () const { return get_relaxed (); }
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
int get_acquire () const { return hb_atomic_int_impl_get (&v); }
int inc () { return hb_atomic_int_impl_add (&v, 1); }
int dec () { return hb_atomic_int_impl_add (&v, -1); }
int v = 0;
};
template <typename P>
struct hb_atomic_ptr_t
{
typedef hb_remove_pointer<P> T;
hb_atomic_ptr_t () = default;
constexpr hb_atomic_ptr_t (T* v) : v (v) {}
hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
bool cmpexch (const T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
operator bool () const { return get_acquire () != nullptr; }
T * operator -> () const { return get_acquire (); }
template <typename C> operator C * () const { return get_acquire (); }

View file

@ -78,28 +78,6 @@ struct hb_vector_size_t
hb_vector_size_t operator ~ () const
{ return process (hb_bitwise_neg); }
operator bool () const
{
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
if (v[i])
return true;
return false;
}
operator unsigned int () const
{
unsigned int r = 0;
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
r += hb_popcount (v[i]);
return r;
}
bool operator == (const hb_vector_size_t &o) const
{
for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
if (v[i] != o.v[i])
return false;
return true;
}
hb_array_t<const elt_t> iter () const
{ return hb_array (v); }
@ -111,8 +89,6 @@ struct hb_vector_size_t
struct hb_bit_page_t
{
hb_bit_page_t () { init0 (); }
void init0 () { v.init0 (); population = 0; }
void init1 () { v.init1 (); population = PAGE_BITS; }
@ -125,9 +101,10 @@ struct hb_bit_page_t
bool is_empty () const
{
if (has_population ()) return !population;
bool empty = !v;
if (empty) population = 0;
return empty;
return
+ hb_iter (v)
| hb_none
;
}
uint32_t hash () const
{
@ -138,10 +115,6 @@ struct hb_bit_page_t
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); }
void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
bool may_have (hb_codepoint_t g) const { return get (g); }
bool operator [] (hb_codepoint_t g) const { return get (g); }
bool operator () (hb_codepoint_t g) const { return get (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
@ -247,17 +220,13 @@ struct hb_bit_page_t
}
bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
bool is_equal (const hb_bit_page_t &other) const { return v == other.v; }
bool intersects (const hb_bit_page_t &other) const
bool is_equal (const hb_bit_page_t &other) const
{
for (unsigned i = 0; i < len (); i++)
if (v[i] & other.v[i])
return true;
return false;
if (v[i] != other.v[i])
return false;
return true;
}
bool may_intersect (const hb_bit_page_t &other) const
{ return intersects (other); }
bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); }
bool is_subset (const hb_bit_page_t &larger_page) const
{
@ -272,10 +241,14 @@ struct hb_bit_page_t
}
bool has_population () const { return population != UINT_MAX; }
unsigned get_population () const
unsigned int get_population () const
{
if (has_population ()) return population;
return population = v;
population =
+ hb_iter (v)
| hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
;
return population;
}
bool next (hb_codepoint_t *codepoint) const

View file

@ -126,7 +126,6 @@ struct hb_bit_set_invertible_t
{ unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
bool may_have (hb_codepoint_t g) const { return get (g); }
/* Has interface. */
bool operator [] (hb_codepoint_t k) const { return get (k); }
@ -140,9 +139,6 @@ struct hb_bit_set_invertible_t
hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool may_intersect (const hb_bit_set_invertible_t &other) const
{ return inverted || other.inverted || s.intersects (other.s); }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;

View file

@ -77,7 +77,7 @@ struct hb_bit_set_t
bool successful = true; /* Allocations successful */
mutable unsigned int population = 0;
mutable hb_atomic_t<unsigned> last_page_lookup = 0;
mutable hb_atomic_int_t last_page_lookup = 0;
hb_sorted_vector_t<page_map_t> page_map;
hb_vector_t<page_t> pages;
@ -88,11 +88,10 @@ struct hb_bit_set_t
{
if (unlikely (!successful)) return false;
if (pages.length < count && (unsigned) pages.allocated < count && count <= 2)
if (pages.length == 0 && count == 1)
exact_size = true; // Most sets are small and local
if (unlikely (!pages.resize (count, clear, exact_size) ||
!page_map.resize (count, clear)))
if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size)))
{
pages.resize (page_map.length, clear, exact_size);
successful = false;
@ -298,9 +297,9 @@ struct hb_bit_set_t
unsigned int write_index = 0;
for (unsigned int i = 0; i < page_map.length; i++)
{
int m = (int) page_map.arrayZ[i].major;
int m = (int) page_map[i].major;
if (m < ds || de < m)
page_map.arrayZ[write_index++] = page_map.arrayZ[i];
page_map[write_index++] = page_map[i];
}
compact (compact_workspace, write_index);
resize (write_index);
@ -346,7 +345,6 @@ struct hb_bit_set_t
return false;
return page->get (g);
}
bool may_have (hb_codepoint_t g) const { return get (g); }
/* Has interface. */
bool operator [] (hb_codepoint_t k) const { return get (k); }
@ -360,31 +358,6 @@ struct hb_bit_set_t
hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (const hb_bit_set_t &other) const
{
unsigned int na = pages.length;
unsigned int nb = other.pages.length;
unsigned int a = 0, b = 0;
for (; a < na && b < nb; )
{
if (page_map.arrayZ[a].major == other.page_map.arrayZ[b].major)
{
if (page_at (a).intersects (other.page_at (b)))
return true;
a++;
b++;
}
else if (page_map.arrayZ[a].major < other.page_map.arrayZ[b].major)
a++;
else
b++;
}
return false;
}
bool may_intersect (const hb_bit_set_t &other) const
{ return intersects (other); }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;
@ -416,7 +389,7 @@ struct hb_bit_set_t
{
if (page_at (a).is_empty ()) { a++; continue; }
if (other.page_at (b).is_empty ()) { b++; continue; }
if (page_map.arrayZ[a].major != other.page_map.arrayZ[b].major ||
if (page_map[a].major != other.page_map[b].major ||
!page_at (a).is_equal (other.page_at (b)))
return false;
a++;
@ -439,8 +412,8 @@ struct hb_bit_set_t
uint32_t spi = 0;
for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
{
uint32_t spm = page_map.arrayZ[spi].major;
uint32_t lpm = larger_set.page_map.arrayZ[lpi].major;
uint32_t spm = page_map[spi].major;
uint32_t lpm = larger_set.page_map[lpi].major;
auto sp = page_at (spi);
if (spm < lpm && !sp.is_empty ())
@ -530,7 +503,7 @@ struct hb_bit_set_t
for (; a < na && b < nb; )
{
if (page_map.arrayZ[a].major == other.page_map.arrayZ[b].major)
if (page_map[a].major == other.page_map[b].major)
{
if (!passthru_left)
{
@ -539,7 +512,7 @@ struct hb_bit_set_t
// passthru_left is set since no left side pages will be removed
// in that case.
if (write_index < a)
page_map.arrayZ[write_index] = page_map.arrayZ[a];
page_map[write_index] = page_map[a];
write_index++;
}
@ -547,7 +520,7 @@ struct hb_bit_set_t
a++;
b++;
}
else if (page_map.arrayZ[a].major < other.page_map.arrayZ[b].major)
else if (page_map[a].major < other.page_map[b].major)
{
if (passthru_left)
count++;
@ -792,8 +765,8 @@ struct hb_bit_set_t
unsigned int initial_size = size;
for (unsigned int i = start_page; i < page_map.length && size; i++)
{
uint32_t base = major_start (page_map.arrayZ[i].major);
unsigned int n = pages[page_map.arrayZ[i].index].write (base, start_page_value, out, size);
uint32_t base = major_start (page_map[i].major);
unsigned int n = pages[page_map[i].index].write (base, start_page_value, out, size);
out += n;
size -= n;
start_page_value = 0;
@ -841,8 +814,8 @@ struct hb_bit_set_t
hb_codepoint_t next_value = codepoint + 1;
for (unsigned int i=start_page; i<page_map.length && size; i++)
{
uint32_t base = major_start (page_map.arrayZ[i].major);
unsigned int n = pages[page_map.arrayZ[i].index].write_inverted (base, start_page_value, out, size, &next_value);
uint32_t base = major_start (page_map[i].major);
unsigned int n = pages[page_map[i].index].write_inverted (base, start_page_value, out, size, &next_value);
out += n;
size -= n;
start_page_value = 0;
@ -873,8 +846,8 @@ struct hb_bit_set_t
unsigned count = pages.length;
for (unsigned i = 0; i < count; i++)
{
const auto& map = page_map.arrayZ[i];
const auto& page = pages.arrayZ[map.index];
const auto& map = page_map[i];
const auto& page = pages[map.index];
if (!page.is_empty ())
return map.major * page_t::PAGE_BITS + page.get_min ();
@ -886,8 +859,8 @@ struct hb_bit_set_t
unsigned count = pages.length;
for (signed i = count - 1; i >= 0; i--)
{
const auto& map = page_map.arrayZ[(unsigned) i];
const auto& page = pages.arrayZ[map.index];
const auto& map = page_map[(unsigned) i];
const auto& page = pages[map.index];
if (!page.is_empty ())
return map.major * page_t::PAGE_BITS + page.get_max ();
@ -988,7 +961,7 @@ struct hb_bit_set_t
return nullptr;
last_page_lookup = i;
return &pages.arrayZ[page_map.arrayZ[i].index];
return &pages.arrayZ[page_map[i].index];
}
page_t &page_at (unsigned int i)
{

View file

@ -1,195 +0,0 @@
/*
* 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.
*
* Author(s): Behdad Esfahbod
*/
#ifndef HB_BIT_VECTOR_HH
#define HB_BIT_VECTOR_HH
#include "hb.hh"
#include "hb-atomic.hh"
struct hb_min_max_t
{
void add (hb_codepoint_t v) { min_v = hb_min (min_v, v); max_v = hb_max (max_v, v); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
min_v = hb_min (min_v, a);
max_v = hb_max (max_v, b);
}
template <typename set_t>
void union_ (const set_t &set)
{
hb_codepoint_t set_min = set.get_min ();
if (unlikely (set_min == HB_CODEPOINT_INVALID))
return;
hb_codepoint_t set_max = set.get_max ();
min_v = hb_min (min_v, set_min);
max_v = hb_max (max_v, set_max);
}
hb_codepoint_t get_min () const { return min_v; }
hb_codepoint_t get_max () const { return max_v; }
private:
hb_codepoint_t min_v = HB_CODEPOINT_INVALID;
hb_codepoint_t max_v = 0;
};
template <bool atomic = false>
struct hb_bit_vector_t
{
using int_t = uint64_t;
using elt_t = typename std::conditional<atomic, hb_atomic_t<int_t>, int_t>::type;
hb_bit_vector_t () = delete;
hb_bit_vector_t (const hb_bit_vector_t &other) = delete;
hb_bit_vector_t &operator= (const hb_bit_vector_t &other) = delete;
// Move
hb_bit_vector_t (hb_bit_vector_t &&other)
: min_v (other.min_v), max_v (other.max_v), count (other.count), elts (other.elts)
{
other.min_v = other.max_v = other.count = 0;
other.elts = nullptr;
}
hb_bit_vector_t &operator= (hb_bit_vector_t &&other)
{
hb_swap (min_v, other.min_v);
hb_swap (max_v, other.max_v);
hb_swap (count, other.count);
hb_swap (elts, other.elts);
return *this;
}
hb_bit_vector_t (unsigned min_v, unsigned max_v)
: min_v (min_v), max_v (max_v)
{
if (unlikely (min_v >= max_v))
{
min_v = max_v = count = 0;
return;
}
unsigned num = (max_v - min_v + sizeof (int_t) * 8) / (sizeof (int_t) * 8);
elts = (elt_t *) hb_calloc (num, sizeof (int_t));
if (unlikely (!elts))
{
min_v = max_v = count = 0;
return;
}
count = max_v - min_v + 1;
}
~hb_bit_vector_t ()
{
hb_free (elts);
}
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
bool has (hb_codepoint_t g) const { return get (g); }
bool may_have (hb_codepoint_t g) const { return get (g); }
bool operator [] (hb_codepoint_t g) const { return get (g); }
bool operator () (hb_codepoint_t g) const { return get (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (unlikely (!count || a > b || a < min_v || b > max_v))
return;
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
*la |= (mask (b) << 1) - mask(a);
else
{
*la |= ~(mask (a) - 1llu);
la++;
hb_memset (la, 0xff, (char *) lb - (char *) la);
*lb |= ((mask (b) << 1) - 1llu);
}
}
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (unlikely (!count || a > b || a < min_v || b > max_v))
return;
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
*la &= ~((mask (b) << 1llu) - mask(a));
else
{
*la &= mask (a) - 1;
la++;
hb_memset (la, 0, (char *) lb - (char *) la);
*lb &= ~((mask (b) << 1) - 1llu);
}
}
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
{ if (v) add_range (a, b); else del_range (a, b); }
template <typename set_t>
void union_ (const set_t &set)
{
for (hb_codepoint_t g : set)
add (g);
}
static const unsigned int ELT_BITS = sizeof (elt_t) * 8;
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
static constexpr elt_t zero = 0;
elt_t &elt (hb_codepoint_t g)
{
g -= min_v;
if (unlikely (g >= count))
return Crap(elt_t);
return elts[g / ELT_BITS];
}
const elt_t& elt (hb_codepoint_t g) const
{
g -= min_v;
if (unlikely (g >= count))
return Null(elt_t);
return elts[g / ELT_BITS];
}
static constexpr int_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
hb_codepoint_t min_v = 0, max_v = 0, count = 0;
elt_t *elts = nullptr;
};
#endif /* HB_BIT_VECTOR_HH */

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